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 IDWriteTextFormat1 IDWriteTextFormat1_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_IDWriteTextFormat1(IDWriteTextFormat1
*iface
)
331 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextFormat1_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
->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_IDWriteTextFormat1
) ||
2818 IsEqualIID(riid
, &IID_IDWriteTextFormat
))
2819 *obj
= &This
->IDWriteTextFormat1_iface
;
2822 IDWriteTextLayout3_AddRef(iface
);
2826 WARN("%s not implemented.\n", debugstr_guid(riid
));
2828 return E_NOINTERFACE
;
2831 static ULONG WINAPI
dwritetextlayout_AddRef(IDWriteTextLayout3
*iface
)
2833 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2834 ULONG ref
= InterlockedIncrement(&This
->ref
);
2835 TRACE("(%p)->(%d)\n", This
, ref
);
2839 static ULONG WINAPI
dwritetextlayout_Release(IDWriteTextLayout3
*iface
)
2841 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2842 ULONG ref
= InterlockedDecrement(&This
->ref
);
2844 TRACE("(%p)->(%d)\n", This
, ref
);
2847 IDWriteFactory5_Release(This
->factory
);
2848 free_layout_ranges_list(This
);
2849 free_layout_eruns(This
);
2850 free_layout_runs(This
);
2851 release_format_data(&This
->format
);
2852 heap_free(This
->nominal_breakpoints
);
2853 heap_free(This
->actual_breakpoints
);
2854 heap_free(This
->clustermetrics
);
2855 heap_free(This
->clusters
);
2856 heap_free(This
->linemetrics
);
2857 heap_free(This
->lines
);
2858 heap_free(This
->str
);
2865 static HRESULT WINAPI
dwritetextlayout_SetTextAlignment(IDWriteTextLayout3
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
2867 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2868 return IDWriteTextFormat1_SetTextAlignment(&This
->IDWriteTextFormat1_iface
, alignment
);
2871 static HRESULT WINAPI
dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout3
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
2873 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2874 return IDWriteTextFormat1_SetParagraphAlignment(&This
->IDWriteTextFormat1_iface
, alignment
);
2877 static HRESULT WINAPI
dwritetextlayout_SetWordWrapping(IDWriteTextLayout3
*iface
, DWRITE_WORD_WRAPPING wrapping
)
2879 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2880 return IDWriteTextFormat1_SetWordWrapping(&This
->IDWriteTextFormat1_iface
, wrapping
);
2883 static HRESULT WINAPI
dwritetextlayout_SetReadingDirection(IDWriteTextLayout3
*iface
, DWRITE_READING_DIRECTION direction
)
2885 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2886 return IDWriteTextFormat1_SetReadingDirection(&This
->IDWriteTextFormat1_iface
, direction
);
2889 static HRESULT WINAPI
dwritetextlayout_SetFlowDirection(IDWriteTextLayout3
*iface
, DWRITE_FLOW_DIRECTION direction
)
2891 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2892 TRACE("(%p)->(%d)\n", This
, direction
);
2893 return IDWriteTextFormat1_SetFlowDirection(&This
->IDWriteTextFormat1_iface
, direction
);
2896 static HRESULT WINAPI
dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout3
*iface
, FLOAT tabstop
)
2898 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2899 TRACE("(%p)->(%.2f)\n", This
, tabstop
);
2900 return IDWriteTextFormat1_SetIncrementalTabStop(&This
->IDWriteTextFormat1_iface
, tabstop
);
2903 static HRESULT WINAPI
dwritetextlayout_SetTrimming(IDWriteTextLayout3
*iface
, DWRITE_TRIMMING
const *trimming
,
2904 IDWriteInlineObject
*trimming_sign
)
2906 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2907 TRACE("(%p)->(%p %p)\n", This
, trimming
, trimming_sign
);
2908 return IDWriteTextFormat1_SetTrimming(&This
->IDWriteTextFormat1_iface
, trimming
, trimming_sign
);
2911 static HRESULT WINAPI
dwritetextlayout_SetLineSpacing(IDWriteTextLayout3
*iface
, DWRITE_LINE_SPACING_METHOD spacing
,
2912 FLOAT line_spacing
, FLOAT baseline
)
2914 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2915 TRACE("(%p)->(%d %.2f %.2f)\n", This
, spacing
, line_spacing
, baseline
);
2916 return IDWriteTextFormat1_SetLineSpacing(&This
->IDWriteTextFormat1_iface
, spacing
, line_spacing
, baseline
);
2919 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextlayout_GetTextAlignment(IDWriteTextLayout3
*iface
)
2921 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2922 return IDWriteTextFormat1_GetTextAlignment(&This
->IDWriteTextFormat1_iface
);
2925 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout3
*iface
)
2927 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2928 return IDWriteTextFormat1_GetParagraphAlignment(&This
->IDWriteTextFormat1_iface
);
2931 static DWRITE_WORD_WRAPPING WINAPI
dwritetextlayout_GetWordWrapping(IDWriteTextLayout3
*iface
)
2933 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2934 return IDWriteTextFormat1_GetWordWrapping(&This
->IDWriteTextFormat1_iface
);
2937 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_GetReadingDirection(IDWriteTextLayout3
*iface
)
2939 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2940 return IDWriteTextFormat1_GetReadingDirection(&This
->IDWriteTextFormat1_iface
);
2943 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextlayout_GetFlowDirection(IDWriteTextLayout3
*iface
)
2945 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2946 return IDWriteTextFormat1_GetFlowDirection(&This
->IDWriteTextFormat1_iface
);
2949 static FLOAT WINAPI
dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout3
*iface
)
2951 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2952 return IDWriteTextFormat1_GetIncrementalTabStop(&This
->IDWriteTextFormat1_iface
);
2955 static HRESULT WINAPI
dwritetextlayout_GetTrimming(IDWriteTextLayout3
*iface
, DWRITE_TRIMMING
*options
,
2956 IDWriteInlineObject
**trimming_sign
)
2958 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2959 return IDWriteTextFormat1_GetTrimming(&This
->IDWriteTextFormat1_iface
, options
, trimming_sign
);
2962 static HRESULT WINAPI
dwritetextlayout_GetLineSpacing(IDWriteTextLayout3
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
2963 FLOAT
*spacing
, FLOAT
*baseline
)
2965 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2966 return IDWriteTextFormat_GetLineSpacing((IDWriteTextFormat
*)&This
->IDWriteTextFormat1_iface
, method
, spacing
, baseline
);
2969 static HRESULT WINAPI
dwritetextlayout_GetFontCollection(IDWriteTextLayout3
*iface
, IDWriteFontCollection
**collection
)
2971 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2972 return IDWriteTextFormat1_GetFontCollection(&This
->IDWriteTextFormat1_iface
, collection
);
2975 static UINT32 WINAPI
dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout3
*iface
)
2977 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2978 return IDWriteTextFormat1_GetFontFamilyNameLength(&This
->IDWriteTextFormat1_iface
);
2981 static HRESULT WINAPI
dwritetextlayout_GetFontFamilyName(IDWriteTextLayout3
*iface
, WCHAR
*name
, UINT32 size
)
2983 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2984 return IDWriteTextFormat1_GetFontFamilyName(&This
->IDWriteTextFormat1_iface
, name
, size
);
2987 static DWRITE_FONT_WEIGHT WINAPI
dwritetextlayout_GetFontWeight(IDWriteTextLayout3
*iface
)
2989 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2990 return IDWriteTextFormat1_GetFontWeight(&This
->IDWriteTextFormat1_iface
);
2993 static DWRITE_FONT_STYLE WINAPI
dwritetextlayout_GetFontStyle(IDWriteTextLayout3
*iface
)
2995 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2996 return IDWriteTextFormat1_GetFontStyle(&This
->IDWriteTextFormat1_iface
);
2999 static DWRITE_FONT_STRETCH WINAPI
dwritetextlayout_GetFontStretch(IDWriteTextLayout3
*iface
)
3001 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3002 return IDWriteTextFormat1_GetFontStretch(&This
->IDWriteTextFormat1_iface
);
3005 static FLOAT WINAPI
dwritetextlayout_GetFontSize(IDWriteTextLayout3
*iface
)
3007 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3008 return IDWriteTextFormat1_GetFontSize(&This
->IDWriteTextFormat1_iface
);
3011 static UINT32 WINAPI
dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout3
*iface
)
3013 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3014 return IDWriteTextFormat1_GetLocaleNameLength(&This
->IDWriteTextFormat1_iface
);
3017 static HRESULT WINAPI
dwritetextlayout_GetLocaleName(IDWriteTextLayout3
*iface
, WCHAR
*name
, UINT32 size
)
3019 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3020 return IDWriteTextFormat1_GetLocaleName(&This
->IDWriteTextFormat1_iface
, name
, size
);
3023 static HRESULT WINAPI
dwritetextlayout_SetMaxWidth(IDWriteTextLayout3
*iface
, FLOAT maxWidth
)
3025 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3028 TRACE("(%p)->(%.2f)\n", This
, maxWidth
);
3030 if (maxWidth
< 0.0f
)
3031 return E_INVALIDARG
;
3033 changed
= This
->metrics
.layoutWidth
!= maxWidth
;
3034 This
->metrics
.layoutWidth
= maxWidth
;
3037 This
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
3041 static HRESULT WINAPI
dwritetextlayout_SetMaxHeight(IDWriteTextLayout3
*iface
, FLOAT maxHeight
)
3043 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3046 TRACE("(%p)->(%.2f)\n", This
, maxHeight
);
3048 if (maxHeight
< 0.0f
)
3049 return E_INVALIDARG
;
3051 changed
= This
->metrics
.layoutHeight
!= maxHeight
;
3052 This
->metrics
.layoutHeight
= maxHeight
;
3055 This
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
3059 static HRESULT WINAPI
dwritetextlayout_SetFontCollection(IDWriteTextLayout3
*iface
, IDWriteFontCollection
* collection
, DWRITE_TEXT_RANGE range
)
3061 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3062 struct layout_range_attr_value value
;
3064 TRACE("(%p)->(%p %s)\n", This
, collection
, debugstr_range(&range
));
3066 value
.range
= range
;
3067 value
.u
.collection
= collection
;
3068 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTCOLL
, &value
);
3071 static HRESULT WINAPI
dwritetextlayout_SetFontFamilyName(IDWriteTextLayout3
*iface
, WCHAR
const *name
, DWRITE_TEXT_RANGE range
)
3073 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3074 struct layout_range_attr_value value
;
3076 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(name
), debugstr_range(&range
));
3079 return E_INVALIDARG
;
3081 value
.range
= range
;
3082 value
.u
.fontfamily
= name
;
3083 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, &value
);
3086 static HRESULT WINAPI
dwritetextlayout_SetFontWeight(IDWriteTextLayout3
*iface
, DWRITE_FONT_WEIGHT weight
, DWRITE_TEXT_RANGE range
)
3088 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3089 struct layout_range_attr_value value
;
3091 TRACE("(%p)->(%d %s)\n", This
, weight
, debugstr_range(&range
));
3093 if ((UINT32
)weight
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
)
3094 return E_INVALIDARG
;
3096 value
.range
= range
;
3097 value
.u
.weight
= weight
;
3098 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_WEIGHT
, &value
);
3101 static HRESULT WINAPI
dwritetextlayout_SetFontStyle(IDWriteTextLayout3
*iface
, DWRITE_FONT_STYLE style
, DWRITE_TEXT_RANGE range
)
3103 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3104 struct layout_range_attr_value value
;
3106 TRACE("(%p)->(%d %s)\n", This
, style
, debugstr_range(&range
));
3108 if ((UINT32
)style
> DWRITE_FONT_STYLE_ITALIC
)
3109 return E_INVALIDARG
;
3111 value
.range
= range
;
3112 value
.u
.style
= style
;
3113 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STYLE
, &value
);
3116 static HRESULT WINAPI
dwritetextlayout_SetFontStretch(IDWriteTextLayout3
*iface
, DWRITE_FONT_STRETCH stretch
, DWRITE_TEXT_RANGE range
)
3118 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3119 struct layout_range_attr_value value
;
3121 TRACE("(%p)->(%d %s)\n", This
, stretch
, debugstr_range(&range
));
3123 if (stretch
== DWRITE_FONT_STRETCH_UNDEFINED
|| (UINT32
)stretch
> DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
3124 return E_INVALIDARG
;
3126 value
.range
= range
;
3127 value
.u
.stretch
= stretch
;
3128 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STRETCH
, &value
);
3131 static HRESULT WINAPI
dwritetextlayout_SetFontSize(IDWriteTextLayout3
*iface
, FLOAT size
, DWRITE_TEXT_RANGE range
)
3133 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3134 struct layout_range_attr_value value
;
3136 TRACE("(%p)->(%.2f %s)\n", This
, size
, debugstr_range(&range
));
3139 return E_INVALIDARG
;
3141 value
.range
= range
;
3142 value
.u
.fontsize
= size
;
3143 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTSIZE
, &value
);
3146 static HRESULT WINAPI
dwritetextlayout_SetUnderline(IDWriteTextLayout3
*iface
, BOOL underline
, DWRITE_TEXT_RANGE range
)
3148 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3149 struct layout_range_attr_value value
;
3151 TRACE("(%p)->(%d %s)\n", This
, underline
, debugstr_range(&range
));
3153 value
.range
= range
;
3154 value
.u
.underline
= underline
;
3155 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_UNDERLINE
, &value
);
3158 static HRESULT WINAPI
dwritetextlayout_SetStrikethrough(IDWriteTextLayout3
*iface
, BOOL strikethrough
, DWRITE_TEXT_RANGE range
)
3160 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3161 struct layout_range_attr_value value
;
3163 TRACE("(%p)->(%d %s)\n", This
, strikethrough
, debugstr_range(&range
));
3165 value
.range
= range
;
3166 value
.u
.strikethrough
= strikethrough
;
3167 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STRIKETHROUGH
, &value
);
3170 static HRESULT WINAPI
dwritetextlayout_SetDrawingEffect(IDWriteTextLayout3
*iface
, IUnknown
* effect
, DWRITE_TEXT_RANGE range
)
3172 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3173 struct layout_range_attr_value value
;
3175 TRACE("(%p)->(%p %s)\n", This
, effect
, debugstr_range(&range
));
3177 value
.range
= range
;
3178 value
.u
.effect
= effect
;
3179 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_EFFECT
, &value
);
3182 static HRESULT WINAPI
dwritetextlayout_SetInlineObject(IDWriteTextLayout3
*iface
, IDWriteInlineObject
*object
, DWRITE_TEXT_RANGE range
)
3184 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3185 struct layout_range_attr_value value
;
3187 TRACE("(%p)->(%p %s)\n", This
, object
, debugstr_range(&range
));
3189 value
.range
= range
;
3190 value
.u
.object
= object
;
3191 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_INLINE
, &value
);
3194 static HRESULT WINAPI
dwritetextlayout_SetTypography(IDWriteTextLayout3
*iface
, IDWriteTypography
* typography
, DWRITE_TEXT_RANGE range
)
3196 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3197 struct layout_range_attr_value value
;
3199 TRACE("(%p)->(%p %s)\n", This
, typography
, debugstr_range(&range
));
3201 value
.range
= range
;
3202 value
.u
.typography
= typography
;
3203 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_TYPOGRAPHY
, &value
);
3206 static HRESULT WINAPI
dwritetextlayout_SetLocaleName(IDWriteTextLayout3
*iface
, WCHAR
const* locale
, DWRITE_TEXT_RANGE range
)
3208 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3209 struct layout_range_attr_value value
;
3211 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(locale
), debugstr_range(&range
));
3213 if (!locale
|| strlenW(locale
) > LOCALE_NAME_MAX_LENGTH
-1)
3214 return E_INVALIDARG
;
3216 value
.range
= range
;
3217 value
.u
.locale
= locale
;
3218 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_LOCALE
, &value
);
3221 static FLOAT WINAPI
dwritetextlayout_GetMaxWidth(IDWriteTextLayout3
*iface
)
3223 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3224 TRACE("(%p)\n", This
);
3225 return This
->metrics
.layoutWidth
;
3228 static FLOAT WINAPI
dwritetextlayout_GetMaxHeight(IDWriteTextLayout3
*iface
)
3230 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3231 TRACE("(%p)\n", This
);
3232 return This
->metrics
.layoutHeight
;
3235 static HRESULT WINAPI
dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout3
*iface
, UINT32 position
,
3236 IDWriteFontCollection
** collection
, DWRITE_TEXT_RANGE
*r
)
3238 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3239 struct layout_range
*range
;
3241 TRACE("(%p)->(%u %p %p)\n", This
, position
, collection
, r
);
3243 if (position
>= This
->len
)
3246 range
= get_layout_range_by_pos(This
, position
);
3247 *collection
= range
->collection
;
3249 IDWriteFontCollection_AddRef(*collection
);
3251 return return_range(&range
->h
, r
);
3254 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout3
*iface
,
3255 UINT32 position
, UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
3257 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3258 TRACE("(%p)->(%d %p %p)\n", This
, position
, length
, r
);
3259 return get_string_attribute_length(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, length
, r
);
3262 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout3
*iface
,
3263 UINT32 position
, WCHAR
*name
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
3265 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3266 TRACE("(%p)->(%u %p %u %p)\n", This
, position
, name
, length
, r
);
3267 return get_string_attribute_value(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, name
, length
, r
);
3270 static HRESULT WINAPI
dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout3
*iface
,
3271 UINT32 position
, DWRITE_FONT_WEIGHT
*weight
, DWRITE_TEXT_RANGE
*r
)
3273 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3274 struct layout_range
*range
;
3276 TRACE("(%p)->(%u %p %p)\n", This
, position
, weight
, r
);
3278 if (position
>= This
->len
)
3281 range
= get_layout_range_by_pos(This
, position
);
3282 *weight
= range
->weight
;
3284 return return_range(&range
->h
, r
);
3287 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout3
*iface
,
3288 UINT32 position
, DWRITE_FONT_STYLE
*style
, DWRITE_TEXT_RANGE
*r
)
3290 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3291 struct layout_range
*range
;
3293 TRACE("(%p)->(%u %p %p)\n", This
, position
, style
, r
);
3295 range
= get_layout_range_by_pos(This
, position
);
3296 *style
= range
->style
;
3297 return return_range(&range
->h
, r
);
3300 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout3
*iface
,
3301 UINT32 position
, DWRITE_FONT_STRETCH
*stretch
, DWRITE_TEXT_RANGE
*r
)
3303 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3304 struct layout_range
*range
;
3306 TRACE("(%p)->(%u %p %p)\n", This
, position
, stretch
, r
);
3308 range
= get_layout_range_by_pos(This
, position
);
3309 *stretch
= range
->stretch
;
3310 return return_range(&range
->h
, r
);
3313 static HRESULT WINAPI
dwritetextlayout_layout_GetFontSize(IDWriteTextLayout3
*iface
,
3314 UINT32 position
, FLOAT
*size
, DWRITE_TEXT_RANGE
*r
)
3316 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3317 struct layout_range
*range
;
3319 TRACE("(%p)->(%u %p %p)\n", This
, position
, size
, r
);
3321 range
= get_layout_range_by_pos(This
, position
);
3322 *size
= range
->fontsize
;
3323 return return_range(&range
->h
, r
);
3326 static HRESULT WINAPI
dwritetextlayout_GetUnderline(IDWriteTextLayout3
*iface
,
3327 UINT32 position
, BOOL
*underline
, DWRITE_TEXT_RANGE
*r
)
3329 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3330 struct layout_range_bool
*range
;
3332 TRACE("(%p)->(%u %p %p)\n", This
, position
, underline
, r
);
3334 range
= (struct layout_range_bool
*)get_layout_range_header_by_pos(&This
->underline_ranges
, position
);
3335 *underline
= range
->value
;
3337 return return_range(&range
->h
, r
);
3340 static HRESULT WINAPI
dwritetextlayout_GetStrikethrough(IDWriteTextLayout3
*iface
,
3341 UINT32 position
, BOOL
*strikethrough
, DWRITE_TEXT_RANGE
*r
)
3343 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3344 struct layout_range_bool
*range
;
3346 TRACE("(%p)->(%u %p %p)\n", This
, position
, strikethrough
, r
);
3348 range
= (struct layout_range_bool
*)get_layout_range_header_by_pos(&This
->strike_ranges
, position
);
3349 *strikethrough
= range
->value
;
3351 return return_range(&range
->h
, r
);
3354 static HRESULT WINAPI
dwritetextlayout_GetDrawingEffect(IDWriteTextLayout3
*iface
,
3355 UINT32 position
, IUnknown
**effect
, DWRITE_TEXT_RANGE
*r
)
3357 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3358 struct layout_range_iface
*range
;
3360 TRACE("(%p)->(%u %p %p)\n", This
, position
, effect
, r
);
3362 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&This
->effects
, position
);
3363 *effect
= range
->iface
;
3365 IUnknown_AddRef(*effect
);
3367 return return_range(&range
->h
, r
);
3370 static HRESULT WINAPI
dwritetextlayout_GetInlineObject(IDWriteTextLayout3
*iface
,
3371 UINT32 position
, IDWriteInlineObject
**object
, DWRITE_TEXT_RANGE
*r
)
3373 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3374 struct layout_range
*range
;
3376 TRACE("(%p)->(%u %p %p)\n", This
, position
, object
, r
);
3378 if (position
>= This
->len
)
3381 range
= get_layout_range_by_pos(This
, position
);
3382 *object
= range
->object
;
3384 IDWriteInlineObject_AddRef(*object
);
3386 return return_range(&range
->h
, r
);
3389 static HRESULT WINAPI
dwritetextlayout_GetTypography(IDWriteTextLayout3
*iface
,
3390 UINT32 position
, IDWriteTypography
** typography
, DWRITE_TEXT_RANGE
*r
)
3392 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3393 struct layout_range_iface
*range
;
3395 TRACE("(%p)->(%u %p %p)\n", This
, position
, typography
, r
);
3397 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&This
->typographies
, position
);
3398 *typography
= (IDWriteTypography
*)range
->iface
;
3400 IDWriteTypography_AddRef(*typography
);
3402 return return_range(&range
->h
, r
);
3405 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout3
*iface
,
3406 UINT32 position
, UINT32
* length
, DWRITE_TEXT_RANGE
*r
)
3408 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3409 TRACE("(%p)->(%u %p %p)\n", This
, position
, length
, r
);
3410 return get_string_attribute_length(This
, LAYOUT_RANGE_ATTR_LOCALE
, position
, length
, r
);
3413 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout3
*iface
,
3414 UINT32 position
, WCHAR
* locale
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
3416 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3417 TRACE("(%p)->(%u %p %u %p)\n", This
, position
, locale
, length
, r
);
3418 return get_string_attribute_value(This
, LAYOUT_RANGE_ATTR_LOCALE
, position
, locale
, length
, r
);
3421 static inline FLOAT
renderer_apply_snapping(FLOAT coord
, BOOL skiptransform
, FLOAT ppdip
, FLOAT det
,
3422 const DWRITE_MATRIX
*m
)
3424 D2D1_POINT_2F vec
, vec2
;
3426 if (!skiptransform
) {
3427 /* apply transform */
3429 vec
.y
= coord
* ppdip
;
3431 vec2
.x
= m
->m11
* vec
.x
+ m
->m21
* vec
.y
+ m
->dx
;
3432 vec2
.y
= m
->m12
* vec
.x
+ m
->m22
* vec
.y
+ m
->dy
;
3435 vec2
.x
= floorf(vec2
.x
+ 0.5f
);
3436 vec2
.y
= floorf(vec2
.y
+ 0.5f
);
3438 /* apply inverted transform, we don't care about X component at this point */
3439 vec
.y
= (-m
->m12
* vec2
.x
+ m
->m11
* vec2
.y
- (m
->m11
* m
->dy
- m
->m12
* m
->dx
)) / det
;
3443 vec
.y
= floorf(coord
* ppdip
+ 0.5f
) / ppdip
;
3448 static HRESULT WINAPI
dwritetextlayout_Draw(IDWriteTextLayout3
*iface
,
3449 void *context
, IDWriteTextRenderer
* renderer
, FLOAT origin_x
, FLOAT origin_y
)
3451 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3452 BOOL disabled
= FALSE
, skiptransform
= FALSE
;
3453 struct layout_effective_inline
*inlineobject
;
3454 struct layout_effective_run
*run
;
3455 struct layout_strikethrough
*s
;
3456 struct layout_underline
*u
;
3457 FLOAT det
= 0.0f
, ppdip
= 0.0f
;
3458 DWRITE_MATRIX m
= { 0 };
3461 TRACE("(%p)->(%p %p %.2f %.2f)\n", This
, context
, renderer
, origin_x
, origin_y
);
3463 hr
= layout_compute_effective_runs(This
);
3467 hr
= IDWriteTextRenderer_IsPixelSnappingDisabled(renderer
, context
, &disabled
);
3472 hr
= IDWriteTextRenderer_GetPixelsPerDip(renderer
, context
, &ppdip
);
3476 hr
= IDWriteTextRenderer_GetCurrentTransform(renderer
, context
, &m
);
3480 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
3481 if (ppdip
<= 0.0f
||
3482 (m
.m11
* m
.m22
!= 0.0f
&& (m
.m12
!= 0.0f
|| m
.m21
!= 0.0f
)) ||
3483 (m
.m12
* m
.m21
!= 0.0f
&& (m
.m11
!= 0.0f
|| m
.m22
!= 0.0f
)))
3486 skiptransform
= should_skip_transform(&m
, &det
);
3489 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
3490 /* 1. Regular runs */
3491 LIST_FOR_EACH_ENTRY(run
, &This
->eruns
, struct layout_effective_run
, entry
) {
3492 const struct regular_layout_run
*regular
= &run
->run
->u
.regular
;
3493 UINT32 start_glyph
= regular
->clustermap
[run
->start
];
3494 DWRITE_GLYPH_RUN_DESCRIPTION descr
;
3495 DWRITE_GLYPH_RUN glyph_run
;
3497 /* Everything but cluster map will be reused from nominal run, as we only need
3498 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
3499 it can't be reused because it has to start with 0 index for each reported run. */
3500 glyph_run
= regular
->run
;
3501 glyph_run
.glyphCount
= run
->glyphcount
;
3503 /* fixup glyph data arrays */
3504 glyph_run
.glyphIndices
+= start_glyph
;
3505 glyph_run
.glyphAdvances
+= start_glyph
;
3506 glyph_run
.glyphOffsets
+= start_glyph
;
3509 descr
= regular
->descr
;
3510 descr
.stringLength
= run
->length
;
3511 descr
.string
+= run
->start
;
3512 descr
.clusterMap
= run
->clustermap
;
3513 descr
.textPosition
+= run
->start
;
3515 /* return value is ignored */
3516 IDWriteTextRenderer_DrawGlyphRun(renderer
,
3518 run
->origin
.x
+ run
->align_dx
+ origin_x
,
3519 SNAP_COORD(run
->origin
.y
+ origin_y
),
3520 This
->measuringmode
,
3526 /* 2. Inline objects */
3527 LIST_FOR_EACH_ENTRY(inlineobject
, &This
->inlineobjects
, struct layout_effective_inline
, entry
) {
3528 IDWriteTextRenderer_DrawInlineObject(renderer
,
3530 inlineobject
->origin
.x
+ inlineobject
->align_dx
+ origin_x
,
3531 SNAP_COORD(inlineobject
->origin
.y
+ origin_y
),
3532 inlineobject
->object
,
3533 inlineobject
->is_sideways
,
3534 inlineobject
->is_rtl
,
3535 inlineobject
->effect
);
3539 LIST_FOR_EACH_ENTRY(u
, &This
->underlines
, struct layout_underline
, entry
) {
3540 IDWriteTextRenderer_DrawUnderline(renderer
,
3542 /* horizontal underline always grows from left to right, width is always added to origin regardless of run direction */
3543 (is_run_rtl(u
->run
) ? u
->run
->origin
.x
- u
->run
->width
: u
->run
->origin
.x
) + u
->run
->align_dx
+ origin_x
,
3544 SNAP_COORD(u
->run
->origin
.y
+ origin_y
),
3549 /* 4. Strikethrough */
3550 LIST_FOR_EACH_ENTRY(s
, &This
->strikethrough
, struct layout_strikethrough
, entry
) {
3551 IDWriteTextRenderer_DrawStrikethrough(renderer
,
3553 s
->run
->origin
.x
+ s
->run
->align_dx
+ origin_x
,
3554 SNAP_COORD(s
->run
->origin
.y
+ origin_y
),
3563 static HRESULT WINAPI
dwritetextlayout_GetLineMetrics(IDWriteTextLayout3
*iface
,
3564 DWRITE_LINE_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
3566 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3569 TRACE("(%p)->(%p %u %p)\n", This
, metrics
, max_count
, count
);
3571 hr
= layout_compute_effective_runs(This
);
3576 UINT32 i
, c
= min(max_count
, This
->metrics
.lineCount
);
3577 for (i
= 0; i
< c
; i
++)
3578 memcpy(metrics
+ i
, This
->linemetrics
+ i
, sizeof(*metrics
));
3581 *count
= This
->metrics
.lineCount
;
3582 return max_count
>= This
->metrics
.lineCount
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
3585 static HRESULT WINAPI
dwritetextlayout_GetMetrics(IDWriteTextLayout3
*iface
, DWRITE_TEXT_METRICS
*metrics
)
3587 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3588 DWRITE_TEXT_METRICS1 metrics1
;
3591 TRACE("(%p)->(%p)\n", This
, metrics
);
3593 hr
= IDWriteTextLayout3_GetMetrics(iface
, &metrics1
);
3595 memcpy(metrics
, &metrics1
, sizeof(*metrics
));
3600 static void scale_glyph_bbox(RECT
*bbox
, FLOAT emSize
, UINT16 units_per_em
, D2D1_RECT_F
*ret
)
3602 #define SCALE(x) ((FLOAT)x * emSize / (FLOAT)units_per_em)
3603 ret
->left
= SCALE(bbox
->left
);
3604 ret
->right
= SCALE(bbox
->right
);
3605 ret
->top
= SCALE(bbox
->top
);
3606 ret
->bottom
= SCALE(bbox
->bottom
);
3610 static void d2d_rect_offset(D2D1_RECT_F
*rect
, FLOAT x
, FLOAT y
)
3618 static BOOL
d2d_rect_is_empty(const D2D1_RECT_F
*rect
)
3620 return ((rect
->left
>= rect
->right
) || (rect
->top
>= rect
->bottom
));
3623 static void d2d_rect_union(D2D1_RECT_F
*dst
, const D2D1_RECT_F
*src
)
3625 if (d2d_rect_is_empty(dst
)) {
3626 if (d2d_rect_is_empty(src
)) {
3627 dst
->left
= dst
->right
= dst
->top
= dst
->bottom
= 0.0f
;
3634 if (!d2d_rect_is_empty(src
)) {
3635 dst
->left
= min(dst
->left
, src
->left
);
3636 dst
->right
= max(dst
->right
, src
->right
);
3637 dst
->top
= min(dst
->top
, src
->top
);
3638 dst
->bottom
= max(dst
->bottom
, src
->bottom
);
3643 static void layout_get_erun_bbox(struct dwrite_textlayout
*layout
, struct layout_effective_run
*run
, D2D1_RECT_F
*bbox
)
3645 const struct regular_layout_run
*regular
= &run
->run
->u
.regular
;
3646 UINT32 start_glyph
= regular
->clustermap
[run
->start
];
3647 const DWRITE_GLYPH_RUN
*glyph_run
= ®ular
->run
;
3648 DWRITE_FONT_METRICS font_metrics
;
3649 D2D1_POINT_2F origin
= { 0 };
3652 if (run
->bbox
.top
== run
->bbox
.bottom
) {
3653 IDWriteFontFace_GetMetrics(glyph_run
->fontFace
, &font_metrics
);
3655 for (i
= 0; i
< run
->glyphcount
; i
++) {
3656 D2D1_RECT_F glyph_bbox
;
3659 freetype_get_design_glyph_bbox((IDWriteFontFace4
*)glyph_run
->fontFace
, font_metrics
.designUnitsPerEm
,
3660 glyph_run
->glyphIndices
[i
+ start_glyph
], &design_bbox
);
3662 scale_glyph_bbox(&design_bbox
, glyph_run
->fontEmSize
, font_metrics
.designUnitsPerEm
, &glyph_bbox
);
3663 d2d_rect_offset(&glyph_bbox
, origin
.x
+ glyph_run
->glyphOffsets
[i
+ start_glyph
].advanceOffset
,
3664 origin
.y
+ glyph_run
->glyphOffsets
[i
+ start_glyph
].ascenderOffset
);
3665 d2d_rect_union(&run
->bbox
, &glyph_bbox
);
3667 /* FIXME: take care of vertical/rtl */
3668 origin
.x
+= glyph_run
->glyphAdvances
[i
+ start_glyph
];
3673 d2d_rect_offset(bbox
, run
->origin
.x
+ run
->align_dx
, run
->origin
.y
);
3676 static void layout_get_inlineobj_bbox(struct dwrite_textlayout
*layout
, struct layout_effective_inline
*run
,
3679 DWRITE_OVERHANG_METRICS overhang_metrics
= { 0 };
3680 DWRITE_INLINE_OBJECT_METRICS metrics
= { 0 };
3683 if (FAILED(hr
= IDWriteInlineObject_GetMetrics(run
->object
, &metrics
))) {
3684 WARN("Failed to get inline object metrics, hr %#x.\n", hr
);
3685 memset(bbox
, 0, sizeof(*bbox
));
3689 bbox
->left
= run
->origin
.x
+ run
->align_dx
;
3690 bbox
->right
= bbox
->left
+ metrics
.width
;
3691 bbox
->top
= run
->origin
.y
;
3692 bbox
->bottom
= bbox
->top
+ metrics
.height
;
3694 IDWriteInlineObject_GetOverhangMetrics(run
->object
, &overhang_metrics
);
3696 bbox
->left
-= overhang_metrics
.left
;
3697 bbox
->right
+= overhang_metrics
.right
;
3698 bbox
->top
-= overhang_metrics
.top
;
3699 bbox
->bottom
+= overhang_metrics
.bottom
;
3702 static HRESULT WINAPI
dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout3
*iface
,
3703 DWRITE_OVERHANG_METRICS
*overhangs
)
3705 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3706 struct layout_effective_inline
*inline_run
;
3707 struct layout_effective_run
*run
;
3708 D2D1_RECT_F bbox
= { 0 };
3711 TRACE("(%p)->(%p)\n", This
, overhangs
);
3713 memset(overhangs
, 0, sizeof(*overhangs
));
3715 if (!(This
->recompute
& RECOMPUTE_OVERHANGS
)) {
3716 *overhangs
= This
->overhangs
;
3720 hr
= layout_compute_effective_runs(This
);
3724 LIST_FOR_EACH_ENTRY(run
, &This
->eruns
, struct layout_effective_run
, entry
) {
3725 D2D1_RECT_F run_bbox
;
3727 layout_get_erun_bbox(This
, run
, &run_bbox
);
3728 d2d_rect_union(&bbox
, &run_bbox
);
3731 LIST_FOR_EACH_ENTRY(inline_run
, &This
->inlineobjects
, struct layout_effective_inline
, entry
) {
3732 D2D1_RECT_F object_bbox
;
3734 layout_get_inlineobj_bbox(This
, inline_run
, &object_bbox
);
3735 d2d_rect_union(&bbox
, &object_bbox
);
3738 /* Deltas from layout box. */
3739 This
->overhangs
.left
= -bbox
.left
;
3740 This
->overhangs
.top
= -bbox
.top
;
3741 This
->overhangs
.right
= bbox
.right
- This
->metrics
.layoutWidth
;
3742 This
->overhangs
.bottom
= bbox
.bottom
- This
->metrics
.layoutHeight
;
3743 This
->recompute
&= ~RECOMPUTE_OVERHANGS
;
3745 *overhangs
= This
->overhangs
;
3750 static HRESULT WINAPI
dwritetextlayout_GetClusterMetrics(IDWriteTextLayout3
*iface
,
3751 DWRITE_CLUSTER_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
3753 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3756 TRACE("(%p)->(%p %u %p)\n", This
, metrics
, max_count
, count
);
3758 hr
= layout_compute(This
);
3763 memcpy(metrics
, This
->clustermetrics
, sizeof(DWRITE_CLUSTER_METRICS
)*min(max_count
, This
->cluster_count
));
3765 *count
= This
->cluster_count
;
3766 return max_count
>= This
->cluster_count
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
3769 static HRESULT WINAPI
dwritetextlayout_DetermineMinWidth(IDWriteTextLayout3
*iface
, FLOAT
* min_width
)
3771 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3776 TRACE("(%p)->(%p)\n", This
, min_width
);
3779 return E_INVALIDARG
;
3781 if (!(This
->recompute
& RECOMPUTE_MINIMAL_WIDTH
))
3785 hr
= layout_compute(This
);
3789 /* Find widest word without emergency breaking between clusters, trailing whitespaces
3790 preceding breaking point do not contribute to word width. */
3791 for (start
= 0; start
< This
->cluster_count
;) {
3792 UINT32 end
= start
, j
, next
;
3794 /* Last cluster always could be wrapped after. */
3795 while (!This
->clustermetrics
[end
].canWrapLineAfter
)
3797 /* make is so current cluster range that we can wrap after is [start,end) */
3802 /* Ignore trailing whitespace clusters, in case of single space range will
3803 be reduced to empty range, or [start,start+1). */
3804 while (end
> start
&& This
->clustermetrics
[end
-1].isWhitespace
)
3807 /* check if cluster range exceeds last minimal width */
3809 for (j
= start
; j
< end
; j
++)
3810 width
+= This
->clustermetrics
[j
].width
;
3814 if (width
> This
->minwidth
)
3815 This
->minwidth
= width
;
3817 This
->recompute
&= ~RECOMPUTE_MINIMAL_WIDTH
;
3820 *min_width
= This
->minwidth
;
3824 static HRESULT WINAPI
dwritetextlayout_HitTestPoint(IDWriteTextLayout3
*iface
,
3825 FLOAT pointX
, FLOAT pointY
, BOOL
* is_trailinghit
, BOOL
* is_inside
, DWRITE_HIT_TEST_METRICS
*metrics
)
3827 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3828 FIXME("(%p)->(%f %f %p %p %p): stub\n", This
, pointX
, pointY
, is_trailinghit
, is_inside
, metrics
);
3832 static HRESULT WINAPI
dwritetextlayout_HitTestTextPosition(IDWriteTextLayout3
*iface
,
3833 UINT32 textPosition
, BOOL is_trailinghit
, FLOAT
* pointX
, FLOAT
* pointY
, DWRITE_HIT_TEST_METRICS
*metrics
)
3835 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3836 FIXME("(%p)->(%u %d %p %p %p): stub\n", This
, textPosition
, is_trailinghit
, pointX
, pointY
, metrics
);
3840 static HRESULT WINAPI
dwritetextlayout_HitTestTextRange(IDWriteTextLayout3
*iface
,
3841 UINT32 textPosition
, UINT32 textLength
, FLOAT originX
, FLOAT originY
,
3842 DWRITE_HIT_TEST_METRICS
*metrics
, UINT32 max_metricscount
, UINT32
* actual_metricscount
)
3844 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3845 FIXME("(%p)->(%u %u %f %f %p %u %p): stub\n", This
, textPosition
, textLength
, originX
, originY
, metrics
,
3846 max_metricscount
, actual_metricscount
);
3850 static HRESULT WINAPI
dwritetextlayout1_SetPairKerning(IDWriteTextLayout3
*iface
, BOOL is_pairkerning_enabled
,
3851 DWRITE_TEXT_RANGE range
)
3853 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3854 struct layout_range_attr_value value
;
3856 TRACE("(%p)->(%d %s)\n", This
, is_pairkerning_enabled
, debugstr_range(&range
));
3858 value
.range
= range
;
3859 value
.u
.pair_kerning
= !!is_pairkerning_enabled
;
3860 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_PAIR_KERNING
, &value
);
3863 static HRESULT WINAPI
dwritetextlayout1_GetPairKerning(IDWriteTextLayout3
*iface
, UINT32 position
, BOOL
*is_pairkerning_enabled
,
3864 DWRITE_TEXT_RANGE
*r
)
3866 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3867 struct layout_range
*range
;
3869 TRACE("(%p)->(%u %p %p)\n", This
, position
, is_pairkerning_enabled
, r
);
3871 if (position
>= This
->len
)
3874 range
= get_layout_range_by_pos(This
, position
);
3875 *is_pairkerning_enabled
= range
->pair_kerning
;
3877 return return_range(&range
->h
, r
);
3880 static HRESULT WINAPI
dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout3
*iface
, FLOAT leading
, FLOAT trailing
,
3881 FLOAT min_advance
, DWRITE_TEXT_RANGE range
)
3883 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3884 struct layout_range_attr_value value
;
3886 TRACE("(%p)->(%.2f %.2f %.2f %s)\n", This
, leading
, trailing
, min_advance
, debugstr_range(&range
));
3888 if (min_advance
< 0.0f
)
3889 return E_INVALIDARG
;
3891 value
.range
= range
;
3892 value
.u
.spacing
.leading
= leading
;
3893 value
.u
.spacing
.trailing
= trailing
;
3894 value
.u
.spacing
.min_advance
= min_advance
;
3895 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_SPACING
, &value
);
3898 static HRESULT WINAPI
dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout3
*iface
, UINT32 position
, FLOAT
*leading
,
3899 FLOAT
*trailing
, FLOAT
*min_advance
, DWRITE_TEXT_RANGE
*r
)
3901 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3902 struct layout_range_spacing
*range
;
3904 TRACE("(%p)->(%u %p %p %p %p)\n", This
, position
, leading
, trailing
, min_advance
, r
);
3906 range
= (struct layout_range_spacing
*)get_layout_range_header_by_pos(&This
->spacing
, position
);
3907 *leading
= range
->leading
;
3908 *trailing
= range
->trailing
;
3909 *min_advance
= range
->min_advance
;
3911 return return_range(&range
->h
, r
);
3914 static HRESULT WINAPI
dwritetextlayout2_GetMetrics(IDWriteTextLayout3
*iface
, DWRITE_TEXT_METRICS1
*metrics
)
3916 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3919 TRACE("(%p)->(%p)\n", This
, metrics
);
3921 hr
= layout_compute_effective_runs(This
);
3925 *metrics
= This
->metrics
;
3929 static HRESULT WINAPI
dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout3
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
3931 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3933 TRACE("(%p)->(%d)\n", This
, orientation
);
3935 if ((UINT32
)orientation
> DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED
)
3936 return E_INVALIDARG
;
3938 This
->format
.vertical_orientation
= orientation
;
3942 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout3
*iface
)
3944 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3945 TRACE("(%p)\n", This
);
3946 return This
->format
.vertical_orientation
;
3949 static HRESULT WINAPI
dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout3
*iface
, BOOL lastline_wrapping_enabled
)
3951 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3952 TRACE("(%p)->(%d)\n", This
, lastline_wrapping_enabled
);
3953 return IDWriteTextFormat1_SetLastLineWrapping(&This
->IDWriteTextFormat1_iface
, lastline_wrapping_enabled
);
3956 static BOOL WINAPI
dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout3
*iface
)
3958 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3959 TRACE("(%p)\n", This
);
3960 return IDWriteTextFormat1_GetLastLineWrapping(&This
->IDWriteTextFormat1_iface
);
3963 static HRESULT WINAPI
dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout3
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
3965 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3966 TRACE("(%p)->(%d)\n", This
, alignment
);
3967 return IDWriteTextFormat1_SetOpticalAlignment(&This
->IDWriteTextFormat1_iface
, alignment
);
3970 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout3
*iface
)
3972 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3973 TRACE("(%p)\n", This
);
3974 return IDWriteTextFormat1_GetOpticalAlignment(&This
->IDWriteTextFormat1_iface
);
3977 static HRESULT WINAPI
dwritetextlayout2_SetFontFallback(IDWriteTextLayout3
*iface
, IDWriteFontFallback
*fallback
)
3979 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3980 TRACE("(%p)->(%p)\n", This
, fallback
);
3981 return set_fontfallback_for_format(&This
->format
, fallback
);
3984 static HRESULT WINAPI
dwritetextlayout2_GetFontFallback(IDWriteTextLayout3
*iface
, IDWriteFontFallback
**fallback
)
3986 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3987 TRACE("(%p)->(%p)\n", This
, fallback
);
3988 return get_fontfallback_from_format(&This
->format
, fallback
);
3991 static HRESULT WINAPI
dwritetextlayout3_InvalidateLayout(IDWriteTextLayout3
*iface
)
3993 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3995 TRACE("(%p)\n", This
);
3997 This
->recompute
= RECOMPUTE_EVERYTHING
;
4001 static HRESULT WINAPI
dwritetextlayout3_SetLineSpacing(IDWriteTextLayout3
*iface
, DWRITE_LINE_SPACING
const *spacing
)
4003 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
4007 TRACE("(%p)->(%p)\n", This
, spacing
);
4009 hr
= format_set_linespacing(&This
->format
, spacing
, &changed
);
4014 if (!(This
->recompute
& RECOMPUTE_LINES
)) {
4017 for (line
= 0; line
< This
->metrics
.lineCount
; line
++)
4018 layout_apply_line_spacing(This
, line
);
4020 layout_set_line_positions(This
);
4023 This
->recompute
|= RECOMPUTE_OVERHANGS
;
4029 static HRESULT WINAPI
dwritetextlayout3_GetLineSpacing(IDWriteTextLayout3
*iface
, DWRITE_LINE_SPACING
*spacing
)
4031 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
4033 TRACE("(%p)->(%p)\n", This
, spacing
);
4035 *spacing
= This
->format
.spacing
;
4039 static HRESULT WINAPI
dwritetextlayout3_GetLineMetrics(IDWriteTextLayout3
*iface
, DWRITE_LINE_METRICS1
*metrics
,
4040 UINT32 max_count
, UINT32
*count
)
4042 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
4045 TRACE("(%p)->(%p %u %p)\n", This
, metrics
, max_count
, count
);
4047 hr
= layout_compute_effective_runs(This
);
4052 memcpy(metrics
, This
->linemetrics
, sizeof(*metrics
) * min(max_count
, This
->metrics
.lineCount
));
4054 *count
= This
->metrics
.lineCount
;
4055 return max_count
>= This
->metrics
.lineCount
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
4058 static const IDWriteTextLayout3Vtbl dwritetextlayoutvtbl
= {
4059 dwritetextlayout_QueryInterface
,
4060 dwritetextlayout_AddRef
,
4061 dwritetextlayout_Release
,
4062 dwritetextlayout_SetTextAlignment
,
4063 dwritetextlayout_SetParagraphAlignment
,
4064 dwritetextlayout_SetWordWrapping
,
4065 dwritetextlayout_SetReadingDirection
,
4066 dwritetextlayout_SetFlowDirection
,
4067 dwritetextlayout_SetIncrementalTabStop
,
4068 dwritetextlayout_SetTrimming
,
4069 dwritetextlayout_SetLineSpacing
,
4070 dwritetextlayout_GetTextAlignment
,
4071 dwritetextlayout_GetParagraphAlignment
,
4072 dwritetextlayout_GetWordWrapping
,
4073 dwritetextlayout_GetReadingDirection
,
4074 dwritetextlayout_GetFlowDirection
,
4075 dwritetextlayout_GetIncrementalTabStop
,
4076 dwritetextlayout_GetTrimming
,
4077 dwritetextlayout_GetLineSpacing
,
4078 dwritetextlayout_GetFontCollection
,
4079 dwritetextlayout_GetFontFamilyNameLength
,
4080 dwritetextlayout_GetFontFamilyName
,
4081 dwritetextlayout_GetFontWeight
,
4082 dwritetextlayout_GetFontStyle
,
4083 dwritetextlayout_GetFontStretch
,
4084 dwritetextlayout_GetFontSize
,
4085 dwritetextlayout_GetLocaleNameLength
,
4086 dwritetextlayout_GetLocaleName
,
4087 dwritetextlayout_SetMaxWidth
,
4088 dwritetextlayout_SetMaxHeight
,
4089 dwritetextlayout_SetFontCollection
,
4090 dwritetextlayout_SetFontFamilyName
,
4091 dwritetextlayout_SetFontWeight
,
4092 dwritetextlayout_SetFontStyle
,
4093 dwritetextlayout_SetFontStretch
,
4094 dwritetextlayout_SetFontSize
,
4095 dwritetextlayout_SetUnderline
,
4096 dwritetextlayout_SetStrikethrough
,
4097 dwritetextlayout_SetDrawingEffect
,
4098 dwritetextlayout_SetInlineObject
,
4099 dwritetextlayout_SetTypography
,
4100 dwritetextlayout_SetLocaleName
,
4101 dwritetextlayout_GetMaxWidth
,
4102 dwritetextlayout_GetMaxHeight
,
4103 dwritetextlayout_layout_GetFontCollection
,
4104 dwritetextlayout_layout_GetFontFamilyNameLength
,
4105 dwritetextlayout_layout_GetFontFamilyName
,
4106 dwritetextlayout_layout_GetFontWeight
,
4107 dwritetextlayout_layout_GetFontStyle
,
4108 dwritetextlayout_layout_GetFontStretch
,
4109 dwritetextlayout_layout_GetFontSize
,
4110 dwritetextlayout_GetUnderline
,
4111 dwritetextlayout_GetStrikethrough
,
4112 dwritetextlayout_GetDrawingEffect
,
4113 dwritetextlayout_GetInlineObject
,
4114 dwritetextlayout_GetTypography
,
4115 dwritetextlayout_layout_GetLocaleNameLength
,
4116 dwritetextlayout_layout_GetLocaleName
,
4117 dwritetextlayout_Draw
,
4118 dwritetextlayout_GetLineMetrics
,
4119 dwritetextlayout_GetMetrics
,
4120 dwritetextlayout_GetOverhangMetrics
,
4121 dwritetextlayout_GetClusterMetrics
,
4122 dwritetextlayout_DetermineMinWidth
,
4123 dwritetextlayout_HitTestPoint
,
4124 dwritetextlayout_HitTestTextPosition
,
4125 dwritetextlayout_HitTestTextRange
,
4126 dwritetextlayout1_SetPairKerning
,
4127 dwritetextlayout1_GetPairKerning
,
4128 dwritetextlayout1_SetCharacterSpacing
,
4129 dwritetextlayout1_GetCharacterSpacing
,
4130 dwritetextlayout2_GetMetrics
,
4131 dwritetextlayout2_SetVerticalGlyphOrientation
,
4132 dwritetextlayout2_GetVerticalGlyphOrientation
,
4133 dwritetextlayout2_SetLastLineWrapping
,
4134 dwritetextlayout2_GetLastLineWrapping
,
4135 dwritetextlayout2_SetOpticalAlignment
,
4136 dwritetextlayout2_GetOpticalAlignment
,
4137 dwritetextlayout2_SetFontFallback
,
4138 dwritetextlayout2_GetFontFallback
,
4139 dwritetextlayout3_InvalidateLayout
,
4140 dwritetextlayout3_SetLineSpacing
,
4141 dwritetextlayout3_GetLineSpacing
,
4142 dwritetextlayout3_GetLineMetrics
4145 static HRESULT WINAPI
dwritetextformat_layout_QueryInterface(IDWriteTextFormat1
*iface
, REFIID riid
, void **obj
)
4147 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4148 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
4149 return IDWriteTextLayout3_QueryInterface(&This
->IDWriteTextLayout3_iface
, riid
, obj
);
4152 static ULONG WINAPI
dwritetextformat_layout_AddRef(IDWriteTextFormat1
*iface
)
4154 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4155 return IDWriteTextLayout3_AddRef(&This
->IDWriteTextLayout3_iface
);
4158 static ULONG WINAPI
dwritetextformat_layout_Release(IDWriteTextFormat1
*iface
)
4160 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4161 return IDWriteTextLayout3_Release(&This
->IDWriteTextLayout3_iface
);
4164 static HRESULT WINAPI
dwritetextformat_layout_SetTextAlignment(IDWriteTextFormat1
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
4166 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4170 TRACE("(%p)->(%d)\n", This
, alignment
);
4172 hr
= format_set_textalignment(&This
->format
, alignment
, &changed
);
4177 /* if layout is not ready there's nothing to align */
4178 if (!(This
->recompute
& RECOMPUTE_LINES
))
4179 layout_apply_text_alignment(This
);
4180 This
->recompute
|= RECOMPUTE_OVERHANGS
;
4186 static HRESULT WINAPI
dwritetextformat_layout_SetParagraphAlignment(IDWriteTextFormat1
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
4188 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4192 TRACE("(%p)->(%d)\n", This
, alignment
);
4194 hr
= format_set_paralignment(&This
->format
, alignment
, &changed
);
4199 /* if layout is not ready there's nothing to align */
4200 if (!(This
->recompute
& RECOMPUTE_LINES
))
4201 layout_apply_par_alignment(This
);
4202 This
->recompute
|= RECOMPUTE_OVERHANGS
;
4208 static HRESULT WINAPI
dwritetextformat_layout_SetWordWrapping(IDWriteTextFormat1
*iface
, DWRITE_WORD_WRAPPING wrapping
)
4210 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4214 TRACE("(%p)->(%d)\n", This
, wrapping
);
4216 hr
= format_set_wordwrapping(&This
->format
, wrapping
, &changed
);
4221 This
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
4226 static HRESULT WINAPI
dwritetextformat_layout_SetReadingDirection(IDWriteTextFormat1
*iface
, DWRITE_READING_DIRECTION direction
)
4228 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4232 TRACE("(%p)->(%d)\n", This
, direction
);
4234 hr
= format_set_readingdirection(&This
->format
, direction
, &changed
);
4239 This
->recompute
= RECOMPUTE_EVERYTHING
;
4244 static HRESULT WINAPI
dwritetextformat_layout_SetFlowDirection(IDWriteTextFormat1
*iface
, DWRITE_FLOW_DIRECTION direction
)
4246 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4250 TRACE("(%p)->(%d)\n", This
, direction
);
4252 hr
= format_set_flowdirection(&This
->format
, direction
, &changed
);
4257 This
->recompute
= RECOMPUTE_EVERYTHING
;
4262 static HRESULT WINAPI
dwritetextformat_layout_SetIncrementalTabStop(IDWriteTextFormat1
*iface
, FLOAT tabstop
)
4264 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4265 FIXME("(%p)->(%f): stub\n", This
, tabstop
);
4269 static HRESULT WINAPI
dwritetextformat_layout_SetTrimming(IDWriteTextFormat1
*iface
, DWRITE_TRIMMING
const *trimming
,
4270 IDWriteInlineObject
*trimming_sign
)
4272 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4276 TRACE("(%p)->(%p %p)\n", This
, trimming
, trimming_sign
);
4278 hr
= format_set_trimming(&This
->format
, trimming
, trimming_sign
, &changed
);
4281 This
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
4286 static HRESULT WINAPI
dwritetextformat_layout_SetLineSpacing(IDWriteTextFormat1
*iface
, DWRITE_LINE_SPACING_METHOD method
,
4287 FLOAT height
, FLOAT baseline
)
4289 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4290 DWRITE_LINE_SPACING spacing
;
4292 TRACE("(%p)->(%d %f %f)\n", This
, method
, height
, baseline
);
4294 spacing
= This
->format
.spacing
;
4295 spacing
.method
= method
;
4296 spacing
.height
= height
;
4297 spacing
.baseline
= baseline
;
4298 return IDWriteTextLayout3_SetLineSpacing(&This
->IDWriteTextLayout3_iface
, &spacing
);
4301 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextformat_layout_GetTextAlignment(IDWriteTextFormat1
*iface
)
4303 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4304 TRACE("(%p)\n", This
);
4305 return This
->format
.textalignment
;
4308 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextformat_layout_GetParagraphAlignment(IDWriteTextFormat1
*iface
)
4310 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4311 TRACE("(%p)\n", This
);
4312 return This
->format
.paralign
;
4315 static DWRITE_WORD_WRAPPING WINAPI
dwritetextformat_layout_GetWordWrapping(IDWriteTextFormat1
*iface
)
4317 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4318 TRACE("(%p)\n", This
);
4319 return This
->format
.wrapping
;
4322 static DWRITE_READING_DIRECTION WINAPI
dwritetextformat_layout_GetReadingDirection(IDWriteTextFormat1
*iface
)
4324 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4325 TRACE("(%p)\n", This
);
4326 return This
->format
.readingdir
;
4329 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextformat_layout_GetFlowDirection(IDWriteTextFormat1
*iface
)
4331 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4332 TRACE("(%p)\n", This
);
4333 return This
->format
.flow
;
4336 static FLOAT WINAPI
dwritetextformat_layout_GetIncrementalTabStop(IDWriteTextFormat1
*iface
)
4338 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4339 FIXME("(%p): stub\n", This
);
4343 static HRESULT WINAPI
dwritetextformat_layout_GetTrimming(IDWriteTextFormat1
*iface
, DWRITE_TRIMMING
*options
,
4344 IDWriteInlineObject
**trimming_sign
)
4346 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4348 TRACE("(%p)->(%p %p)\n", This
, options
, trimming_sign
);
4350 *options
= This
->format
.trimming
;
4351 *trimming_sign
= This
->format
.trimmingsign
;
4353 IDWriteInlineObject_AddRef(*trimming_sign
);
4357 static HRESULT WINAPI
dwritetextformat_layout_GetLineSpacing(IDWriteTextFormat1
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
4358 FLOAT
*spacing
, FLOAT
*baseline
)
4360 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4362 TRACE("(%p)->(%p %p %p)\n", This
, method
, spacing
, baseline
);
4364 *method
= This
->format
.spacing
.method
;
4365 *spacing
= This
->format
.spacing
.height
;
4366 *baseline
= This
->format
.spacing
.baseline
;
4370 static HRESULT WINAPI
dwritetextformat_layout_GetFontCollection(IDWriteTextFormat1
*iface
, IDWriteFontCollection
**collection
)
4372 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4374 TRACE("(%p)->(%p)\n", This
, collection
);
4376 *collection
= This
->format
.collection
;
4378 IDWriteFontCollection_AddRef(*collection
);
4382 static UINT32 WINAPI
dwritetextformat_layout_GetFontFamilyNameLength(IDWriteTextFormat1
*iface
)
4384 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4385 TRACE("(%p)\n", This
);
4386 return This
->format
.family_len
;
4389 static HRESULT WINAPI
dwritetextformat_layout_GetFontFamilyName(IDWriteTextFormat1
*iface
, WCHAR
*name
, UINT32 size
)
4391 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4393 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
4395 if (size
<= This
->format
.family_len
) return E_NOT_SUFFICIENT_BUFFER
;
4396 strcpyW(name
, This
->format
.family_name
);
4400 static DWRITE_FONT_WEIGHT WINAPI
dwritetextformat_layout_GetFontWeight(IDWriteTextFormat1
*iface
)
4402 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4403 TRACE("(%p)\n", This
);
4404 return This
->format
.weight
;
4407 static DWRITE_FONT_STYLE WINAPI
dwritetextformat_layout_GetFontStyle(IDWriteTextFormat1
*iface
)
4409 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4410 TRACE("(%p)\n", This
);
4411 return This
->format
.style
;
4414 static DWRITE_FONT_STRETCH WINAPI
dwritetextformat_layout_GetFontStretch(IDWriteTextFormat1
*iface
)
4416 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4417 TRACE("(%p)\n", This
);
4418 return This
->format
.stretch
;
4421 static FLOAT WINAPI
dwritetextformat_layout_GetFontSize(IDWriteTextFormat1
*iface
)
4423 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4424 TRACE("(%p)\n", This
);
4425 return This
->format
.fontsize
;
4428 static UINT32 WINAPI
dwritetextformat_layout_GetLocaleNameLength(IDWriteTextFormat1
*iface
)
4430 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4431 TRACE("(%p)\n", This
);
4432 return This
->format
.locale_len
;
4435 static HRESULT WINAPI
dwritetextformat_layout_GetLocaleName(IDWriteTextFormat1
*iface
, WCHAR
*name
, UINT32 size
)
4437 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4439 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
4441 if (size
<= This
->format
.locale_len
) return E_NOT_SUFFICIENT_BUFFER
;
4442 strcpyW(name
, This
->format
.locale
);
4446 static HRESULT WINAPI
dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat1
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
4448 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4449 FIXME("(%p)->(%d): stub\n", This
, orientation
);
4453 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat1
*iface
)
4455 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4456 FIXME("(%p): stub\n", This
);
4457 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
4460 static HRESULT WINAPI
dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat1
*iface
, BOOL lastline_wrapping_enabled
)
4462 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4464 TRACE("(%p)->(%d)\n", This
, lastline_wrapping_enabled
);
4466 This
->format
.last_line_wrapping
= !!lastline_wrapping_enabled
;
4470 static BOOL WINAPI
dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat1
*iface
)
4472 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4473 TRACE("(%p)\n", This
);
4474 return This
->format
.last_line_wrapping
;
4477 static HRESULT WINAPI
dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat1
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
4479 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4480 TRACE("(%p)->(%d)\n", This
, alignment
);
4481 return format_set_optical_alignment(&This
->format
, alignment
);
4484 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat1
*iface
)
4486 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4487 TRACE("(%p)\n", This
);
4488 return This
->format
.optical_alignment
;
4491 static HRESULT WINAPI
dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat1
*iface
, IDWriteFontFallback
*fallback
)
4493 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4494 TRACE("(%p)->(%p)\n", This
, fallback
);
4495 return IDWriteTextLayout3_SetFontFallback(&This
->IDWriteTextLayout3_iface
, fallback
);
4498 static HRESULT WINAPI
dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat1
*iface
, IDWriteFontFallback
**fallback
)
4500 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4501 TRACE("(%p)->(%p)\n", This
, fallback
);
4502 return IDWriteTextLayout3_GetFontFallback(&This
->IDWriteTextLayout3_iface
, fallback
);
4505 static const IDWriteTextFormat1Vtbl dwritetextformat1_layout_vtbl
= {
4506 dwritetextformat_layout_QueryInterface
,
4507 dwritetextformat_layout_AddRef
,
4508 dwritetextformat_layout_Release
,
4509 dwritetextformat_layout_SetTextAlignment
,
4510 dwritetextformat_layout_SetParagraphAlignment
,
4511 dwritetextformat_layout_SetWordWrapping
,
4512 dwritetextformat_layout_SetReadingDirection
,
4513 dwritetextformat_layout_SetFlowDirection
,
4514 dwritetextformat_layout_SetIncrementalTabStop
,
4515 dwritetextformat_layout_SetTrimming
,
4516 dwritetextformat_layout_SetLineSpacing
,
4517 dwritetextformat_layout_GetTextAlignment
,
4518 dwritetextformat_layout_GetParagraphAlignment
,
4519 dwritetextformat_layout_GetWordWrapping
,
4520 dwritetextformat_layout_GetReadingDirection
,
4521 dwritetextformat_layout_GetFlowDirection
,
4522 dwritetextformat_layout_GetIncrementalTabStop
,
4523 dwritetextformat_layout_GetTrimming
,
4524 dwritetextformat_layout_GetLineSpacing
,
4525 dwritetextformat_layout_GetFontCollection
,
4526 dwritetextformat_layout_GetFontFamilyNameLength
,
4527 dwritetextformat_layout_GetFontFamilyName
,
4528 dwritetextformat_layout_GetFontWeight
,
4529 dwritetextformat_layout_GetFontStyle
,
4530 dwritetextformat_layout_GetFontStretch
,
4531 dwritetextformat_layout_GetFontSize
,
4532 dwritetextformat_layout_GetLocaleNameLength
,
4533 dwritetextformat_layout_GetLocaleName
,
4534 dwritetextformat1_layout_SetVerticalGlyphOrientation
,
4535 dwritetextformat1_layout_GetVerticalGlyphOrientation
,
4536 dwritetextformat1_layout_SetLastLineWrapping
,
4537 dwritetextformat1_layout_GetLastLineWrapping
,
4538 dwritetextformat1_layout_SetOpticalAlignment
,
4539 dwritetextformat1_layout_GetOpticalAlignment
,
4540 dwritetextformat1_layout_SetFontFallback
,
4541 dwritetextformat1_layout_GetFontFallback
,
4544 static HRESULT WINAPI
dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink1
*iface
,
4545 REFIID riid
, void **obj
)
4547 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSink1
) ||
4548 IsEqualIID(riid
, &IID_IDWriteTextAnalysisSink
) ||
4549 IsEqualIID(riid
, &IID_IUnknown
))
4552 IDWriteTextAnalysisSink1_AddRef(iface
);
4556 WARN("%s not implemented.\n", debugstr_guid(riid
));
4559 return E_NOINTERFACE
;
4562 static ULONG WINAPI
dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink1
*iface
)
4564 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4565 return IDWriteTextLayout3_AddRef(&layout
->IDWriteTextLayout3_iface
);
4568 static ULONG WINAPI
dwritetextlayout_sink_Release(IDWriteTextAnalysisSink1
*iface
)
4570 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4571 return IDWriteTextLayout3_Release(&layout
->IDWriteTextLayout3_iface
);
4574 static HRESULT WINAPI
dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink1
*iface
,
4575 UINT32 position
, UINT32 length
, DWRITE_SCRIPT_ANALYSIS
const* sa
)
4577 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4578 struct layout_run
*run
;
4580 TRACE("[%u,%u) script=%u:%s\n", position
, position
+ length
, sa
->script
, debugstr_sa_script(sa
->script
));
4582 run
= alloc_layout_run(LAYOUT_RUN_REGULAR
, position
);
4584 return E_OUTOFMEMORY
;
4586 run
->u
.regular
.descr
.string
= &layout
->str
[position
];
4587 run
->u
.regular
.descr
.stringLength
= length
;
4588 run
->u
.regular
.descr
.textPosition
= position
;
4589 run
->u
.regular
.sa
= *sa
;
4590 list_add_tail(&layout
->runs
, &run
->entry
);
4594 static HRESULT WINAPI
dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink1
*iface
,
4595 UINT32 position
, UINT32 length
, DWRITE_LINE_BREAKPOINT
const* breakpoints
)
4597 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4599 if (position
+ length
> layout
->len
)
4602 memcpy(&layout
->nominal_breakpoints
[position
], breakpoints
, length
*sizeof(DWRITE_LINE_BREAKPOINT
));
4606 static HRESULT WINAPI
dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink1
*iface
, UINT32 position
,
4607 UINT32 length
, UINT8 explicitLevel
, UINT8 resolvedLevel
)
4609 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4610 struct layout_run
*cur_run
;
4612 TRACE("[%u,%u) %u %u\n", position
, position
+ length
, explicitLevel
, resolvedLevel
);
4614 LIST_FOR_EACH_ENTRY(cur_run
, &layout
->runs
, struct layout_run
, entry
) {
4615 struct regular_layout_run
*cur
= &cur_run
->u
.regular
;
4616 struct layout_run
*run
;
4618 if (cur_run
->kind
== LAYOUT_RUN_INLINE
)
4621 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
4622 if (position
< cur
->descr
.textPosition
|| position
>= cur
->descr
.textPosition
+ cur
->descr
.stringLength
)
4625 /* full hit - just set run level */
4626 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
== length
) {
4627 cur
->run
.bidiLevel
= resolvedLevel
;
4631 /* current run is fully covered, move to next one */
4632 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
< length
) {
4633 cur
->run
.bidiLevel
= resolvedLevel
;
4634 position
+= cur
->descr
.stringLength
;
4635 length
-= cur
->descr
.stringLength
;
4639 /* all fully covered runs are processed at this point, reuse existing run for remaining
4640 reported bidi range and add another run for the rest of original one */
4642 run
= alloc_layout_run(LAYOUT_RUN_REGULAR
, position
+ length
);
4644 return E_OUTOFMEMORY
;
4647 run
->u
.regular
.descr
.textPosition
= position
+ length
;
4648 run
->u
.regular
.descr
.stringLength
= cur
->descr
.stringLength
- length
;
4649 run
->u
.regular
.descr
.string
= &layout
->str
[position
+ length
];
4651 /* reduce existing run */
4652 cur
->run
.bidiLevel
= resolvedLevel
;
4653 cur
->descr
.stringLength
= length
;
4655 list_add_after(&cur_run
->entry
, &run
->entry
);
4662 static HRESULT WINAPI
dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink1
*iface
,
4663 UINT32 position
, UINT32 length
, IDWriteNumberSubstitution
* substitution
)
4668 static HRESULT WINAPI
dwritetextlayout_sink_SetGlyphOrientation(IDWriteTextAnalysisSink1
*iface
,
4669 UINT32 position
, UINT32 length
, DWRITE_GLYPH_ORIENTATION_ANGLE angle
, UINT8 adjusted_bidi_level
,
4670 BOOL is_sideways
, BOOL is_rtl
)
4675 static const IDWriteTextAnalysisSink1Vtbl dwritetextlayoutsinkvtbl
= {
4676 dwritetextlayout_sink_QueryInterface
,
4677 dwritetextlayout_sink_AddRef
,
4678 dwritetextlayout_sink_Release
,
4679 dwritetextlayout_sink_SetScriptAnalysis
,
4680 dwritetextlayout_sink_SetLineBreakpoints
,
4681 dwritetextlayout_sink_SetBidiLevel
,
4682 dwritetextlayout_sink_SetNumberSubstitution
,
4683 dwritetextlayout_sink_SetGlyphOrientation
4686 static HRESULT WINAPI
dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource1
*iface
,
4687 REFIID riid
, void **obj
)
4689 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSource1
) ||
4690 IsEqualIID(riid
, &IID_IDWriteTextAnalysisSource
) ||
4691 IsEqualIID(riid
, &IID_IUnknown
))
4694 IDWriteTextAnalysisSource1_AddRef(iface
);
4698 WARN("%s not implemented.\n", debugstr_guid(riid
));
4701 return E_NOINTERFACE
;
4704 static ULONG WINAPI
dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource1
*iface
)
4706 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4707 return IDWriteTextLayout3_AddRef(&layout
->IDWriteTextLayout3_iface
);
4710 static ULONG WINAPI
dwritetextlayout_source_Release(IDWriteTextAnalysisSource1
*iface
)
4712 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4713 return IDWriteTextLayout3_Release(&layout
->IDWriteTextLayout3_iface
);
4716 static HRESULT WINAPI
dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource1
*iface
,
4717 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
4719 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4721 TRACE("(%p)->(%u %p %p)\n", layout
, position
, text
, text_len
);
4723 if (position
< layout
->len
) {
4724 *text
= &layout
->str
[position
];
4725 *text_len
= layout
->len
- position
;
4735 static HRESULT WINAPI
dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource1
*iface
,
4736 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
4738 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4740 TRACE("(%p)->(%u %p %p)\n", layout
, position
, text
, text_len
);
4742 if (position
> 0 && position
< layout
->len
) {
4743 *text
= layout
->str
;
4744 *text_len
= position
;
4754 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource1
*iface
)
4756 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4757 return IDWriteTextLayout3_GetReadingDirection(&layout
->IDWriteTextLayout3_iface
);
4760 static HRESULT WINAPI
dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource1
*iface
,
4761 UINT32 position
, UINT32
* text_len
, WCHAR
const** locale
)
4763 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4764 struct layout_range
*range
= get_layout_range_by_pos(layout
, position
);
4766 if (position
< layout
->len
) {
4767 struct layout_range
*next
;
4769 *locale
= range
->locale
;
4770 *text_len
= range
->h
.range
.length
- position
;
4772 next
= LIST_ENTRY(list_next(&layout
->ranges
, &range
->h
.entry
), struct layout_range
, h
.entry
);
4773 while (next
&& next
->h
.range
.startPosition
< layout
->len
&& !strcmpW(range
->locale
, next
->locale
)) {
4774 *text_len
+= next
->h
.range
.length
;
4775 next
= LIST_ENTRY(list_next(&layout
->ranges
, &next
->h
.entry
), struct layout_range
, h
.entry
);
4778 *text_len
= min(*text_len
, layout
->len
- position
);
4788 static HRESULT WINAPI
dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource1
*iface
,
4789 UINT32 position
, UINT32
* text_len
, IDWriteNumberSubstitution
**substitution
)
4791 FIXME("%u %p %p: stub\n", position
, text_len
, substitution
);
4795 static HRESULT WINAPI
dwritetextlayout_source_GetVerticalGlyphOrientation(IDWriteTextAnalysisSource1
*iface
,
4796 UINT32 position
, UINT32
*length
, DWRITE_VERTICAL_GLYPH_ORIENTATION
*orientation
, UINT8
*bidi_level
)
4798 FIXME("%u %p %p %p: stub\n", position
, length
, orientation
, bidi_level
);
4802 static const IDWriteTextAnalysisSource1Vtbl dwritetextlayoutsourcevtbl
= {
4803 dwritetextlayout_source_QueryInterface
,
4804 dwritetextlayout_source_AddRef
,
4805 dwritetextlayout_source_Release
,
4806 dwritetextlayout_source_GetTextAtPosition
,
4807 dwritetextlayout_source_GetTextBeforePosition
,
4808 dwritetextlayout_source_GetParagraphReadingDirection
,
4809 dwritetextlayout_source_GetLocaleName
,
4810 dwritetextlayout_source_GetNumberSubstitution
,
4811 dwritetextlayout_source_GetVerticalGlyphOrientation
4814 static HRESULT
layout_format_from_textformat(struct dwrite_textlayout
*layout
, IDWriteTextFormat
*format
)
4816 struct dwrite_textformat
*textformat
;
4817 IDWriteTextFormat1
*format1
;
4821 if ((textformat
= unsafe_impl_from_IDWriteTextFormat(format
))) {
4822 layout
->format
= textformat
->format
;
4824 layout
->format
.locale
= heap_strdupW(textformat
->format
.locale
);
4825 layout
->format
.family_name
= heap_strdupW(textformat
->format
.family_name
);
4826 if (!layout
->format
.locale
|| !layout
->format
.family_name
)
4828 heap_free(layout
->format
.locale
);
4829 heap_free(layout
->format
.family_name
);
4830 return E_OUTOFMEMORY
;
4833 if (layout
->format
.trimmingsign
)
4834 IDWriteInlineObject_AddRef(layout
->format
.trimmingsign
);
4835 if (layout
->format
.collection
)
4836 IDWriteFontCollection_AddRef(layout
->format
.collection
);
4837 if (layout
->format
.fallback
)
4838 IDWriteFontFallback_AddRef(layout
->format
.fallback
);
4843 layout
->format
.weight
= IDWriteTextFormat_GetFontWeight(format
);
4844 layout
->format
.style
= IDWriteTextFormat_GetFontStyle(format
);
4845 layout
->format
.stretch
= IDWriteTextFormat_GetFontStretch(format
);
4846 layout
->format
.fontsize
= IDWriteTextFormat_GetFontSize(format
);
4847 layout
->format
.textalignment
= IDWriteTextFormat_GetTextAlignment(format
);
4848 layout
->format
.paralign
= IDWriteTextFormat_GetParagraphAlignment(format
);
4849 layout
->format
.wrapping
= IDWriteTextFormat_GetWordWrapping(format
);
4850 layout
->format
.readingdir
= IDWriteTextFormat_GetReadingDirection(format
);
4851 layout
->format
.flow
= IDWriteTextFormat_GetFlowDirection(format
);
4852 layout
->format
.fallback
= NULL
;
4853 layout
->format
.spacing
.leadingBefore
= 0.0f
;
4854 layout
->format
.spacing
.fontLineGapUsage
= DWRITE_FONT_LINE_GAP_USAGE_DEFAULT
;
4855 hr
= IDWriteTextFormat_GetLineSpacing(format
, &layout
->format
.spacing
.method
,
4856 &layout
->format
.spacing
.height
, &layout
->format
.spacing
.baseline
);
4860 hr
= IDWriteTextFormat_GetTrimming(format
, &layout
->format
.trimming
, &layout
->format
.trimmingsign
);
4864 /* locale name and length */
4865 len
= IDWriteTextFormat_GetLocaleNameLength(format
);
4866 layout
->format
.locale
= heap_alloc((len
+1)*sizeof(WCHAR
));
4867 if (!layout
->format
.locale
)
4868 return E_OUTOFMEMORY
;
4870 hr
= IDWriteTextFormat_GetLocaleName(format
, layout
->format
.locale
, len
+1);
4873 layout
->format
.locale_len
= len
;
4875 /* font family name and length */
4876 len
= IDWriteTextFormat_GetFontFamilyNameLength(format
);
4877 layout
->format
.family_name
= heap_alloc((len
+1)*sizeof(WCHAR
));
4878 if (!layout
->format
.family_name
)
4879 return E_OUTOFMEMORY
;
4881 hr
= IDWriteTextFormat_GetFontFamilyName(format
, layout
->format
.family_name
, len
+1);
4884 layout
->format
.family_len
= len
;
4886 hr
= IDWriteTextFormat_QueryInterface(format
, &IID_IDWriteTextFormat1
, (void**)&format1
);
4888 IDWriteTextFormat2
*format2
;
4890 layout
->format
.vertical_orientation
= IDWriteTextFormat1_GetVerticalGlyphOrientation(format1
);
4891 layout
->format
.optical_alignment
= IDWriteTextFormat1_GetOpticalAlignment(format1
);
4892 IDWriteTextFormat1_GetFontFallback(format1
, &layout
->format
.fallback
);
4894 if (IDWriteTextFormat1_QueryInterface(format1
, &IID_IDWriteTextFormat2
, (void**)&format2
) == S_OK
) {
4895 IDWriteTextFormat2_GetLineSpacing(format2
, &layout
->format
.spacing
);
4896 IDWriteTextFormat2_Release(format2
);
4899 IDWriteTextFormat1_Release(format1
);
4902 layout
->format
.vertical_orientation
= DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
4903 layout
->format
.optical_alignment
= DWRITE_OPTICAL_ALIGNMENT_NONE
;
4906 return IDWriteTextFormat_GetFontCollection(format
, &layout
->format
.collection
);
4909 static HRESULT
init_textlayout(const struct textlayout_desc
*desc
, struct dwrite_textlayout
*layout
)
4911 struct layout_range_header
*range
, *strike
, *underline
, *effect
, *spacing
, *typography
;
4912 static const DWRITE_TEXT_RANGE r
= { 0, ~0u };
4915 layout
->IDWriteTextLayout3_iface
.lpVtbl
= &dwritetextlayoutvtbl
;
4916 layout
->IDWriteTextFormat1_iface
.lpVtbl
= &dwritetextformat1_layout_vtbl
;
4917 layout
->IDWriteTextAnalysisSink1_iface
.lpVtbl
= &dwritetextlayoutsinkvtbl
;
4918 layout
->IDWriteTextAnalysisSource1_iface
.lpVtbl
= &dwritetextlayoutsourcevtbl
;
4920 layout
->len
= desc
->length
;
4921 layout
->recompute
= RECOMPUTE_EVERYTHING
;
4922 layout
->nominal_breakpoints
= NULL
;
4923 layout
->actual_breakpoints
= NULL
;
4924 layout
->cluster_count
= 0;
4925 layout
->clustermetrics
= NULL
;
4926 layout
->clusters
= NULL
;
4927 layout
->linemetrics
= NULL
;
4928 layout
->lines
= NULL
;
4929 layout
->line_alloc
= 0;
4930 layout
->minwidth
= 0.0f
;
4931 list_init(&layout
->eruns
);
4932 list_init(&layout
->inlineobjects
);
4933 list_init(&layout
->underlines
);
4934 list_init(&layout
->strikethrough
);
4935 list_init(&layout
->runs
);
4936 list_init(&layout
->ranges
);
4937 list_init(&layout
->strike_ranges
);
4938 list_init(&layout
->underline_ranges
);
4939 list_init(&layout
->effects
);
4940 list_init(&layout
->spacing
);
4941 list_init(&layout
->typographies
);
4942 memset(&layout
->format
, 0, sizeof(layout
->format
));
4943 memset(&layout
->metrics
, 0, sizeof(layout
->metrics
));
4944 layout
->metrics
.layoutWidth
= desc
->max_width
;
4945 layout
->metrics
.layoutHeight
= desc
->max_height
;
4946 layout
->measuringmode
= DWRITE_MEASURING_MODE_NATURAL
;
4948 layout
->ppdip
= 0.0f
;
4949 memset(&layout
->transform
, 0, sizeof(layout
->transform
));
4951 layout
->str
= heap_strdupnW(desc
->string
, desc
->length
);
4952 if (desc
->length
&& !layout
->str
) {
4957 hr
= layout_format_from_textformat(layout
, desc
->format
);
4961 range
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_REGULAR
);
4962 strike
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_STRIKETHROUGH
);
4963 underline
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_UNDERLINE
);
4964 effect
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_EFFECT
);
4965 spacing
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_SPACING
);
4966 typography
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_TYPOGRAPHY
);
4967 if (!range
|| !strike
|| !effect
|| !spacing
|| !typography
|| !underline
) {
4968 free_layout_range(range
);
4969 free_layout_range(strike
);
4970 free_layout_range(underline
);
4971 free_layout_range(effect
);
4972 free_layout_range(spacing
);
4973 free_layout_range(typography
);
4978 if (desc
->is_gdi_compatible
)
4979 layout
->measuringmode
= desc
->use_gdi_natural
? DWRITE_MEASURING_MODE_GDI_NATURAL
: DWRITE_MEASURING_MODE_GDI_CLASSIC
;
4981 layout
->measuringmode
= DWRITE_MEASURING_MODE_NATURAL
;
4982 layout
->ppdip
= desc
->ppdip
;
4983 layout
->transform
= desc
->transform
? *desc
->transform
: identity
;
4985 layout
->factory
= desc
->factory
;
4986 IDWriteFactory5_AddRef(layout
->factory
);
4987 list_add_head(&layout
->ranges
, &range
->entry
);
4988 list_add_head(&layout
->strike_ranges
, &strike
->entry
);
4989 list_add_head(&layout
->underline_ranges
, &underline
->entry
);
4990 list_add_head(&layout
->effects
, &effect
->entry
);
4991 list_add_head(&layout
->spacing
, &spacing
->entry
);
4992 list_add_head(&layout
->typographies
, &typography
->entry
);
4996 IDWriteTextLayout3_Release(&layout
->IDWriteTextLayout3_iface
);
5000 HRESULT
create_textlayout(const struct textlayout_desc
*desc
, IDWriteTextLayout
**ret
)
5002 struct dwrite_textlayout
*layout
;
5007 if (!desc
->format
|| !desc
->string
)
5008 return E_INVALIDARG
;
5010 layout
= heap_alloc(sizeof(struct dwrite_textlayout
));
5011 if (!layout
) return E_OUTOFMEMORY
;
5013 hr
= init_textlayout(desc
, layout
);
5015 *ret
= (IDWriteTextLayout
*)&layout
->IDWriteTextLayout3_iface
;
5020 static HRESULT WINAPI
dwritetrimmingsign_QueryInterface(IDWriteInlineObject
*iface
, REFIID riid
, void **obj
)
5022 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5024 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
5026 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDWriteInlineObject
)) {
5028 IDWriteInlineObject_AddRef(iface
);
5032 WARN("%s not implemented.\n", debugstr_guid(riid
));
5035 return E_NOINTERFACE
;
5038 static ULONG WINAPI
dwritetrimmingsign_AddRef(IDWriteInlineObject
*iface
)
5040 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5041 ULONG ref
= InterlockedIncrement(&This
->ref
);
5042 TRACE("(%p)->(%d)\n", This
, ref
);
5046 static ULONG WINAPI
dwritetrimmingsign_Release(IDWriteInlineObject
*iface
)
5048 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5049 ULONG ref
= InterlockedDecrement(&This
->ref
);
5051 TRACE("(%p)->(%d)\n", This
, ref
);
5054 IDWriteTextLayout_Release(This
->layout
);
5061 static HRESULT WINAPI
dwritetrimmingsign_Draw(IDWriteInlineObject
*iface
, void *context
, IDWriteTextRenderer
*renderer
,
5062 FLOAT originX
, FLOAT originY
, BOOL is_sideways
, BOOL is_rtl
, IUnknown
*effect
)
5064 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5065 DWRITE_LINE_METRICS line
;
5068 TRACE("(%p)->(%p %p %.2f %.2f %d %d %p)\n", This
, context
, renderer
, originX
, originY
,
5069 is_sideways
, is_rtl
, effect
);
5071 IDWriteTextLayout_GetLineMetrics(This
->layout
, &line
, 1, &line_count
);
5072 return IDWriteTextLayout_Draw(This
->layout
, context
, renderer
, originX
, originY
- line
.baseline
);
5075 static HRESULT WINAPI
dwritetrimmingsign_GetMetrics(IDWriteInlineObject
*iface
, DWRITE_INLINE_OBJECT_METRICS
*ret
)
5077 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5078 DWRITE_TEXT_METRICS metrics
;
5081 TRACE("(%p)->(%p)\n", This
, ret
);
5083 hr
= IDWriteTextLayout_GetMetrics(This
->layout
, &metrics
);
5085 memset(ret
, 0, sizeof(*ret
));
5089 ret
->width
= metrics
.width
;
5091 ret
->baseline
= 0.0f
;
5092 ret
->supportsSideways
= FALSE
;
5096 static HRESULT WINAPI
dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject
*iface
, DWRITE_OVERHANG_METRICS
*overhangs
)
5098 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5099 TRACE("(%p)->(%p)\n", This
, overhangs
);
5100 return IDWriteTextLayout_GetOverhangMetrics(This
->layout
, overhangs
);
5103 static HRESULT WINAPI
dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject
*iface
, DWRITE_BREAK_CONDITION
*before
,
5104 DWRITE_BREAK_CONDITION
*after
)
5106 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5108 TRACE("(%p)->(%p %p)\n", This
, before
, after
);
5110 *before
= *after
= DWRITE_BREAK_CONDITION_NEUTRAL
;
5114 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl
= {
5115 dwritetrimmingsign_QueryInterface
,
5116 dwritetrimmingsign_AddRef
,
5117 dwritetrimmingsign_Release
,
5118 dwritetrimmingsign_Draw
,
5119 dwritetrimmingsign_GetMetrics
,
5120 dwritetrimmingsign_GetOverhangMetrics
,
5121 dwritetrimmingsign_GetBreakConditions
5124 static inline BOOL
is_reading_direction_horz(DWRITE_READING_DIRECTION direction
)
5126 return (direction
== DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
) ||
5127 (direction
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
);
5130 static inline BOOL
is_reading_direction_vert(DWRITE_READING_DIRECTION direction
)
5132 return (direction
== DWRITE_READING_DIRECTION_TOP_TO_BOTTOM
) ||
5133 (direction
== DWRITE_READING_DIRECTION_BOTTOM_TO_TOP
);
5136 static inline BOOL
is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction
)
5138 return (direction
== DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT
) ||
5139 (direction
== DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT
);
5142 static inline BOOL
is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction
)
5144 return (direction
== DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM
) ||
5145 (direction
== DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP
);
5148 HRESULT
create_trimmingsign(IDWriteFactory5
*factory
, IDWriteTextFormat
*format
, IDWriteInlineObject
**sign
)
5150 static const WCHAR ellipsisW
= 0x2026;
5151 struct dwrite_trimmingsign
*This
;
5152 DWRITE_READING_DIRECTION reading
;
5153 DWRITE_FLOW_DIRECTION flow
;
5158 /* Validate reading/flow direction here, layout creation won't complain about
5159 invalid combinations. */
5160 reading
= IDWriteTextFormat_GetReadingDirection(format
);
5161 flow
= IDWriteTextFormat_GetFlowDirection(format
);
5163 if ((is_reading_direction_horz(reading
) && is_flow_direction_horz(flow
)) ||
5164 (is_reading_direction_vert(reading
) && is_flow_direction_vert(flow
)))
5165 return DWRITE_E_FLOWDIRECTIONCONFLICTS
;
5167 This
= heap_alloc(sizeof(*This
));
5169 return E_OUTOFMEMORY
;
5171 This
->IDWriteInlineObject_iface
.lpVtbl
= &dwritetrimmingsignvtbl
;
5174 hr
= IDWriteFactory5_CreateTextLayout(factory
, &ellipsisW
, 1, format
, 0.0f
, 0.0f
, &This
->layout
);
5180 IDWriteTextLayout_SetWordWrapping(This
->layout
, DWRITE_WORD_WRAPPING_NO_WRAP
);
5181 IDWriteTextLayout_SetParagraphAlignment(This
->layout
, DWRITE_PARAGRAPH_ALIGNMENT_NEAR
);
5182 IDWriteTextLayout_SetTextAlignment(This
->layout
, DWRITE_TEXT_ALIGNMENT_LEADING
);
5184 *sign
= &This
->IDWriteInlineObject_iface
;
5189 static HRESULT WINAPI
dwritetextformat_QueryInterface(IDWriteTextFormat2
*iface
, REFIID riid
, void **obj
)
5191 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5193 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
5195 if (IsEqualIID(riid
, &IID_IDWriteTextFormat2
) ||
5196 IsEqualIID(riid
, &IID_IDWriteTextFormat1
) ||
5197 IsEqualIID(riid
, &IID_IDWriteTextFormat
) ||
5198 IsEqualIID(riid
, &IID_IUnknown
))
5201 IDWriteTextFormat2_AddRef(iface
);
5205 WARN("%s not implemented.\n", debugstr_guid(riid
));
5209 return E_NOINTERFACE
;
5212 static ULONG WINAPI
dwritetextformat_AddRef(IDWriteTextFormat2
*iface
)
5214 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5215 ULONG ref
= InterlockedIncrement(&This
->ref
);
5216 TRACE("(%p)->(%d)\n", This
, ref
);
5220 static ULONG WINAPI
dwritetextformat_Release(IDWriteTextFormat2
*iface
)
5222 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5223 ULONG ref
= InterlockedDecrement(&This
->ref
);
5225 TRACE("(%p)->(%d)\n", This
, ref
);
5229 release_format_data(&This
->format
);
5236 static HRESULT WINAPI
dwritetextformat_SetTextAlignment(IDWriteTextFormat2
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
5238 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5239 TRACE("(%p)->(%d)\n", This
, alignment
);
5240 return format_set_textalignment(&This
->format
, alignment
, NULL
);
5243 static HRESULT WINAPI
dwritetextformat_SetParagraphAlignment(IDWriteTextFormat2
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
5245 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5246 TRACE("(%p)->(%d)\n", This
, alignment
);
5247 return format_set_paralignment(&This
->format
, alignment
, NULL
);
5250 static HRESULT WINAPI
dwritetextformat_SetWordWrapping(IDWriteTextFormat2
*iface
, DWRITE_WORD_WRAPPING wrapping
)
5252 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5253 TRACE("(%p)->(%d)\n", This
, wrapping
);
5254 return format_set_wordwrapping(&This
->format
, wrapping
, NULL
);
5257 static HRESULT WINAPI
dwritetextformat_SetReadingDirection(IDWriteTextFormat2
*iface
, DWRITE_READING_DIRECTION direction
)
5259 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5260 TRACE("(%p)->(%d)\n", This
, direction
);
5261 return format_set_readingdirection(&This
->format
, direction
, NULL
);
5264 static HRESULT WINAPI
dwritetextformat_SetFlowDirection(IDWriteTextFormat2
*iface
, DWRITE_FLOW_DIRECTION direction
)
5266 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5267 TRACE("(%p)->(%d)\n", This
, direction
);
5268 return format_set_flowdirection(&This
->format
, direction
, NULL
);
5271 static HRESULT WINAPI
dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat2
*iface
, FLOAT tabstop
)
5273 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5274 FIXME("(%p)->(%f): stub\n", This
, tabstop
);
5278 static HRESULT WINAPI
dwritetextformat_SetTrimming(IDWriteTextFormat2
*iface
, DWRITE_TRIMMING
const *trimming
,
5279 IDWriteInlineObject
*trimming_sign
)
5281 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5282 TRACE("(%p)->(%p %p)\n", This
, trimming
, trimming_sign
);
5283 return format_set_trimming(&This
->format
, trimming
, trimming_sign
, NULL
);
5286 static HRESULT WINAPI
dwritetextformat_SetLineSpacing(IDWriteTextFormat2
*iface
, DWRITE_LINE_SPACING_METHOD method
,
5287 FLOAT height
, FLOAT baseline
)
5289 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5290 DWRITE_LINE_SPACING spacing
;
5292 TRACE("(%p)->(%d %f %f)\n", This
, method
, height
, baseline
);
5294 spacing
= This
->format
.spacing
;
5295 spacing
.method
= method
;
5296 spacing
.height
= height
;
5297 spacing
.baseline
= baseline
;
5299 return format_set_linespacing(&This
->format
, &spacing
, NULL
);
5302 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextformat_GetTextAlignment(IDWriteTextFormat2
*iface
)
5304 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5305 TRACE("(%p)\n", This
);
5306 return This
->format
.textalignment
;
5309 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextformat_GetParagraphAlignment(IDWriteTextFormat2
*iface
)
5311 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5312 TRACE("(%p)\n", This
);
5313 return This
->format
.paralign
;
5316 static DWRITE_WORD_WRAPPING WINAPI
dwritetextformat_GetWordWrapping(IDWriteTextFormat2
*iface
)
5318 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5319 TRACE("(%p)\n", This
);
5320 return This
->format
.wrapping
;
5323 static DWRITE_READING_DIRECTION WINAPI
dwritetextformat_GetReadingDirection(IDWriteTextFormat2
*iface
)
5325 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5326 TRACE("(%p)\n", This
);
5327 return This
->format
.readingdir
;
5330 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextformat_GetFlowDirection(IDWriteTextFormat2
*iface
)
5332 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5333 TRACE("(%p)\n", This
);
5334 return This
->format
.flow
;
5337 static FLOAT WINAPI
dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat2
*iface
)
5339 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5340 FIXME("(%p): stub\n", This
);
5344 static HRESULT WINAPI
dwritetextformat_GetTrimming(IDWriteTextFormat2
*iface
, DWRITE_TRIMMING
*options
,
5345 IDWriteInlineObject
**trimming_sign
)
5347 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5348 TRACE("(%p)->(%p %p)\n", This
, options
, trimming_sign
);
5350 *options
= This
->format
.trimming
;
5351 if ((*trimming_sign
= This
->format
.trimmingsign
))
5352 IDWriteInlineObject_AddRef(*trimming_sign
);
5357 static HRESULT WINAPI
dwritetextformat_GetLineSpacing(IDWriteTextFormat2
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
5358 FLOAT
*spacing
, FLOAT
*baseline
)
5360 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5361 TRACE("(%p)->(%p %p %p)\n", This
, method
, spacing
, baseline
);
5363 *method
= This
->format
.spacing
.method
;
5364 *spacing
= This
->format
.spacing
.height
;
5365 *baseline
= This
->format
.spacing
.baseline
;
5369 static HRESULT WINAPI
dwritetextformat_GetFontCollection(IDWriteTextFormat2
*iface
, IDWriteFontCollection
**collection
)
5371 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5373 TRACE("(%p)->(%p)\n", This
, collection
);
5375 *collection
= This
->format
.collection
;
5376 IDWriteFontCollection_AddRef(*collection
);
5381 static UINT32 WINAPI
dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat2
*iface
)
5383 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5384 TRACE("(%p)\n", This
);
5385 return This
->format
.family_len
;
5388 static HRESULT WINAPI
dwritetextformat_GetFontFamilyName(IDWriteTextFormat2
*iface
, WCHAR
*name
, UINT32 size
)
5390 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5392 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
5394 if (size
<= This
->format
.family_len
) return E_NOT_SUFFICIENT_BUFFER
;
5395 strcpyW(name
, This
->format
.family_name
);
5399 static DWRITE_FONT_WEIGHT WINAPI
dwritetextformat_GetFontWeight(IDWriteTextFormat2
*iface
)
5401 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5402 TRACE("(%p)\n", This
);
5403 return This
->format
.weight
;
5406 static DWRITE_FONT_STYLE WINAPI
dwritetextformat_GetFontStyle(IDWriteTextFormat2
*iface
)
5408 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5409 TRACE("(%p)\n", This
);
5410 return This
->format
.style
;
5413 static DWRITE_FONT_STRETCH WINAPI
dwritetextformat_GetFontStretch(IDWriteTextFormat2
*iface
)
5415 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5416 TRACE("(%p)\n", This
);
5417 return This
->format
.stretch
;
5420 static FLOAT WINAPI
dwritetextformat_GetFontSize(IDWriteTextFormat2
*iface
)
5422 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5423 TRACE("(%p)\n", This
);
5424 return This
->format
.fontsize
;
5427 static UINT32 WINAPI
dwritetextformat_GetLocaleNameLength(IDWriteTextFormat2
*iface
)
5429 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5430 TRACE("(%p)\n", This
);
5431 return This
->format
.locale_len
;
5434 static HRESULT WINAPI
dwritetextformat_GetLocaleName(IDWriteTextFormat2
*iface
, WCHAR
*name
, UINT32 size
)
5436 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5438 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
5440 if (size
<= This
->format
.locale_len
) return E_NOT_SUFFICIENT_BUFFER
;
5441 strcpyW(name
, This
->format
.locale
);
5445 static HRESULT WINAPI
dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat2
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
5447 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5449 TRACE("(%p)->(%d)\n", This
, orientation
);
5451 if ((UINT32
)orientation
> DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED
)
5452 return E_INVALIDARG
;
5454 This
->format
.vertical_orientation
= orientation
;
5458 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat2
*iface
)
5460 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5461 TRACE("(%p)\n", This
);
5462 return This
->format
.vertical_orientation
;
5465 static HRESULT WINAPI
dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat2
*iface
, BOOL lastline_wrapping_enabled
)
5467 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5469 TRACE("(%p)->(%d)\n", This
, lastline_wrapping_enabled
);
5471 This
->format
.last_line_wrapping
= !!lastline_wrapping_enabled
;
5475 static BOOL WINAPI
dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat2
*iface
)
5477 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5478 TRACE("(%p)\n", This
);
5479 return This
->format
.last_line_wrapping
;
5482 static HRESULT WINAPI
dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat2
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
5484 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5485 TRACE("(%p)->(%d)\n", This
, alignment
);
5486 return format_set_optical_alignment(&This
->format
, alignment
);
5489 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat2
*iface
)
5491 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5492 TRACE("(%p)\n", This
);
5493 return This
->format
.optical_alignment
;
5496 static HRESULT WINAPI
dwritetextformat1_SetFontFallback(IDWriteTextFormat2
*iface
, IDWriteFontFallback
*fallback
)
5498 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5499 TRACE("(%p)->(%p)\n", This
, fallback
);
5500 return set_fontfallback_for_format(&This
->format
, fallback
);
5503 static HRESULT WINAPI
dwritetextformat1_GetFontFallback(IDWriteTextFormat2
*iface
, IDWriteFontFallback
**fallback
)
5505 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5506 TRACE("(%p)->(%p)\n", This
, fallback
);
5507 return get_fontfallback_from_format(&This
->format
, fallback
);
5510 static HRESULT WINAPI
dwritetextformat2_SetLineSpacing(IDWriteTextFormat2
*iface
, DWRITE_LINE_SPACING
const *spacing
)
5512 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5513 TRACE("(%p)->(%p)\n", This
, spacing
);
5514 return format_set_linespacing(&This
->format
, spacing
, NULL
);
5517 static HRESULT WINAPI
dwritetextformat2_GetLineSpacing(IDWriteTextFormat2
*iface
, DWRITE_LINE_SPACING
*spacing
)
5519 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5521 TRACE("(%p)->(%p)\n", This
, spacing
);
5523 *spacing
= This
->format
.spacing
;
5527 static const IDWriteTextFormat2Vtbl dwritetextformatvtbl
= {
5528 dwritetextformat_QueryInterface
,
5529 dwritetextformat_AddRef
,
5530 dwritetextformat_Release
,
5531 dwritetextformat_SetTextAlignment
,
5532 dwritetextformat_SetParagraphAlignment
,
5533 dwritetextformat_SetWordWrapping
,
5534 dwritetextformat_SetReadingDirection
,
5535 dwritetextformat_SetFlowDirection
,
5536 dwritetextformat_SetIncrementalTabStop
,
5537 dwritetextformat_SetTrimming
,
5538 dwritetextformat_SetLineSpacing
,
5539 dwritetextformat_GetTextAlignment
,
5540 dwritetextformat_GetParagraphAlignment
,
5541 dwritetextformat_GetWordWrapping
,
5542 dwritetextformat_GetReadingDirection
,
5543 dwritetextformat_GetFlowDirection
,
5544 dwritetextformat_GetIncrementalTabStop
,
5545 dwritetextformat_GetTrimming
,
5546 dwritetextformat_GetLineSpacing
,
5547 dwritetextformat_GetFontCollection
,
5548 dwritetextformat_GetFontFamilyNameLength
,
5549 dwritetextformat_GetFontFamilyName
,
5550 dwritetextformat_GetFontWeight
,
5551 dwritetextformat_GetFontStyle
,
5552 dwritetextformat_GetFontStretch
,
5553 dwritetextformat_GetFontSize
,
5554 dwritetextformat_GetLocaleNameLength
,
5555 dwritetextformat_GetLocaleName
,
5556 dwritetextformat1_SetVerticalGlyphOrientation
,
5557 dwritetextformat1_GetVerticalGlyphOrientation
,
5558 dwritetextformat1_SetLastLineWrapping
,
5559 dwritetextformat1_GetLastLineWrapping
,
5560 dwritetextformat1_SetOpticalAlignment
,
5561 dwritetextformat1_GetOpticalAlignment
,
5562 dwritetextformat1_SetFontFallback
,
5563 dwritetextformat1_GetFontFallback
,
5564 dwritetextformat2_SetLineSpacing
,
5565 dwritetextformat2_GetLineSpacing
5568 static struct dwrite_textformat
*unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat
*iface
)
5570 return (iface
->lpVtbl
== (IDWriteTextFormatVtbl
*)&dwritetextformatvtbl
) ?
5571 CONTAINING_RECORD(iface
, struct dwrite_textformat
, IDWriteTextFormat2_iface
) : NULL
;
5574 HRESULT
create_textformat(const WCHAR
*family_name
, IDWriteFontCollection
*collection
, DWRITE_FONT_WEIGHT weight
, DWRITE_FONT_STYLE style
,
5575 DWRITE_FONT_STRETCH stretch
, FLOAT size
, const WCHAR
*locale
, IDWriteTextFormat
**format
)
5577 struct dwrite_textformat
*This
;
5582 return E_INVALIDARG
;
5584 if (((UINT32
)weight
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
) ||
5585 ((UINT32
)stretch
> DWRITE_FONT_STRETCH_ULTRA_EXPANDED
) ||
5586 ((UINT32
)style
> DWRITE_FONT_STYLE_ITALIC
))
5587 return E_INVALIDARG
;
5589 This
= heap_alloc(sizeof(struct dwrite_textformat
));
5590 if (!This
) return E_OUTOFMEMORY
;
5592 This
->IDWriteTextFormat2_iface
.lpVtbl
= &dwritetextformatvtbl
;
5594 This
->format
.family_name
= heap_strdupW(family_name
);
5595 This
->format
.family_len
= strlenW(family_name
);
5596 This
->format
.locale
= heap_strdupW(locale
);
5597 This
->format
.locale_len
= strlenW(locale
);
5598 /* force locale name to lower case, layout will inherit this modified value */
5599 strlwrW(This
->format
.locale
);
5600 This
->format
.weight
= weight
;
5601 This
->format
.style
= style
;
5602 This
->format
.fontsize
= size
;
5603 This
->format
.stretch
= stretch
;
5604 This
->format
.textalignment
= DWRITE_TEXT_ALIGNMENT_LEADING
;
5605 This
->format
.optical_alignment
= DWRITE_OPTICAL_ALIGNMENT_NONE
;
5606 This
->format
.paralign
= DWRITE_PARAGRAPH_ALIGNMENT_NEAR
;
5607 This
->format
.wrapping
= DWRITE_WORD_WRAPPING_WRAP
;
5608 This
->format
.last_line_wrapping
= TRUE
;
5609 This
->format
.readingdir
= DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
;
5610 This
->format
.flow
= DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM
;
5611 This
->format
.spacing
.method
= DWRITE_LINE_SPACING_METHOD_DEFAULT
;
5612 This
->format
.spacing
.height
= 0.0f
;
5613 This
->format
.spacing
.baseline
= 0.0f
;
5614 This
->format
.spacing
.leadingBefore
= 0.0f
;
5615 This
->format
.spacing
.fontLineGapUsage
= DWRITE_FONT_LINE_GAP_USAGE_DEFAULT
;
5616 This
->format
.vertical_orientation
= DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
5617 This
->format
.trimming
.granularity
= DWRITE_TRIMMING_GRANULARITY_NONE
;
5618 This
->format
.trimming
.delimiter
= 0;
5619 This
->format
.trimming
.delimiterCount
= 0;
5620 This
->format
.trimmingsign
= NULL
;
5621 This
->format
.collection
= collection
;
5622 This
->format
.fallback
= NULL
;
5623 IDWriteFontCollection_AddRef(collection
);
5625 *format
= (IDWriteTextFormat
*)&This
->IDWriteTextFormat2_iface
;
5630 static HRESULT WINAPI
dwritetypography_QueryInterface(IDWriteTypography
*iface
, REFIID riid
, void **obj
)
5632 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5634 TRACE("(%p)->(%s %p)\n", typography
, debugstr_guid(riid
), obj
);
5636 if (IsEqualIID(riid
, &IID_IDWriteTypography
) || IsEqualIID(riid
, &IID_IUnknown
)) {
5638 IDWriteTypography_AddRef(iface
);
5642 WARN("%s not implemented.\n", debugstr_guid(riid
));
5646 return E_NOINTERFACE
;
5649 static ULONG WINAPI
dwritetypography_AddRef(IDWriteTypography
*iface
)
5651 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5652 ULONG ref
= InterlockedIncrement(&typography
->ref
);
5653 TRACE("(%p)->(%d)\n", typography
, ref
);
5657 static ULONG WINAPI
dwritetypography_Release(IDWriteTypography
*iface
)
5659 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5660 ULONG ref
= InterlockedDecrement(&typography
->ref
);
5662 TRACE("(%p)->(%d)\n", typography
, ref
);
5665 heap_free(typography
->features
);
5666 heap_free(typography
);
5672 static HRESULT WINAPI
dwritetypography_AddFontFeature(IDWriteTypography
*iface
, DWRITE_FONT_FEATURE feature
)
5674 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5676 TRACE("(%p)->(%x %u)\n", typography
, feature
.nameTag
, feature
.parameter
);
5678 if (typography
->count
== typography
->allocated
) {
5679 DWRITE_FONT_FEATURE
*ptr
= heap_realloc(typography
->features
, 2*typography
->allocated
*sizeof(DWRITE_FONT_FEATURE
));
5681 return E_OUTOFMEMORY
;
5683 typography
->features
= ptr
;
5684 typography
->allocated
*= 2;
5687 typography
->features
[typography
->count
++] = feature
;
5691 static UINT32 WINAPI
dwritetypography_GetFontFeatureCount(IDWriteTypography
*iface
)
5693 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5694 TRACE("(%p)\n", typography
);
5695 return typography
->count
;
5698 static HRESULT WINAPI
dwritetypography_GetFontFeature(IDWriteTypography
*iface
, UINT32 index
, DWRITE_FONT_FEATURE
*feature
)
5700 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5702 TRACE("(%p)->(%u %p)\n", typography
, index
, feature
);
5704 if (index
>= typography
->count
)
5705 return E_INVALIDARG
;
5707 *feature
= typography
->features
[index
];
5711 static const IDWriteTypographyVtbl dwritetypographyvtbl
= {
5712 dwritetypography_QueryInterface
,
5713 dwritetypography_AddRef
,
5714 dwritetypography_Release
,
5715 dwritetypography_AddFontFeature
,
5716 dwritetypography_GetFontFeatureCount
,
5717 dwritetypography_GetFontFeature
5720 HRESULT
create_typography(IDWriteTypography
**ret
)
5722 struct dwrite_typography
*typography
;
5726 typography
= heap_alloc(sizeof(*typography
));
5728 return E_OUTOFMEMORY
;
5730 typography
->IDWriteTypography_iface
.lpVtbl
= &dwritetypographyvtbl
;
5731 typography
->ref
= 1;
5732 typography
->allocated
= 2;
5733 typography
->count
= 0;
5735 typography
->features
= heap_alloc(typography
->allocated
*sizeof(DWRITE_FONT_FEATURE
));
5736 if (!typography
->features
) {
5737 heap_free(typography
);
5738 return E_OUTOFMEMORY
;
5741 *ret
= &typography
->IDWriteTypography_iface
;