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 HRESULT
layout_set_line_metrics(struct dwrite_textlayout
*layout
, DWRITE_LINE_METRICS1
*metrics
)
1363 UINT32 i
= layout
->metrics
.lineCount
;
1365 if (!layout
->line_alloc
) {
1366 layout
->line_alloc
= 5;
1367 layout
->linemetrics
= heap_alloc(layout
->line_alloc
* sizeof(*layout
->linemetrics
));
1368 layout
->lines
= heap_alloc(layout
->line_alloc
* sizeof(*layout
->lines
));
1369 if (!layout
->linemetrics
|| !layout
->lines
) {
1370 heap_free(layout
->linemetrics
);
1371 heap_free(layout
->lines
);
1372 layout
->linemetrics
= NULL
;
1373 layout
->lines
= NULL
;
1374 return E_OUTOFMEMORY
;
1378 if (layout
->metrics
.lineCount
== layout
->line_alloc
) {
1379 DWRITE_LINE_METRICS1
*metrics
;
1380 struct layout_line
*lines
;
1382 if ((metrics
= heap_realloc(layout
->linemetrics
, layout
->line_alloc
* 2 * sizeof(*layout
->linemetrics
))))
1383 layout
->linemetrics
= metrics
;
1384 if ((lines
= heap_realloc(layout
->lines
, layout
->line_alloc
* 2 * sizeof(*layout
->lines
))))
1385 layout
->lines
= lines
;
1387 if (!metrics
|| !lines
)
1388 return E_OUTOFMEMORY
;
1390 layout
->line_alloc
*= 2;
1393 layout
->linemetrics
[i
] = *metrics
;
1395 switch (layout
->format
.spacing
.method
)
1397 case DWRITE_LINE_SPACING_METHOD_UNIFORM
:
1398 if (layout
->format
.spacing
.method
== DWRITE_LINE_SPACING_METHOD_UNIFORM
) {
1399 layout
->linemetrics
[i
].height
= layout
->format
.spacing
.height
;
1400 layout
->linemetrics
[i
].baseline
= layout
->format
.spacing
.baseline
;
1403 case DWRITE_LINE_SPACING_METHOD_PROPORTIONAL
:
1404 if (layout
->format
.spacing
.method
== DWRITE_LINE_SPACING_METHOD_UNIFORM
) {
1405 layout
->linemetrics
[i
].height
= layout
->format
.spacing
.height
* metrics
->height
;
1406 layout
->linemetrics
[i
].baseline
= layout
->format
.spacing
.baseline
* metrics
->baseline
;
1410 /* using content values */;
1413 layout
->lines
[i
].height
= metrics
->height
;
1414 layout
->lines
[i
].baseline
= metrics
->baseline
;
1416 layout
->metrics
.lineCount
++;
1420 static inline struct layout_effective_run
*layout_get_next_erun(struct dwrite_textlayout
*layout
,
1421 const struct layout_effective_run
*cur
)
1426 e
= list_head(&layout
->eruns
);
1428 e
= list_next(&layout
->eruns
, &cur
->entry
);
1431 return LIST_ENTRY(e
, struct layout_effective_run
, entry
);
1434 static inline struct layout_effective_run
*layout_get_prev_erun(struct dwrite_textlayout
*layout
,
1435 const struct layout_effective_run
*cur
)
1440 e
= list_tail(&layout
->eruns
);
1442 e
= list_prev(&layout
->eruns
, &cur
->entry
);
1445 return LIST_ENTRY(e
, struct layout_effective_run
, entry
);
1448 static inline struct layout_effective_inline
*layout_get_next_inline_run(struct dwrite_textlayout
*layout
,
1449 const struct layout_effective_inline
*cur
)
1454 e
= list_head(&layout
->inlineobjects
);
1456 e
= list_next(&layout
->inlineobjects
, &cur
->entry
);
1459 return LIST_ENTRY(e
, struct layout_effective_inline
, entry
);
1462 static FLOAT
layout_get_line_width(struct dwrite_textlayout
*layout
,
1463 struct layout_effective_run
*erun
, struct layout_effective_inline
*inrun
, UINT32 line
)
1467 while (erun
&& erun
->line
== line
) {
1468 width
+= erun
->width
;
1469 erun
= layout_get_next_erun(layout
, erun
);
1474 while (inrun
&& inrun
->line
== line
) {
1475 width
+= inrun
->width
;
1476 inrun
= layout_get_next_inline_run(layout
, inrun
);
1484 static inline BOOL
should_skip_transform(const DWRITE_MATRIX
*m
, FLOAT
*det
)
1486 *det
= m
->m11
* m
->m22
- m
->m12
* m
->m21
;
1487 /* on certain conditions we can skip transform */
1488 return (!memcmp(m
, &identity
, sizeof(*m
)) || fabsf(*det
) <= 1e-10f
);
1491 static inline void layout_apply_snapping(D2D1_POINT_2F
*vec
, BOOL skiptransform
, FLOAT ppdip
,
1492 const DWRITE_MATRIX
*m
, FLOAT det
)
1494 if (!skiptransform
) {
1497 /* apply transform */
1501 vec2
.x
= m
->m11
* vec
->x
+ m
->m21
* vec
->y
+ m
->dx
;
1502 vec2
.y
= m
->m12
* vec
->x
+ m
->m22
* vec
->y
+ m
->dy
;
1505 vec2
.x
= floorf(vec2
.x
+ 0.5f
);
1506 vec2
.y
= floorf(vec2
.y
+ 0.5f
);
1508 /* apply inverted transform, we don't care about X component at this point */
1509 vec
->x
= (m
->m22
* vec2
.x
- m
->m21
* vec2
.y
+ m
->m21
* m
->dy
- m
->m22
* m
->dx
) / det
;
1512 vec
->y
= (-m
->m12
* vec2
.x
+ m
->m11
* vec2
.y
- (m
->m11
* m
->dy
- m
->m12
* m
->dx
)) / det
;
1516 vec
->x
= floorf(vec
->x
* ppdip
+ 0.5f
) / ppdip
;
1517 vec
->y
= floorf(vec
->y
* ppdip
+ 0.5f
) / ppdip
;
1521 static void layout_apply_leading_alignment(struct dwrite_textlayout
*layout
)
1523 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1524 struct layout_effective_inline
*inrun
;
1525 struct layout_effective_run
*erun
;
1527 erun
= layout_get_next_erun(layout
, NULL
);
1528 inrun
= layout_get_next_inline_run(layout
, NULL
);
1531 erun
->align_dx
= 0.0f
;
1532 erun
= layout_get_next_erun(layout
, erun
);
1536 inrun
->align_dx
= 0.0f
;
1537 inrun
= layout_get_next_inline_run(layout
, inrun
);
1540 layout
->metrics
.left
= is_rtl
? layout
->metrics
.layoutWidth
- layout
->metrics
.width
: 0.0f
;
1543 static void layout_apply_trailing_alignment(struct dwrite_textlayout
*layout
)
1545 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1546 struct layout_effective_inline
*inrun
;
1547 struct layout_effective_run
*erun
;
1550 erun
= layout_get_next_erun(layout
, NULL
);
1551 inrun
= layout_get_next_inline_run(layout
, NULL
);
1553 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1554 FLOAT width
= layout_get_line_width(layout
, erun
, inrun
, line
);
1555 FLOAT shift
= layout
->metrics
.layoutWidth
- width
;
1560 while (erun
&& erun
->line
== line
) {
1561 erun
->align_dx
= shift
;
1562 erun
= layout_get_next_erun(layout
, erun
);
1565 while (inrun
&& inrun
->line
== line
) {
1566 inrun
->align_dx
= shift
;
1567 inrun
= layout_get_next_inline_run(layout
, inrun
);
1571 layout
->metrics
.left
= is_rtl
? 0.0f
: layout
->metrics
.layoutWidth
- layout
->metrics
.width
;
1574 static inline FLOAT
layout_get_centered_shift(struct dwrite_textlayout
*layout
, BOOL skiptransform
,
1575 FLOAT width
, FLOAT det
)
1577 if (is_layout_gdi_compatible(layout
)) {
1578 D2D1_POINT_2F vec
= { layout
->metrics
.layoutWidth
- width
, 0.0f
};
1579 layout_apply_snapping(&vec
, skiptransform
, layout
->ppdip
, &layout
->transform
, det
);
1580 return floorf(vec
.x
/ 2.0f
);
1583 return (layout
->metrics
.layoutWidth
- width
) / 2.0f
;
1586 static void layout_apply_centered_alignment(struct dwrite_textlayout
*layout
)
1588 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1589 struct layout_effective_inline
*inrun
;
1590 struct layout_effective_run
*erun
;
1595 erun
= layout_get_next_erun(layout
, NULL
);
1596 inrun
= layout_get_next_inline_run(layout
, NULL
);
1598 skiptransform
= should_skip_transform(&layout
->transform
, &det
);
1600 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1601 FLOAT width
= layout_get_line_width(layout
, erun
, inrun
, line
);
1602 FLOAT shift
= layout_get_centered_shift(layout
, skiptransform
, width
, det
);
1607 while (erun
&& erun
->line
== line
) {
1608 erun
->align_dx
= shift
;
1609 erun
= layout_get_next_erun(layout
, erun
);
1612 while (inrun
&& inrun
->line
== line
) {
1613 inrun
->align_dx
= shift
;
1614 inrun
= layout_get_next_inline_run(layout
, inrun
);
1618 layout
->metrics
.left
= (layout
->metrics
.layoutWidth
- layout
->metrics
.width
) / 2.0f
;
1621 static void layout_apply_text_alignment(struct dwrite_textlayout
*layout
)
1623 switch (layout
->format
.textalignment
)
1625 case DWRITE_TEXT_ALIGNMENT_LEADING
:
1626 layout_apply_leading_alignment(layout
);
1628 case DWRITE_TEXT_ALIGNMENT_TRAILING
:
1629 layout_apply_trailing_alignment(layout
);
1631 case DWRITE_TEXT_ALIGNMENT_CENTER
:
1632 layout_apply_centered_alignment(layout
);
1634 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED
:
1635 FIXME("alignment %d not implemented\n", layout
->format
.textalignment
);
1642 static void layout_apply_par_alignment(struct dwrite_textlayout
*layout
)
1644 struct layout_effective_inline
*inrun
;
1645 struct layout_effective_run
*erun
;
1646 FLOAT origin_y
= 0.0f
;
1649 /* alignment mode defines origin, after that all run origins are updated
1652 switch (layout
->format
.paralign
)
1654 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR
:
1657 case DWRITE_PARAGRAPH_ALIGNMENT_FAR
:
1658 origin_y
= layout
->metrics
.layoutHeight
- layout
->metrics
.height
;
1660 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER
:
1661 origin_y
= (layout
->metrics
.layoutHeight
- layout
->metrics
.height
) / 2.0f
;
1667 layout
->metrics
.top
= origin_y
;
1669 erun
= layout_get_next_erun(layout
, NULL
);
1670 inrun
= layout_get_next_inline_run(layout
, NULL
);
1671 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1672 FLOAT pos_y
= origin_y
+ layout
->linemetrics
[line
].baseline
;
1674 while (erun
&& erun
->line
== line
) {
1675 erun
->origin
.y
= pos_y
;
1676 erun
= layout_get_next_erun(layout
, erun
);
1679 while (inrun
&& inrun
->line
== line
) {
1680 inrun
->origin
.y
= pos_y
- inrun
->baseline
;
1681 inrun
= layout_get_next_inline_run(layout
, inrun
);
1684 origin_y
+= layout
->linemetrics
[line
].height
;
1688 struct layout_underline_splitting_params
{
1689 const WCHAR
*locale
; /* points to range data, no additional allocation */
1690 IUnknown
*effect
; /* does not hold another reference */
1693 static void init_u_splitting_params_from_erun(struct layout_effective_run
*erun
,
1694 struct layout_underline_splitting_params
*params
)
1696 params
->locale
= erun
->run
->u
.regular
.descr
.localeName
;
1697 params
->effect
= erun
->effect
;
1700 static BOOL
is_same_u_splitting(struct layout_underline_splitting_params
*left
,
1701 struct layout_underline_splitting_params
*right
)
1703 return left
->effect
== right
->effect
&& !strcmpiW(left
->locale
, right
->locale
);
1706 static HRESULT
layout_add_underline(struct dwrite_textlayout
*layout
, struct layout_effective_run
*first
,
1707 struct layout_effective_run
*last
)
1709 FLOAT thickness
, offset
, runheight
;
1710 struct layout_effective_run
*cur
;
1711 DWRITE_FONT_METRICS metrics
;
1713 if (first
== layout_get_prev_erun(layout
, last
)) {
1714 layout_get_erun_font_metrics(layout
, first
, &metrics
);
1715 thickness
= SCALE_FONT_METRIC(metrics
.underlineThickness
, first
->run
->u
.regular
.run
.fontEmSize
, &metrics
);
1716 offset
= SCALE_FONT_METRIC(metrics
.underlinePosition
, first
->run
->u
.regular
.run
.fontEmSize
, &metrics
);
1717 runheight
= SCALE_FONT_METRIC(metrics
.capHeight
, first
->run
->u
.regular
.run
.fontEmSize
, &metrics
);
1722 /* Single underline is added for consecutive underlined runs. In this case underline parameters are
1723 calculated as weighted average, where run width acts as a weight. */
1724 thickness
= offset
= runheight
= 0.0f
;
1727 layout_get_erun_font_metrics(layout
, cur
, &metrics
);
1729 thickness
+= SCALE_FONT_METRIC(metrics
.underlineThickness
, cur
->run
->u
.regular
.run
.fontEmSize
, &metrics
) * cur
->width
;
1730 offset
+= SCALE_FONT_METRIC(metrics
.underlinePosition
, cur
->run
->u
.regular
.run
.fontEmSize
, &metrics
) * cur
->width
;
1731 runheight
= max(SCALE_FONT_METRIC(metrics
.capHeight
, cur
->run
->u
.regular
.run
.fontEmSize
, &metrics
), runheight
);
1732 width
+= cur
->width
;
1734 cur
= layout_get_next_erun(layout
, cur
);
1735 } while (cur
!= last
);
1743 struct layout_underline_splitting_params params
, prev_params
;
1744 struct layout_effective_run
*next
, *w
;
1745 struct layout_underline
*u
;
1747 init_u_splitting_params_from_erun(cur
, &prev_params
);
1748 while ((next
= layout_get_next_erun(layout
, cur
)) != last
) {
1749 init_u_splitting_params_from_erun(next
, ¶ms
);
1750 if (!is_same_u_splitting(&prev_params
, ¶ms
))
1755 u
= heap_alloc(sizeof(*u
));
1757 return E_OUTOFMEMORY
;
1762 u
->u
.width
+= w
->width
;
1763 w
= layout_get_next_erun(layout
, w
);
1766 u
->u
.thickness
= thickness
;
1767 /* Font metrics convention is to have it negative when below baseline, for rendering
1768 however Y grows from baseline down for horizontal baseline. */
1769 u
->u
.offset
= -offset
;
1770 u
->u
.runHeight
= runheight
;
1771 u
->u
.readingDirection
= is_run_rtl(cur
) ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
:
1772 DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
;
1773 u
->u
.flowDirection
= layout
->format
.flow
;
1774 u
->u
.localeName
= cur
->run
->u
.regular
.descr
.localeName
;
1775 u
->u
.measuringMode
= layout
->measuringmode
;
1777 list_add_tail(&layout
->underlines
, &u
->entry
);
1780 } while (cur
!= last
);
1785 /* Adds zero width line, metrics are derived from font at specified text position. */
1786 static HRESULT
layout_set_dummy_line_metrics(struct dwrite_textlayout
*layout
, UINT32 pos
)
1788 DWRITE_LINE_METRICS1 metrics
= { 0 };
1789 DWRITE_FONT_METRICS fontmetrics
;
1790 struct layout_range
*range
;
1791 IDWriteFontFace
*fontface
;
1795 range
= get_layout_range_by_pos(layout
, pos
);
1796 hr
= create_matching_font(range
->collection
,
1804 hr
= IDWriteFont_CreateFontFace(font
, &fontface
);
1805 IDWriteFont_Release(font
);
1809 layout_get_font_metrics(layout
, fontface
, range
->fontsize
, &fontmetrics
);
1810 layout_get_font_height(range
->fontsize
, &fontmetrics
, &metrics
.baseline
, &metrics
.height
);
1811 IDWriteFontFace_Release(fontface
);
1813 return layout_set_line_metrics(layout
, &metrics
);
1816 static void layout_add_line(struct dwrite_textlayout
*layout
, UINT32 first_cluster
, UINT32 last_cluster
,
1819 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1820 struct layout_final_splitting_params params
, prev_params
;
1821 DWRITE_INLINE_OBJECT_METRICS sign_metrics
= { 0 };
1822 UINT32 line
= layout
->metrics
.lineCount
, i
;
1823 DWRITE_LINE_METRICS1 metrics
= { 0 };
1824 UINT32 index
, start
, pos
= *textpos
;
1825 FLOAT descent
, trailingspacewidth
;
1826 BOOL append_trimming_run
= FALSE
;
1827 const struct layout_run
*run
;
1828 FLOAT width
, origin_x
;
1831 /* Take a look at clusters we got for this line in reverse order to set trailing properties for current line */
1832 for (index
= last_cluster
, trailingspacewidth
= 0.0f
; index
>= first_cluster
; index
--) {
1833 DWRITE_CLUSTER_METRICS
*cluster
= &layout
->clustermetrics
[index
];
1834 struct layout_cluster
*lc
= &layout
->clusters
[index
];
1837 /* This also filters out clusters added from inline objects, those are never
1838 treated as a white space. */
1839 if (!cluster
->isWhitespace
)
1842 /* Every isNewline cluster is also isWhitespace, but not every
1843 newline character cluster has isNewline set, so go back to original string. */
1844 ch
= lc
->run
->u
.regular
.descr
.string
[lc
->position
];
1845 if (cluster
->length
== 1 && lb_is_newline_char(ch
))
1846 metrics
.newlineLength
+= cluster
->length
;
1848 metrics
.trailingWhitespaceLength
+= cluster
->length
;
1849 trailingspacewidth
+= cluster
->width
;
1852 /* Line metrics length includes trailing whitespace length too */
1853 for (i
= first_cluster
; i
<= last_cluster
; i
++)
1854 metrics
.length
+= layout
->clustermetrics
[i
].length
;
1856 /* Ignore trailing whitespaces */
1857 while (last_cluster
> first_cluster
) {
1858 if (!layout
->clustermetrics
[last_cluster
].isWhitespace
)
1864 /* Does not include trailing space width */
1865 width
= get_cluster_range_width(layout
, first_cluster
, last_cluster
+ 1);
1867 /* Append trimming run if necessary */
1868 if (width
> layout
->metrics
.layoutWidth
&& layout
->format
.trimmingsign
!= NULL
&&
1869 layout
->format
.trimming
.granularity
!= DWRITE_TRIMMING_GRANULARITY_NONE
) {
1870 FLOAT trimmed_width
= width
;
1872 hr
= IDWriteInlineObject_GetMetrics(layout
->format
.trimmingsign
, &sign_metrics
);
1873 if (SUCCEEDED(hr
)) {
1874 while (last_cluster
> first_cluster
) {
1875 if (trimmed_width
+ sign_metrics
.width
<= layout
->metrics
.layoutWidth
)
1877 trimmed_width
-= layout
->clustermetrics
[last_cluster
--].width
;
1879 append_trimming_run
= TRUE
;
1882 WARN("Failed to get trimming sign metrics, lines won't be trimmed, hr %#x.\n", hr
);
1884 width
= trimmed_width
+ sign_metrics
.width
;
1887 layout_splitting_params_from_pos(layout
, pos
, ¶ms
);
1888 prev_params
= params
;
1889 run
= layout
->clusters
[first_cluster
].run
;
1891 /* Form runs from a range of clusters; this is what will be reported with DrawGlyphRun() */
1892 origin_x
= is_rtl
? layout
->metrics
.layoutWidth
: 0.0f
;
1893 for (start
= first_cluster
, i
= first_cluster
; i
<= last_cluster
; i
++) {
1894 layout_splitting_params_from_pos(layout
, pos
, ¶ms
);
1896 if (run
!= layout
->clusters
[i
].run
|| !is_same_splitting_params(&prev_params
, ¶ms
)) {
1897 hr
= layout_add_effective_run(layout
, run
, start
, i
- start
, line
, origin_x
, &prev_params
);
1901 origin_x
+= is_rtl
? -get_cluster_range_width(layout
, start
, i
) :
1902 get_cluster_range_width(layout
, start
, i
);
1903 run
= layout
->clusters
[i
].run
;
1907 prev_params
= params
;
1908 pos
+= layout
->clustermetrics
[i
].length
;
1911 /* Final run from what's left from cluster range */
1912 hr
= layout_add_effective_run(layout
, run
, start
, i
- start
, line
, origin_x
, &prev_params
);
1916 if (append_trimming_run
) {
1917 struct layout_effective_inline
*trimming_sign
;
1919 trimming_sign
= heap_alloc(sizeof(*trimming_sign
));
1923 trimming_sign
->object
= layout
->format
.trimmingsign
;
1924 trimming_sign
->width
= sign_metrics
.width
;
1925 origin_x
+= is_rtl
? -get_cluster_range_width(layout
, start
, i
) : get_cluster_range_width(layout
, start
, i
);
1926 trimming_sign
->origin
.x
= is_rtl
? origin_x
- trimming_sign
->width
: origin_x
;
1927 trimming_sign
->origin
.y
= 0.0f
; /* set after line is built */
1928 trimming_sign
->align_dx
= 0.0f
;
1929 trimming_sign
->baseline
= sign_metrics
.baseline
;
1931 trimming_sign
->is_sideways
= FALSE
;
1932 trimming_sign
->is_rtl
= FALSE
;
1933 trimming_sign
->line
= line
;
1935 trimming_sign
->effect
= layout_get_effect_from_pos(layout
, layout
->clusters
[i
].position
+
1936 layout
->clusters
[i
].run
->start_position
);
1938 list_add_tail(&layout
->inlineobjects
, &trimming_sign
->entry
);
1941 /* Look for max baseline and descent for this line */
1942 for (index
= first_cluster
, metrics
.baseline
= 0.0f
, descent
= 0.0f
; index
<= last_cluster
; index
++) {
1943 const struct layout_run
*cur
= layout
->clusters
[index
].run
;
1944 FLOAT cur_descent
= cur
->height
- cur
->baseline
;
1946 if (cur
->baseline
> metrics
.baseline
)
1947 metrics
.baseline
= cur
->baseline
;
1948 if (cur_descent
> descent
)
1949 descent
= cur_descent
;
1952 layout
->metrics
.width
= max(width
, layout
->metrics
.width
);
1953 layout
->metrics
.widthIncludingTrailingWhitespace
= max(width
+ trailingspacewidth
,
1954 layout
->metrics
.widthIncludingTrailingWhitespace
);
1956 metrics
.height
= descent
+ metrics
.baseline
;
1957 metrics
.isTrimmed
= append_trimming_run
|| width
> layout
->metrics
.layoutWidth
;
1958 layout_set_line_metrics(layout
, &metrics
);
1960 *textpos
+= metrics
.length
;
1963 static void layout_set_line_positions(struct dwrite_textlayout
*layout
)
1965 struct layout_effective_inline
*inrun
;
1966 struct layout_effective_run
*erun
;
1970 /* Now all line info is here, update effective runs positions in flow direction */
1971 erun
= layout_get_next_erun(layout
, NULL
);
1972 inrun
= layout_get_next_inline_run(layout
, NULL
);
1974 for (line
= 0, origin_y
= 0.0f
; line
< layout
->metrics
.lineCount
; line
++) {
1975 FLOAT pos_y
= origin_y
+ layout
->linemetrics
[line
].baseline
;
1977 /* For all runs on this line */
1978 while (erun
&& erun
->line
== line
) {
1979 erun
->origin
.y
= pos_y
;
1980 erun
= layout_get_next_erun(layout
, erun
);
1983 /* Same for inline runs */
1984 while (inrun
&& inrun
->line
== line
) {
1985 inrun
->origin
.y
= pos_y
- inrun
->baseline
;
1986 inrun
= layout_get_next_inline_run(layout
, inrun
);
1989 origin_y
+= layout
->linemetrics
[line
].height
;
1992 layout
->metrics
.height
= origin_y
;
1994 /* Initial paragraph alignment is always near */
1995 if (layout
->format
.paralign
!= DWRITE_PARAGRAPH_ALIGNMENT_NEAR
)
1996 layout_apply_par_alignment(layout
);
1999 static BOOL
layout_can_wrap_after(const struct dwrite_textlayout
*layout
, UINT32 cluster
)
2001 if (layout
->format
.wrapping
== DWRITE_WORD_WRAPPING_CHARACTER
)
2004 return layout
->clustermetrics
[cluster
].canWrapLineAfter
;
2007 static HRESULT
layout_compute_effective_runs(struct dwrite_textlayout
*layout
)
2009 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
2010 struct layout_effective_run
*erun
, *first_underlined
;
2011 UINT32 i
, start
, textpos
, last_breaking_point
;
2012 DWRITE_LINE_METRICS1 metrics
;
2017 if (!(layout
->recompute
& RECOMPUTE_LINES
))
2020 free_layout_eruns(layout
);
2022 hr
= layout_compute(layout
);
2026 layout
->metrics
.lineCount
= 0;
2027 memset(&metrics
, 0, sizeof(metrics
));
2029 layout
->metrics
.height
= 0.0f
;
2030 layout
->metrics
.width
= 0.0f
;
2031 layout
->metrics
.widthIncludingTrailingWhitespace
= 0.0f
;
2033 last_breaking_point
= ~0u;
2035 for (i
= 0, start
= 0, width
= 0.0f
, textpos
= 0; i
< layout
->cluster_count
; i
++) {
2036 BOOL overflow
= FALSE
;
2038 while (i
< layout
->cluster_count
&& !layout
->clustermetrics
[i
].isNewline
) {
2039 /* Check for overflow */
2040 overflow
= ((width
+ layout
->clustermetrics
[i
].width
> layout
->metrics
.layoutWidth
) &&
2041 (layout
->format
.wrapping
!= DWRITE_WORD_WRAPPING_NO_WRAP
));
2045 if (layout_can_wrap_after(layout
, i
))
2046 last_breaking_point
= i
;
2047 width
+= layout
->clustermetrics
[i
].width
;
2050 i
= min(i
, layout
->cluster_count
- 1);
2052 /* Ignore if overflown on whitespace */
2053 if (overflow
&& !(layout
->clustermetrics
[i
].isWhitespace
&& layout_can_wrap_after(layout
, i
))) {
2054 /* Use most recently found breaking point */
2055 if (last_breaking_point
!= ~0u) {
2056 i
= last_breaking_point
;
2057 last_breaking_point
= ~0u;
2060 /* Otherwise proceed forward to next newline or breaking point */
2061 for (; i
< layout
->cluster_count
; i
++)
2062 if (layout_can_wrap_after(layout
, i
) || layout
->clustermetrics
[i
].isNewline
)
2066 i
= min(i
, layout
->cluster_count
- 1);
2068 layout_add_line(layout
, start
, i
, &textpos
);
2073 /* Add dummy line if:
2074 - there's no text, metrics come from first range in this case;
2075 - last ended with a mandatory break, metrics come from last text position.
2077 if (layout
->len
== 0)
2078 hr
= layout_set_dummy_line_metrics(layout
, 0);
2079 else if (layout
->clustermetrics
[layout
->cluster_count
- 1].isNewline
)
2080 hr
= layout_set_dummy_line_metrics(layout
, layout
->len
- 1);
2084 layout
->metrics
.left
= is_rtl
? layout
->metrics
.layoutWidth
- layout
->metrics
.width
: 0.0f
;
2085 layout
->metrics
.top
= 0.0f
;
2086 layout
->metrics
.maxBidiReorderingDepth
= 1; /* FIXME */
2088 /* Add explicit underlined runs */
2089 erun
= layout_get_next_erun(layout
, NULL
);
2090 first_underlined
= erun
&& erun
->underlined
? erun
: NULL
;
2091 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
2092 while (erun
&& erun
->line
== line
) {
2093 erun
= layout_get_next_erun(layout
, erun
);
2095 if (first_underlined
&& (!erun
|| !erun
->underlined
)) {
2096 layout_add_underline(layout
, first_underlined
, erun
);
2097 first_underlined
= NULL
;
2099 else if (!first_underlined
&& erun
&& erun
->underlined
)
2100 first_underlined
= erun
;
2104 /* Position runs in flow direction */
2105 layout_set_line_positions(layout
);
2107 /* Initial alignment is always leading */
2108 if (layout
->format
.textalignment
!= DWRITE_TEXT_ALIGNMENT_LEADING
)
2109 layout_apply_text_alignment(layout
);
2111 layout
->recompute
&= ~RECOMPUTE_LINES
;
2115 static BOOL
is_same_layout_attrvalue(struct layout_range_header
const *h
, enum layout_range_attr_kind attr
,
2116 struct layout_range_attr_value
*value
)
2118 struct layout_range_spacing
const *range_spacing
= (struct layout_range_spacing
*)h
;
2119 struct layout_range_iface
const *range_iface
= (struct layout_range_iface
*)h
;
2120 struct layout_range_bool
const *range_bool
= (struct layout_range_bool
*)h
;
2121 struct layout_range
const *range
= (struct layout_range
*)h
;
2124 case LAYOUT_RANGE_ATTR_WEIGHT
:
2125 return range
->weight
== value
->u
.weight
;
2126 case LAYOUT_RANGE_ATTR_STYLE
:
2127 return range
->style
== value
->u
.style
;
2128 case LAYOUT_RANGE_ATTR_STRETCH
:
2129 return range
->stretch
== value
->u
.stretch
;
2130 case LAYOUT_RANGE_ATTR_FONTSIZE
:
2131 return range
->fontsize
== value
->u
.fontsize
;
2132 case LAYOUT_RANGE_ATTR_INLINE
:
2133 return range
->object
== value
->u
.object
;
2134 case LAYOUT_RANGE_ATTR_EFFECT
:
2135 return range_iface
->iface
== value
->u
.effect
;
2136 case LAYOUT_RANGE_ATTR_UNDERLINE
:
2137 return range_bool
->value
== value
->u
.underline
;
2138 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
2139 return range_bool
->value
== value
->u
.strikethrough
;
2140 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
2141 return range
->pair_kerning
== value
->u
.pair_kerning
;
2142 case LAYOUT_RANGE_ATTR_FONTCOLL
:
2143 return range
->collection
== value
->u
.collection
;
2144 case LAYOUT_RANGE_ATTR_LOCALE
:
2145 return strcmpiW(range
->locale
, value
->u
.locale
) == 0;
2146 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2147 return strcmpW(range
->fontfamily
, value
->u
.fontfamily
) == 0;
2148 case LAYOUT_RANGE_ATTR_SPACING
:
2149 return range_spacing
->leading
== value
->u
.spacing
.leading
&&
2150 range_spacing
->trailing
== value
->u
.spacing
.trailing
&&
2151 range_spacing
->min_advance
== value
->u
.spacing
.min_advance
;
2152 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
2153 return range_iface
->iface
== (IUnknown
*)value
->u
.typography
;
2161 static inline BOOL
is_same_layout_attributes(struct layout_range_header
const *hleft
, struct layout_range_header
const *hright
)
2163 switch (hleft
->kind
)
2165 case LAYOUT_RANGE_REGULAR
:
2167 struct layout_range
const *left
= (struct layout_range
const*)hleft
;
2168 struct layout_range
const *right
= (struct layout_range
const*)hright
;
2169 return left
->weight
== right
->weight
&&
2170 left
->style
== right
->style
&&
2171 left
->stretch
== right
->stretch
&&
2172 left
->fontsize
== right
->fontsize
&&
2173 left
->object
== right
->object
&&
2174 left
->pair_kerning
== right
->pair_kerning
&&
2175 left
->collection
== right
->collection
&&
2176 !strcmpiW(left
->locale
, right
->locale
) &&
2177 !strcmpW(left
->fontfamily
, right
->fontfamily
);
2179 case LAYOUT_RANGE_UNDERLINE
:
2180 case LAYOUT_RANGE_STRIKETHROUGH
:
2182 struct layout_range_bool
const *left
= (struct layout_range_bool
const*)hleft
;
2183 struct layout_range_bool
const *right
= (struct layout_range_bool
const*)hright
;
2184 return left
->value
== right
->value
;
2186 case LAYOUT_RANGE_EFFECT
:
2187 case LAYOUT_RANGE_TYPOGRAPHY
:
2189 struct layout_range_iface
const *left
= (struct layout_range_iface
const*)hleft
;
2190 struct layout_range_iface
const *right
= (struct layout_range_iface
const*)hright
;
2191 return left
->iface
== right
->iface
;
2193 case LAYOUT_RANGE_SPACING
:
2195 struct layout_range_spacing
const *left
= (struct layout_range_spacing
const*)hleft
;
2196 struct layout_range_spacing
const *right
= (struct layout_range_spacing
const*)hright
;
2197 return left
->leading
== right
->leading
&&
2198 left
->trailing
== right
->trailing
&&
2199 left
->min_advance
== right
->min_advance
;
2202 FIXME("unknown range kind %d\n", hleft
->kind
);
2207 static inline BOOL
is_same_text_range(const DWRITE_TEXT_RANGE
*left
, const DWRITE_TEXT_RANGE
*right
)
2209 return left
->startPosition
== right
->startPosition
&& left
->length
== right
->length
;
2212 /* Allocates range and inits it with default values from text format. */
2213 static struct layout_range_header
*alloc_layout_range(struct dwrite_textlayout
*layout
, const DWRITE_TEXT_RANGE
*r
,
2214 enum layout_range_kind kind
)
2216 struct layout_range_header
*h
;
2220 case LAYOUT_RANGE_REGULAR
:
2222 struct layout_range
*range
;
2224 range
= heap_alloc(sizeof(*range
));
2225 if (!range
) return NULL
;
2227 range
->weight
= layout
->format
.weight
;
2228 range
->style
= layout
->format
.style
;
2229 range
->stretch
= layout
->format
.stretch
;
2230 range
->fontsize
= layout
->format
.fontsize
;
2231 range
->object
= NULL
;
2232 range
->pair_kerning
= FALSE
;
2234 range
->fontfamily
= heap_strdupW(layout
->format
.family_name
);
2235 if (!range
->fontfamily
) {
2240 range
->collection
= layout
->format
.collection
;
2241 if (range
->collection
)
2242 IDWriteFontCollection_AddRef(range
->collection
);
2243 strcpyW(range
->locale
, layout
->format
.locale
);
2248 case LAYOUT_RANGE_UNDERLINE
:
2249 case LAYOUT_RANGE_STRIKETHROUGH
:
2251 struct layout_range_bool
*range
;
2253 range
= heap_alloc(sizeof(*range
));
2254 if (!range
) return NULL
;
2256 range
->value
= FALSE
;
2260 case LAYOUT_RANGE_EFFECT
:
2261 case LAYOUT_RANGE_TYPOGRAPHY
:
2263 struct layout_range_iface
*range
;
2265 range
= heap_alloc(sizeof(*range
));
2266 if (!range
) return NULL
;
2268 range
->iface
= NULL
;
2272 case LAYOUT_RANGE_SPACING
:
2274 struct layout_range_spacing
*range
;
2276 range
= heap_alloc(sizeof(*range
));
2277 if (!range
) return NULL
;
2279 range
->leading
= 0.0f
;
2280 range
->trailing
= 0.0f
;
2281 range
->min_advance
= 0.0f
;
2286 FIXME("unknown range kind %d\n", kind
);
2295 static struct layout_range_header
*alloc_layout_range_from(struct layout_range_header
*h
, const DWRITE_TEXT_RANGE
*r
)
2297 struct layout_range_header
*ret
;
2301 case LAYOUT_RANGE_REGULAR
:
2303 struct layout_range
*from
= (struct layout_range
*)h
;
2305 struct layout_range
*range
= heap_alloc(sizeof(*range
));
2306 if (!range
) return NULL
;
2309 range
->fontfamily
= heap_strdupW(from
->fontfamily
);
2310 if (!range
->fontfamily
) {
2315 /* update refcounts */
2317 IDWriteInlineObject_AddRef(range
->object
);
2318 if (range
->collection
)
2319 IDWriteFontCollection_AddRef(range
->collection
);
2323 case LAYOUT_RANGE_UNDERLINE
:
2324 case LAYOUT_RANGE_STRIKETHROUGH
:
2326 struct layout_range_bool
*strike
= heap_alloc(sizeof(*strike
));
2327 if (!strike
) return NULL
;
2329 *strike
= *(struct layout_range_bool
*)h
;
2333 case LAYOUT_RANGE_EFFECT
:
2334 case LAYOUT_RANGE_TYPOGRAPHY
:
2336 struct layout_range_iface
*effect
= heap_alloc(sizeof(*effect
));
2337 if (!effect
) return NULL
;
2339 *effect
= *(struct layout_range_iface
*)h
;
2341 IUnknown_AddRef(effect
->iface
);
2345 case LAYOUT_RANGE_SPACING
:
2347 struct layout_range_spacing
*spacing
= heap_alloc(sizeof(*spacing
));
2348 if (!spacing
) return NULL
;
2350 *spacing
= *(struct layout_range_spacing
*)h
;
2355 FIXME("unknown range kind %d\n", h
->kind
);
2363 static void free_layout_range(struct layout_range_header
*h
)
2370 case LAYOUT_RANGE_REGULAR
:
2372 struct layout_range
*range
= (struct layout_range
*)h
;
2375 IDWriteInlineObject_Release(range
->object
);
2376 if (range
->collection
)
2377 IDWriteFontCollection_Release(range
->collection
);
2378 heap_free(range
->fontfamily
);
2381 case LAYOUT_RANGE_EFFECT
:
2382 case LAYOUT_RANGE_TYPOGRAPHY
:
2384 struct layout_range_iface
*range
= (struct layout_range_iface
*)h
;
2386 IUnknown_Release(range
->iface
);
2396 static void free_layout_ranges_list(struct dwrite_textlayout
*layout
)
2398 struct layout_range_header
*cur
, *cur2
;
2400 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->ranges
, struct layout_range_header
, entry
) {
2401 list_remove(&cur
->entry
);
2402 free_layout_range(cur
);
2405 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->underline_ranges
, struct layout_range_header
, entry
) {
2406 list_remove(&cur
->entry
);
2407 free_layout_range(cur
);
2410 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->strike_ranges
, struct layout_range_header
, entry
) {
2411 list_remove(&cur
->entry
);
2412 free_layout_range(cur
);
2415 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->effects
, struct layout_range_header
, entry
) {
2416 list_remove(&cur
->entry
);
2417 free_layout_range(cur
);
2420 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->spacing
, struct layout_range_header
, entry
) {
2421 list_remove(&cur
->entry
);
2422 free_layout_range(cur
);
2425 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->typographies
, struct layout_range_header
, entry
) {
2426 list_remove(&cur
->entry
);
2427 free_layout_range(cur
);
2431 static struct layout_range_header
*find_outer_range(struct list
*ranges
, const DWRITE_TEXT_RANGE
*range
)
2433 struct layout_range_header
*cur
;
2435 LIST_FOR_EACH_ENTRY(cur
, ranges
, struct layout_range_header
, entry
) {
2437 if (cur
->range
.startPosition
> range
->startPosition
)
2440 if ((cur
->range
.startPosition
+ cur
->range
.length
< range
->startPosition
+ range
->length
) &&
2441 (range
->startPosition
< cur
->range
.startPosition
+ cur
->range
.length
))
2443 if (cur
->range
.startPosition
+ cur
->range
.length
>= range
->startPosition
+ range
->length
)
2450 static struct layout_range
*get_layout_range_by_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
2452 struct layout_range
*cur
;
2454 LIST_FOR_EACH_ENTRY(cur
, &layout
->ranges
, struct layout_range
, h
.entry
) {
2455 DWRITE_TEXT_RANGE
*r
= &cur
->h
.range
;
2456 if (r
->startPosition
<= pos
&& pos
< r
->startPosition
+ r
->length
)
2463 static inline BOOL
set_layout_range_iface_attr(IUnknown
**dest
, IUnknown
*value
)
2465 if (*dest
== value
) return FALSE
;
2468 IUnknown_Release(*dest
);
2471 IUnknown_AddRef(*dest
);
2476 static BOOL
set_layout_range_attrval(struct layout_range_header
*h
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
2478 struct layout_range_spacing
*dest_spacing
= (struct layout_range_spacing
*)h
;
2479 struct layout_range_iface
*dest_iface
= (struct layout_range_iface
*)h
;
2480 struct layout_range_bool
*dest_bool
= (struct layout_range_bool
*)h
;
2481 struct layout_range
*dest
= (struct layout_range
*)h
;
2483 BOOL changed
= FALSE
;
2486 case LAYOUT_RANGE_ATTR_WEIGHT
:
2487 changed
= dest
->weight
!= value
->u
.weight
;
2488 dest
->weight
= value
->u
.weight
;
2490 case LAYOUT_RANGE_ATTR_STYLE
:
2491 changed
= dest
->style
!= value
->u
.style
;
2492 dest
->style
= value
->u
.style
;
2494 case LAYOUT_RANGE_ATTR_STRETCH
:
2495 changed
= dest
->stretch
!= value
->u
.stretch
;
2496 dest
->stretch
= value
->u
.stretch
;
2498 case LAYOUT_RANGE_ATTR_FONTSIZE
:
2499 changed
= dest
->fontsize
!= value
->u
.fontsize
;
2500 dest
->fontsize
= value
->u
.fontsize
;
2502 case LAYOUT_RANGE_ATTR_INLINE
:
2503 changed
= set_layout_range_iface_attr((IUnknown
**)&dest
->object
, (IUnknown
*)value
->u
.object
);
2505 case LAYOUT_RANGE_ATTR_EFFECT
:
2506 changed
= set_layout_range_iface_attr((IUnknown
**)&dest_iface
->iface
, (IUnknown
*)value
->u
.effect
);
2508 case LAYOUT_RANGE_ATTR_UNDERLINE
:
2509 changed
= dest_bool
->value
!= value
->u
.underline
;
2510 dest_bool
->value
= value
->u
.underline
;
2512 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
2513 changed
= dest_bool
->value
!= value
->u
.strikethrough
;
2514 dest_bool
->value
= value
->u
.strikethrough
;
2516 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
2517 changed
= dest
->pair_kerning
!= value
->u
.pair_kerning
;
2518 dest
->pair_kerning
= value
->u
.pair_kerning
;
2520 case LAYOUT_RANGE_ATTR_FONTCOLL
:
2521 changed
= set_layout_range_iface_attr((IUnknown
**)&dest
->collection
, (IUnknown
*)value
->u
.collection
);
2523 case LAYOUT_RANGE_ATTR_LOCALE
:
2524 changed
= strcmpiW(dest
->locale
, value
->u
.locale
) != 0;
2526 strcpyW(dest
->locale
, value
->u
.locale
);
2527 strlwrW(dest
->locale
);
2530 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2531 changed
= strcmpW(dest
->fontfamily
, value
->u
.fontfamily
) != 0;
2533 heap_free(dest
->fontfamily
);
2534 dest
->fontfamily
= heap_strdupW(value
->u
.fontfamily
);
2537 case LAYOUT_RANGE_ATTR_SPACING
:
2538 changed
= dest_spacing
->leading
!= value
->u
.spacing
.leading
||
2539 dest_spacing
->trailing
!= value
->u
.spacing
.trailing
||
2540 dest_spacing
->min_advance
!= value
->u
.spacing
.min_advance
;
2541 dest_spacing
->leading
= value
->u
.spacing
.leading
;
2542 dest_spacing
->trailing
= value
->u
.spacing
.trailing
;
2543 dest_spacing
->min_advance
= value
->u
.spacing
.min_advance
;
2545 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
2546 changed
= set_layout_range_iface_attr((IUnknown
**)&dest_iface
->iface
, (IUnknown
*)value
->u
.typography
);
2555 static inline BOOL
is_in_layout_range(const DWRITE_TEXT_RANGE
*outer
, const DWRITE_TEXT_RANGE
*inner
)
2557 return (inner
->startPosition
>= outer
->startPosition
) &&
2558 (inner
->startPosition
+ inner
->length
<= outer
->startPosition
+ outer
->length
);
2561 static inline HRESULT
return_range(const struct layout_range_header
*h
, DWRITE_TEXT_RANGE
*r
)
2563 if (r
) *r
= h
->range
;
2567 /* Sets attribute value for given range, does all needed splitting/merging of existing ranges. */
2568 static HRESULT
set_layout_range_attr(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
2570 struct layout_range_header
*cur
, *right
, *left
, *outer
;
2571 BOOL changed
= FALSE
;
2572 struct list
*ranges
;
2573 DWRITE_TEXT_RANGE r
;
2575 /* ignore zero length ranges */
2576 if (value
->range
.length
== 0)
2579 /* select from ranges lists */
2582 case LAYOUT_RANGE_ATTR_WEIGHT
:
2583 case LAYOUT_RANGE_ATTR_STYLE
:
2584 case LAYOUT_RANGE_ATTR_STRETCH
:
2585 case LAYOUT_RANGE_ATTR_FONTSIZE
:
2586 case LAYOUT_RANGE_ATTR_INLINE
:
2587 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
2588 case LAYOUT_RANGE_ATTR_FONTCOLL
:
2589 case LAYOUT_RANGE_ATTR_LOCALE
:
2590 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2591 ranges
= &layout
->ranges
;
2593 case LAYOUT_RANGE_ATTR_UNDERLINE
:
2594 ranges
= &layout
->underline_ranges
;
2596 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
2597 ranges
= &layout
->strike_ranges
;
2599 case LAYOUT_RANGE_ATTR_EFFECT
:
2600 ranges
= &layout
->effects
;
2602 case LAYOUT_RANGE_ATTR_SPACING
:
2603 ranges
= &layout
->spacing
;
2605 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
2606 ranges
= &layout
->typographies
;
2609 FIXME("unknown attr kind %d\n", attr
);
2613 /* If new range is completely within existing range, split existing range in two */
2614 if ((outer
= find_outer_range(ranges
, &value
->range
))) {
2616 /* no need to add same range */
2617 if (is_same_layout_attrvalue(outer
, attr
, value
))
2620 /* for matching range bounds just replace data */
2621 if (is_same_text_range(&outer
->range
, &value
->range
)) {
2622 changed
= set_layout_range_attrval(outer
, attr
, value
);
2626 /* add new range to the left */
2627 if (value
->range
.startPosition
== outer
->range
.startPosition
) {
2628 left
= alloc_layout_range_from(outer
, &value
->range
);
2629 if (!left
) return E_OUTOFMEMORY
;
2631 changed
= set_layout_range_attrval(left
, attr
, value
);
2632 list_add_before(&outer
->entry
, &left
->entry
);
2633 outer
->range
.startPosition
+= value
->range
.length
;
2634 outer
->range
.length
-= value
->range
.length
;
2638 /* add new range to the right */
2639 if (value
->range
.startPosition
+ value
->range
.length
== outer
->range
.startPosition
+ outer
->range
.length
) {
2640 right
= alloc_layout_range_from(outer
, &value
->range
);
2641 if (!right
) return E_OUTOFMEMORY
;
2643 changed
= set_layout_range_attrval(right
, attr
, value
);
2644 list_add_after(&outer
->entry
, &right
->entry
);
2645 outer
->range
.length
-= value
->range
.length
;
2649 r
.startPosition
= value
->range
.startPosition
+ value
->range
.length
;
2650 r
.length
= outer
->range
.length
+ outer
->range
.startPosition
- r
.startPosition
;
2653 right
= alloc_layout_range_from(outer
, &r
);
2654 /* new range in the middle */
2655 cur
= alloc_layout_range_from(outer
, &value
->range
);
2656 if (!right
|| !cur
) {
2657 free_layout_range(right
);
2658 free_layout_range(cur
);
2659 return E_OUTOFMEMORY
;
2662 /* reuse container range as a left part */
2663 outer
->range
.length
= value
->range
.startPosition
- outer
->range
.startPosition
;
2666 set_layout_range_attrval(cur
, attr
, value
);
2668 list_add_after(&outer
->entry
, &cur
->entry
);
2669 list_add_after(&cur
->entry
, &right
->entry
);
2671 layout
->recompute
= RECOMPUTE_EVERYTHING
;
2675 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2676 Update all of them. */
2677 left
= get_layout_range_header_by_pos(ranges
, value
->range
.startPosition
);
2678 if (left
->range
.startPosition
== value
->range
.startPosition
)
2679 changed
= set_layout_range_attrval(left
, attr
, value
);
2680 else /* need to split */ {
2681 r
.startPosition
= value
->range
.startPosition
;
2682 r
.length
= left
->range
.length
- value
->range
.startPosition
+ left
->range
.startPosition
;
2683 left
->range
.length
-= r
.length
;
2684 cur
= alloc_layout_range_from(left
, &r
);
2685 changed
= set_layout_range_attrval(cur
, attr
, value
);
2686 list_add_after(&left
->entry
, &cur
->entry
);
2688 cur
= LIST_ENTRY(list_next(ranges
, &left
->entry
), struct layout_range_header
, entry
);
2690 /* for all existing ranges covered by new one update value */
2691 while (cur
&& is_in_layout_range(&value
->range
, &cur
->range
)) {
2692 changed
|= set_layout_range_attrval(cur
, attr
, value
);
2693 cur
= LIST_ENTRY(list_next(ranges
, &cur
->entry
), struct layout_range_header
, entry
);
2696 /* it's possible rightmost range intersects */
2697 if (cur
&& (cur
->range
.startPosition
< value
->range
.startPosition
+ value
->range
.length
)) {
2698 r
.startPosition
= cur
->range
.startPosition
;
2699 r
.length
= value
->range
.startPosition
+ value
->range
.length
- cur
->range
.startPosition
;
2700 left
= alloc_layout_range_from(cur
, &r
);
2701 changed
|= set_layout_range_attrval(left
, attr
, value
);
2702 cur
->range
.startPosition
+= left
->range
.length
;
2703 cur
->range
.length
-= left
->range
.length
;
2704 list_add_before(&cur
->entry
, &left
->entry
);
2709 struct list
*next
, *i
;
2711 layout
->recompute
= RECOMPUTE_EVERYTHING
;
2712 i
= list_head(ranges
);
2713 while ((next
= list_next(ranges
, i
))) {
2714 struct layout_range_header
*next_range
= LIST_ENTRY(next
, struct layout_range_header
, entry
);
2716 cur
= LIST_ENTRY(i
, struct layout_range_header
, entry
);
2717 if (is_same_layout_attributes(cur
, next_range
)) {
2718 /* remove similar range */
2719 cur
->range
.length
+= next_range
->range
.length
;
2721 free_layout_range(next_range
);
2724 i
= list_next(ranges
, i
);
2731 static inline const WCHAR
*get_string_attribute_ptr(struct layout_range
*range
, enum layout_range_attr_kind kind
)
2736 case LAYOUT_RANGE_ATTR_LOCALE
:
2737 str
= range
->locale
;
2739 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2740 str
= range
->fontfamily
;
2749 static HRESULT
get_string_attribute_length(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind kind
, UINT32 position
,
2750 UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
2752 struct layout_range
*range
;
2755 range
= get_layout_range_by_pos(layout
, position
);
2761 str
= get_string_attribute_ptr(range
, kind
);
2762 *length
= strlenW(str
);
2763 return return_range(&range
->h
, r
);
2766 static HRESULT
get_string_attribute_value(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind kind
, UINT32 position
,
2767 WCHAR
*ret
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
2769 struct layout_range
*range
;
2773 return E_INVALIDARG
;
2776 range
= get_layout_range_by_pos(layout
, position
);
2778 return E_INVALIDARG
;
2780 str
= get_string_attribute_ptr(range
, kind
);
2781 if (length
< strlenW(str
) + 1)
2782 return E_NOT_SUFFICIENT_BUFFER
;
2785 return return_range(&range
->h
, r
);
2788 static HRESULT WINAPI
dwritetextlayout_QueryInterface(IDWriteTextLayout3
*iface
, REFIID riid
, void **obj
)
2790 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2792 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
2796 if (IsEqualIID(riid
, &IID_IDWriteTextLayout3
) ||
2797 IsEqualIID(riid
, &IID_IDWriteTextLayout2
) ||
2798 IsEqualIID(riid
, &IID_IDWriteTextLayout1
) ||
2799 IsEqualIID(riid
, &IID_IDWriteTextLayout
) ||
2800 IsEqualIID(riid
, &IID_IUnknown
))
2804 else if (IsEqualIID(riid
, &IID_IDWriteTextFormat1
) ||
2805 IsEqualIID(riid
, &IID_IDWriteTextFormat
))
2806 *obj
= &This
->IDWriteTextFormat1_iface
;
2809 IDWriteTextLayout3_AddRef(iface
);
2813 return E_NOINTERFACE
;
2816 static ULONG WINAPI
dwritetextlayout_AddRef(IDWriteTextLayout3
*iface
)
2818 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2819 ULONG ref
= InterlockedIncrement(&This
->ref
);
2820 TRACE("(%p)->(%d)\n", This
, ref
);
2824 static ULONG WINAPI
dwritetextlayout_Release(IDWriteTextLayout3
*iface
)
2826 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2827 ULONG ref
= InterlockedDecrement(&This
->ref
);
2829 TRACE("(%p)->(%d)\n", This
, ref
);
2832 IDWriteFactory5_Release(This
->factory
);
2833 free_layout_ranges_list(This
);
2834 free_layout_eruns(This
);
2835 free_layout_runs(This
);
2836 release_format_data(&This
->format
);
2837 heap_free(This
->nominal_breakpoints
);
2838 heap_free(This
->actual_breakpoints
);
2839 heap_free(This
->clustermetrics
);
2840 heap_free(This
->clusters
);
2841 heap_free(This
->linemetrics
);
2842 heap_free(This
->lines
);
2843 heap_free(This
->str
);
2850 static HRESULT WINAPI
dwritetextlayout_SetTextAlignment(IDWriteTextLayout3
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
2852 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2853 return IDWriteTextFormat1_SetTextAlignment(&This
->IDWriteTextFormat1_iface
, alignment
);
2856 static HRESULT WINAPI
dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout3
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
2858 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2859 return IDWriteTextFormat1_SetParagraphAlignment(&This
->IDWriteTextFormat1_iface
, alignment
);
2862 static HRESULT WINAPI
dwritetextlayout_SetWordWrapping(IDWriteTextLayout3
*iface
, DWRITE_WORD_WRAPPING wrapping
)
2864 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2865 return IDWriteTextFormat1_SetWordWrapping(&This
->IDWriteTextFormat1_iface
, wrapping
);
2868 static HRESULT WINAPI
dwritetextlayout_SetReadingDirection(IDWriteTextLayout3
*iface
, DWRITE_READING_DIRECTION direction
)
2870 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2871 return IDWriteTextFormat1_SetReadingDirection(&This
->IDWriteTextFormat1_iface
, direction
);
2874 static HRESULT WINAPI
dwritetextlayout_SetFlowDirection(IDWriteTextLayout3
*iface
, DWRITE_FLOW_DIRECTION direction
)
2876 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2877 TRACE("(%p)->(%d)\n", This
, direction
);
2878 return IDWriteTextFormat1_SetFlowDirection(&This
->IDWriteTextFormat1_iface
, direction
);
2881 static HRESULT WINAPI
dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout3
*iface
, FLOAT tabstop
)
2883 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2884 TRACE("(%p)->(%.2f)\n", This
, tabstop
);
2885 return IDWriteTextFormat1_SetIncrementalTabStop(&This
->IDWriteTextFormat1_iface
, tabstop
);
2888 static HRESULT WINAPI
dwritetextlayout_SetTrimming(IDWriteTextLayout3
*iface
, DWRITE_TRIMMING
const *trimming
,
2889 IDWriteInlineObject
*trimming_sign
)
2891 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2892 TRACE("(%p)->(%p %p)\n", This
, trimming
, trimming_sign
);
2893 return IDWriteTextFormat1_SetTrimming(&This
->IDWriteTextFormat1_iface
, trimming
, trimming_sign
);
2896 static HRESULT WINAPI
dwritetextlayout_SetLineSpacing(IDWriteTextLayout3
*iface
, DWRITE_LINE_SPACING_METHOD spacing
,
2897 FLOAT line_spacing
, FLOAT baseline
)
2899 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2900 TRACE("(%p)->(%d %.2f %.2f)\n", This
, spacing
, line_spacing
, baseline
);
2901 return IDWriteTextFormat1_SetLineSpacing(&This
->IDWriteTextFormat1_iface
, spacing
, line_spacing
, baseline
);
2904 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextlayout_GetTextAlignment(IDWriteTextLayout3
*iface
)
2906 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2907 return IDWriteTextFormat1_GetTextAlignment(&This
->IDWriteTextFormat1_iface
);
2910 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout3
*iface
)
2912 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2913 return IDWriteTextFormat1_GetParagraphAlignment(&This
->IDWriteTextFormat1_iface
);
2916 static DWRITE_WORD_WRAPPING WINAPI
dwritetextlayout_GetWordWrapping(IDWriteTextLayout3
*iface
)
2918 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2919 return IDWriteTextFormat1_GetWordWrapping(&This
->IDWriteTextFormat1_iface
);
2922 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_GetReadingDirection(IDWriteTextLayout3
*iface
)
2924 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2925 return IDWriteTextFormat1_GetReadingDirection(&This
->IDWriteTextFormat1_iface
);
2928 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextlayout_GetFlowDirection(IDWriteTextLayout3
*iface
)
2930 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2931 return IDWriteTextFormat1_GetFlowDirection(&This
->IDWriteTextFormat1_iface
);
2934 static FLOAT WINAPI
dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout3
*iface
)
2936 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2937 return IDWriteTextFormat1_GetIncrementalTabStop(&This
->IDWriteTextFormat1_iface
);
2940 static HRESULT WINAPI
dwritetextlayout_GetTrimming(IDWriteTextLayout3
*iface
, DWRITE_TRIMMING
*options
,
2941 IDWriteInlineObject
**trimming_sign
)
2943 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2944 return IDWriteTextFormat1_GetTrimming(&This
->IDWriteTextFormat1_iface
, options
, trimming_sign
);
2947 static HRESULT WINAPI
dwritetextlayout_GetLineSpacing(IDWriteTextLayout3
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
2948 FLOAT
*spacing
, FLOAT
*baseline
)
2950 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2951 return IDWriteTextFormat_GetLineSpacing((IDWriteTextFormat
*)&This
->IDWriteTextFormat1_iface
, method
, spacing
, baseline
);
2954 static HRESULT WINAPI
dwritetextlayout_GetFontCollection(IDWriteTextLayout3
*iface
, IDWriteFontCollection
**collection
)
2956 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2957 return IDWriteTextFormat1_GetFontCollection(&This
->IDWriteTextFormat1_iface
, collection
);
2960 static UINT32 WINAPI
dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout3
*iface
)
2962 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2963 return IDWriteTextFormat1_GetFontFamilyNameLength(&This
->IDWriteTextFormat1_iface
);
2966 static HRESULT WINAPI
dwritetextlayout_GetFontFamilyName(IDWriteTextLayout3
*iface
, WCHAR
*name
, UINT32 size
)
2968 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2969 return IDWriteTextFormat1_GetFontFamilyName(&This
->IDWriteTextFormat1_iface
, name
, size
);
2972 static DWRITE_FONT_WEIGHT WINAPI
dwritetextlayout_GetFontWeight(IDWriteTextLayout3
*iface
)
2974 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2975 return IDWriteTextFormat1_GetFontWeight(&This
->IDWriteTextFormat1_iface
);
2978 static DWRITE_FONT_STYLE WINAPI
dwritetextlayout_GetFontStyle(IDWriteTextLayout3
*iface
)
2980 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2981 return IDWriteTextFormat1_GetFontStyle(&This
->IDWriteTextFormat1_iface
);
2984 static DWRITE_FONT_STRETCH WINAPI
dwritetextlayout_GetFontStretch(IDWriteTextLayout3
*iface
)
2986 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2987 return IDWriteTextFormat1_GetFontStretch(&This
->IDWriteTextFormat1_iface
);
2990 static FLOAT WINAPI
dwritetextlayout_GetFontSize(IDWriteTextLayout3
*iface
)
2992 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2993 return IDWriteTextFormat1_GetFontSize(&This
->IDWriteTextFormat1_iface
);
2996 static UINT32 WINAPI
dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout3
*iface
)
2998 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2999 return IDWriteTextFormat1_GetLocaleNameLength(&This
->IDWriteTextFormat1_iface
);
3002 static HRESULT WINAPI
dwritetextlayout_GetLocaleName(IDWriteTextLayout3
*iface
, WCHAR
*name
, UINT32 size
)
3004 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3005 return IDWriteTextFormat1_GetLocaleName(&This
->IDWriteTextFormat1_iface
, name
, size
);
3008 static HRESULT WINAPI
dwritetextlayout_SetMaxWidth(IDWriteTextLayout3
*iface
, FLOAT maxWidth
)
3010 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3013 TRACE("(%p)->(%.2f)\n", This
, maxWidth
);
3015 if (maxWidth
< 0.0f
)
3016 return E_INVALIDARG
;
3018 changed
= This
->metrics
.layoutWidth
!= maxWidth
;
3019 This
->metrics
.layoutWidth
= maxWidth
;
3022 This
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
3026 static HRESULT WINAPI
dwritetextlayout_SetMaxHeight(IDWriteTextLayout3
*iface
, FLOAT maxHeight
)
3028 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3031 TRACE("(%p)->(%.2f)\n", This
, maxHeight
);
3033 if (maxHeight
< 0.0f
)
3034 return E_INVALIDARG
;
3036 changed
= This
->metrics
.layoutHeight
!= maxHeight
;
3037 This
->metrics
.layoutHeight
= maxHeight
;
3040 This
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
3044 static HRESULT WINAPI
dwritetextlayout_SetFontCollection(IDWriteTextLayout3
*iface
, IDWriteFontCollection
* collection
, DWRITE_TEXT_RANGE range
)
3046 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3047 struct layout_range_attr_value value
;
3049 TRACE("(%p)->(%p %s)\n", This
, collection
, debugstr_range(&range
));
3051 value
.range
= range
;
3052 value
.u
.collection
= collection
;
3053 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTCOLL
, &value
);
3056 static HRESULT WINAPI
dwritetextlayout_SetFontFamilyName(IDWriteTextLayout3
*iface
, WCHAR
const *name
, DWRITE_TEXT_RANGE range
)
3058 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3059 struct layout_range_attr_value value
;
3061 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(name
), debugstr_range(&range
));
3064 return E_INVALIDARG
;
3066 value
.range
= range
;
3067 value
.u
.fontfamily
= name
;
3068 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, &value
);
3071 static HRESULT WINAPI
dwritetextlayout_SetFontWeight(IDWriteTextLayout3
*iface
, DWRITE_FONT_WEIGHT weight
, DWRITE_TEXT_RANGE range
)
3073 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3074 struct layout_range_attr_value value
;
3076 TRACE("(%p)->(%d %s)\n", This
, weight
, debugstr_range(&range
));
3078 if ((UINT32
)weight
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
)
3079 return E_INVALIDARG
;
3081 value
.range
= range
;
3082 value
.u
.weight
= weight
;
3083 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_WEIGHT
, &value
);
3086 static HRESULT WINAPI
dwritetextlayout_SetFontStyle(IDWriteTextLayout3
*iface
, DWRITE_FONT_STYLE style
, 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
, style
, debugstr_range(&range
));
3093 if ((UINT32
)style
> DWRITE_FONT_STYLE_ITALIC
)
3094 return E_INVALIDARG
;
3096 value
.range
= range
;
3097 value
.u
.style
= style
;
3098 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STYLE
, &value
);
3101 static HRESULT WINAPI
dwritetextlayout_SetFontStretch(IDWriteTextLayout3
*iface
, DWRITE_FONT_STRETCH stretch
, 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
, stretch
, debugstr_range(&range
));
3108 if (stretch
== DWRITE_FONT_STRETCH_UNDEFINED
|| (UINT32
)stretch
> DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
3109 return E_INVALIDARG
;
3111 value
.range
= range
;
3112 value
.u
.stretch
= stretch
;
3113 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STRETCH
, &value
);
3116 static HRESULT WINAPI
dwritetextlayout_SetFontSize(IDWriteTextLayout3
*iface
, FLOAT size
, DWRITE_TEXT_RANGE range
)
3118 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3119 struct layout_range_attr_value value
;
3121 TRACE("(%p)->(%.2f %s)\n", This
, size
, debugstr_range(&range
));
3124 return E_INVALIDARG
;
3126 value
.range
= range
;
3127 value
.u
.fontsize
= size
;
3128 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTSIZE
, &value
);
3131 static HRESULT WINAPI
dwritetextlayout_SetUnderline(IDWriteTextLayout3
*iface
, BOOL underline
, DWRITE_TEXT_RANGE range
)
3133 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3134 struct layout_range_attr_value value
;
3136 TRACE("(%p)->(%d %s)\n", This
, underline
, debugstr_range(&range
));
3138 value
.range
= range
;
3139 value
.u
.underline
= underline
;
3140 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_UNDERLINE
, &value
);
3143 static HRESULT WINAPI
dwritetextlayout_SetStrikethrough(IDWriteTextLayout3
*iface
, BOOL strikethrough
, DWRITE_TEXT_RANGE range
)
3145 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3146 struct layout_range_attr_value value
;
3148 TRACE("(%p)->(%d %s)\n", This
, strikethrough
, debugstr_range(&range
));
3150 value
.range
= range
;
3151 value
.u
.strikethrough
= strikethrough
;
3152 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STRIKETHROUGH
, &value
);
3155 static HRESULT WINAPI
dwritetextlayout_SetDrawingEffect(IDWriteTextLayout3
*iface
, IUnknown
* effect
, DWRITE_TEXT_RANGE range
)
3157 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3158 struct layout_range_attr_value value
;
3160 TRACE("(%p)->(%p %s)\n", This
, effect
, debugstr_range(&range
));
3162 value
.range
= range
;
3163 value
.u
.effect
= effect
;
3164 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_EFFECT
, &value
);
3167 static HRESULT WINAPI
dwritetextlayout_SetInlineObject(IDWriteTextLayout3
*iface
, IDWriteInlineObject
*object
, DWRITE_TEXT_RANGE range
)
3169 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3170 struct layout_range_attr_value value
;
3172 TRACE("(%p)->(%p %s)\n", This
, object
, debugstr_range(&range
));
3174 value
.range
= range
;
3175 value
.u
.object
= object
;
3176 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_INLINE
, &value
);
3179 static HRESULT WINAPI
dwritetextlayout_SetTypography(IDWriteTextLayout3
*iface
, IDWriteTypography
* typography
, DWRITE_TEXT_RANGE range
)
3181 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3182 struct layout_range_attr_value value
;
3184 TRACE("(%p)->(%p %s)\n", This
, typography
, debugstr_range(&range
));
3186 value
.range
= range
;
3187 value
.u
.typography
= typography
;
3188 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_TYPOGRAPHY
, &value
);
3191 static HRESULT WINAPI
dwritetextlayout_SetLocaleName(IDWriteTextLayout3
*iface
, WCHAR
const* locale
, DWRITE_TEXT_RANGE range
)
3193 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3194 struct layout_range_attr_value value
;
3196 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(locale
), debugstr_range(&range
));
3198 if (!locale
|| strlenW(locale
) > LOCALE_NAME_MAX_LENGTH
-1)
3199 return E_INVALIDARG
;
3201 value
.range
= range
;
3202 value
.u
.locale
= locale
;
3203 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_LOCALE
, &value
);
3206 static FLOAT WINAPI
dwritetextlayout_GetMaxWidth(IDWriteTextLayout3
*iface
)
3208 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3209 TRACE("(%p)\n", This
);
3210 return This
->metrics
.layoutWidth
;
3213 static FLOAT WINAPI
dwritetextlayout_GetMaxHeight(IDWriteTextLayout3
*iface
)
3215 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3216 TRACE("(%p)\n", This
);
3217 return This
->metrics
.layoutHeight
;
3220 static HRESULT WINAPI
dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout3
*iface
, UINT32 position
,
3221 IDWriteFontCollection
** collection
, DWRITE_TEXT_RANGE
*r
)
3223 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3224 struct layout_range
*range
;
3226 TRACE("(%p)->(%u %p %p)\n", This
, position
, collection
, r
);
3228 if (position
>= This
->len
)
3231 range
= get_layout_range_by_pos(This
, position
);
3232 *collection
= range
->collection
;
3234 IDWriteFontCollection_AddRef(*collection
);
3236 return return_range(&range
->h
, r
);
3239 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout3
*iface
,
3240 UINT32 position
, UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
3242 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3243 TRACE("(%p)->(%d %p %p)\n", This
, position
, length
, r
);
3244 return get_string_attribute_length(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, length
, r
);
3247 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout3
*iface
,
3248 UINT32 position
, WCHAR
*name
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
3250 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3251 TRACE("(%p)->(%u %p %u %p)\n", This
, position
, name
, length
, r
);
3252 return get_string_attribute_value(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, name
, length
, r
);
3255 static HRESULT WINAPI
dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout3
*iface
,
3256 UINT32 position
, DWRITE_FONT_WEIGHT
*weight
, DWRITE_TEXT_RANGE
*r
)
3258 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3259 struct layout_range
*range
;
3261 TRACE("(%p)->(%u %p %p)\n", This
, position
, weight
, r
);
3263 if (position
>= This
->len
)
3266 range
= get_layout_range_by_pos(This
, position
);
3267 *weight
= range
->weight
;
3269 return return_range(&range
->h
, r
);
3272 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout3
*iface
,
3273 UINT32 position
, DWRITE_FONT_STYLE
*style
, DWRITE_TEXT_RANGE
*r
)
3275 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3276 struct layout_range
*range
;
3278 TRACE("(%p)->(%u %p %p)\n", This
, position
, style
, r
);
3280 range
= get_layout_range_by_pos(This
, position
);
3281 *style
= range
->style
;
3282 return return_range(&range
->h
, r
);
3285 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout3
*iface
,
3286 UINT32 position
, DWRITE_FONT_STRETCH
*stretch
, DWRITE_TEXT_RANGE
*r
)
3288 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3289 struct layout_range
*range
;
3291 TRACE("(%p)->(%u %p %p)\n", This
, position
, stretch
, r
);
3293 range
= get_layout_range_by_pos(This
, position
);
3294 *stretch
= range
->stretch
;
3295 return return_range(&range
->h
, r
);
3298 static HRESULT WINAPI
dwritetextlayout_layout_GetFontSize(IDWriteTextLayout3
*iface
,
3299 UINT32 position
, FLOAT
*size
, DWRITE_TEXT_RANGE
*r
)
3301 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3302 struct layout_range
*range
;
3304 TRACE("(%p)->(%u %p %p)\n", This
, position
, size
, r
);
3306 range
= get_layout_range_by_pos(This
, position
);
3307 *size
= range
->fontsize
;
3308 return return_range(&range
->h
, r
);
3311 static HRESULT WINAPI
dwritetextlayout_GetUnderline(IDWriteTextLayout3
*iface
,
3312 UINT32 position
, BOOL
*underline
, DWRITE_TEXT_RANGE
*r
)
3314 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3315 struct layout_range_bool
*range
;
3317 TRACE("(%p)->(%u %p %p)\n", This
, position
, underline
, r
);
3319 range
= (struct layout_range_bool
*)get_layout_range_header_by_pos(&This
->underline_ranges
, position
);
3320 *underline
= range
->value
;
3322 return return_range(&range
->h
, r
);
3325 static HRESULT WINAPI
dwritetextlayout_GetStrikethrough(IDWriteTextLayout3
*iface
,
3326 UINT32 position
, BOOL
*strikethrough
, DWRITE_TEXT_RANGE
*r
)
3328 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3329 struct layout_range_bool
*range
;
3331 TRACE("(%p)->(%u %p %p)\n", This
, position
, strikethrough
, r
);
3333 range
= (struct layout_range_bool
*)get_layout_range_header_by_pos(&This
->strike_ranges
, position
);
3334 *strikethrough
= range
->value
;
3336 return return_range(&range
->h
, r
);
3339 static HRESULT WINAPI
dwritetextlayout_GetDrawingEffect(IDWriteTextLayout3
*iface
,
3340 UINT32 position
, IUnknown
**effect
, DWRITE_TEXT_RANGE
*r
)
3342 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3343 struct layout_range_iface
*range
;
3345 TRACE("(%p)->(%u %p %p)\n", This
, position
, effect
, r
);
3347 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&This
->effects
, position
);
3348 *effect
= range
->iface
;
3350 IUnknown_AddRef(*effect
);
3352 return return_range(&range
->h
, r
);
3355 static HRESULT WINAPI
dwritetextlayout_GetInlineObject(IDWriteTextLayout3
*iface
,
3356 UINT32 position
, IDWriteInlineObject
**object
, DWRITE_TEXT_RANGE
*r
)
3358 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3359 struct layout_range
*range
;
3361 TRACE("(%p)->(%u %p %p)\n", This
, position
, object
, r
);
3363 if (position
>= This
->len
)
3366 range
= get_layout_range_by_pos(This
, position
);
3367 *object
= range
->object
;
3369 IDWriteInlineObject_AddRef(*object
);
3371 return return_range(&range
->h
, r
);
3374 static HRESULT WINAPI
dwritetextlayout_GetTypography(IDWriteTextLayout3
*iface
,
3375 UINT32 position
, IDWriteTypography
** typography
, DWRITE_TEXT_RANGE
*r
)
3377 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3378 struct layout_range_iface
*range
;
3380 TRACE("(%p)->(%u %p %p)\n", This
, position
, typography
, r
);
3382 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&This
->typographies
, position
);
3383 *typography
= (IDWriteTypography
*)range
->iface
;
3385 IDWriteTypography_AddRef(*typography
);
3387 return return_range(&range
->h
, r
);
3390 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout3
*iface
,
3391 UINT32 position
, UINT32
* length
, DWRITE_TEXT_RANGE
*r
)
3393 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3394 TRACE("(%p)->(%u %p %p)\n", This
, position
, length
, r
);
3395 return get_string_attribute_length(This
, LAYOUT_RANGE_ATTR_LOCALE
, position
, length
, r
);
3398 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout3
*iface
,
3399 UINT32 position
, WCHAR
* locale
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
3401 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3402 TRACE("(%p)->(%u %p %u %p)\n", This
, position
, locale
, length
, r
);
3403 return get_string_attribute_value(This
, LAYOUT_RANGE_ATTR_LOCALE
, position
, locale
, length
, r
);
3406 static inline FLOAT
renderer_apply_snapping(FLOAT coord
, BOOL skiptransform
, FLOAT ppdip
, FLOAT det
,
3407 const DWRITE_MATRIX
*m
)
3409 D2D1_POINT_2F vec
, vec2
;
3411 if (!skiptransform
) {
3412 /* apply transform */
3414 vec
.y
= coord
* ppdip
;
3416 vec2
.x
= m
->m11
* vec
.x
+ m
->m21
* vec
.y
+ m
->dx
;
3417 vec2
.y
= m
->m12
* vec
.x
+ m
->m22
* vec
.y
+ m
->dy
;
3420 vec2
.x
= floorf(vec2
.x
+ 0.5f
);
3421 vec2
.y
= floorf(vec2
.y
+ 0.5f
);
3423 /* apply inverted transform, we don't care about X component at this point */
3424 vec
.y
= (-m
->m12
* vec2
.x
+ m
->m11
* vec2
.y
- (m
->m11
* m
->dy
- m
->m12
* m
->dx
)) / det
;
3428 vec
.y
= floorf(coord
* ppdip
+ 0.5f
) / ppdip
;
3433 static HRESULT WINAPI
dwritetextlayout_Draw(IDWriteTextLayout3
*iface
,
3434 void *context
, IDWriteTextRenderer
* renderer
, FLOAT origin_x
, FLOAT origin_y
)
3436 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3437 BOOL disabled
= FALSE
, skiptransform
= FALSE
;
3438 struct layout_effective_inline
*inlineobject
;
3439 struct layout_effective_run
*run
;
3440 struct layout_strikethrough
*s
;
3441 struct layout_underline
*u
;
3442 FLOAT det
= 0.0f
, ppdip
= 0.0f
;
3443 DWRITE_MATRIX m
= { 0 };
3446 TRACE("(%p)->(%p %p %.2f %.2f)\n", This
, context
, renderer
, origin_x
, origin_y
);
3448 hr
= layout_compute_effective_runs(This
);
3452 hr
= IDWriteTextRenderer_IsPixelSnappingDisabled(renderer
, context
, &disabled
);
3457 hr
= IDWriteTextRenderer_GetPixelsPerDip(renderer
, context
, &ppdip
);
3461 hr
= IDWriteTextRenderer_GetCurrentTransform(renderer
, context
, &m
);
3465 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
3466 if (ppdip
<= 0.0f
||
3467 (m
.m11
* m
.m22
!= 0.0f
&& (m
.m12
!= 0.0f
|| m
.m21
!= 0.0f
)) ||
3468 (m
.m12
* m
.m21
!= 0.0f
&& (m
.m11
!= 0.0f
|| m
.m22
!= 0.0f
)))
3471 skiptransform
= should_skip_transform(&m
, &det
);
3474 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
3475 /* 1. Regular runs */
3476 LIST_FOR_EACH_ENTRY(run
, &This
->eruns
, struct layout_effective_run
, entry
) {
3477 const struct regular_layout_run
*regular
= &run
->run
->u
.regular
;
3478 UINT32 start_glyph
= regular
->clustermap
[run
->start
];
3479 DWRITE_GLYPH_RUN_DESCRIPTION descr
;
3480 DWRITE_GLYPH_RUN glyph_run
;
3482 /* Everything but cluster map will be reused from nominal run, as we only need
3483 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
3484 it can't be reused because it has to start with 0 index for each reported run. */
3485 glyph_run
= regular
->run
;
3486 glyph_run
.glyphCount
= run
->glyphcount
;
3488 /* fixup glyph data arrays */
3489 glyph_run
.glyphIndices
+= start_glyph
;
3490 glyph_run
.glyphAdvances
+= start_glyph
;
3491 glyph_run
.glyphOffsets
+= start_glyph
;
3494 descr
= regular
->descr
;
3495 descr
.stringLength
= run
->length
;
3496 descr
.string
+= run
->start
;
3497 descr
.clusterMap
= run
->clustermap
;
3498 descr
.textPosition
+= run
->start
;
3500 /* return value is ignored */
3501 IDWriteTextRenderer_DrawGlyphRun(renderer
,
3503 run
->origin
.x
+ run
->align_dx
+ origin_x
,
3504 SNAP_COORD(run
->origin
.y
+ origin_y
),
3505 This
->measuringmode
,
3511 /* 2. Inline objects */
3512 LIST_FOR_EACH_ENTRY(inlineobject
, &This
->inlineobjects
, struct layout_effective_inline
, entry
) {
3513 IDWriteTextRenderer_DrawInlineObject(renderer
,
3515 inlineobject
->origin
.x
+ inlineobject
->align_dx
+ origin_x
,
3516 SNAP_COORD(inlineobject
->origin
.y
+ origin_y
),
3517 inlineobject
->object
,
3518 inlineobject
->is_sideways
,
3519 inlineobject
->is_rtl
,
3520 inlineobject
->effect
);
3524 LIST_FOR_EACH_ENTRY(u
, &This
->underlines
, struct layout_underline
, entry
) {
3525 IDWriteTextRenderer_DrawUnderline(renderer
,
3527 /* horizontal underline always grows from left to right, width is always added to origin regardless of run direction */
3528 (is_run_rtl(u
->run
) ? u
->run
->origin
.x
- u
->run
->width
: u
->run
->origin
.x
) + u
->run
->align_dx
+ origin_x
,
3529 SNAP_COORD(u
->run
->origin
.y
+ origin_y
),
3534 /* 4. Strikethrough */
3535 LIST_FOR_EACH_ENTRY(s
, &This
->strikethrough
, struct layout_strikethrough
, entry
) {
3536 IDWriteTextRenderer_DrawStrikethrough(renderer
,
3538 s
->run
->origin
.x
+ s
->run
->align_dx
+ origin_x
,
3539 SNAP_COORD(s
->run
->origin
.y
+ origin_y
),
3548 static HRESULT WINAPI
dwritetextlayout_GetLineMetrics(IDWriteTextLayout3
*iface
,
3549 DWRITE_LINE_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
3551 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3554 TRACE("(%p)->(%p %u %p)\n", This
, metrics
, max_count
, count
);
3556 hr
= layout_compute_effective_runs(This
);
3561 UINT32 i
, c
= min(max_count
, This
->metrics
.lineCount
);
3562 for (i
= 0; i
< c
; i
++)
3563 memcpy(metrics
+ i
, This
->linemetrics
+ i
, sizeof(*metrics
));
3566 *count
= This
->metrics
.lineCount
;
3567 return max_count
>= This
->metrics
.lineCount
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
3570 static HRESULT WINAPI
dwritetextlayout_GetMetrics(IDWriteTextLayout3
*iface
, DWRITE_TEXT_METRICS
*metrics
)
3572 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3573 DWRITE_TEXT_METRICS1 metrics1
;
3576 TRACE("(%p)->(%p)\n", This
, metrics
);
3578 hr
= IDWriteTextLayout3_GetMetrics(iface
, &metrics1
);
3580 memcpy(metrics
, &metrics1
, sizeof(*metrics
));
3585 static void scale_glyph_bbox(RECT
*bbox
, FLOAT emSize
, UINT16 units_per_em
, D2D1_RECT_F
*ret
)
3587 #define SCALE(x) ((FLOAT)x * emSize / (FLOAT)units_per_em)
3588 ret
->left
= SCALE(bbox
->left
);
3589 ret
->right
= SCALE(bbox
->right
);
3590 ret
->top
= SCALE(bbox
->top
);
3591 ret
->bottom
= SCALE(bbox
->bottom
);
3595 static void d2d_rect_offset(D2D1_RECT_F
*rect
, FLOAT x
, FLOAT y
)
3603 static BOOL
d2d_rect_is_empty(const D2D1_RECT_F
*rect
)
3605 return ((rect
->left
>= rect
->right
) || (rect
->top
>= rect
->bottom
));
3608 static void d2d_rect_union(D2D1_RECT_F
*dst
, const D2D1_RECT_F
*src
)
3610 if (d2d_rect_is_empty(dst
)) {
3611 if (d2d_rect_is_empty(src
)) {
3612 dst
->left
= dst
->right
= dst
->top
= dst
->bottom
= 0.0f
;
3619 if (!d2d_rect_is_empty(src
)) {
3620 dst
->left
= min(dst
->left
, src
->left
);
3621 dst
->right
= max(dst
->right
, src
->right
);
3622 dst
->top
= min(dst
->top
, src
->top
);
3623 dst
->bottom
= max(dst
->bottom
, src
->bottom
);
3628 static void layout_get_erun_bbox(struct dwrite_textlayout
*layout
, struct layout_effective_run
*run
, D2D1_RECT_F
*bbox
)
3630 const struct regular_layout_run
*regular
= &run
->run
->u
.regular
;
3631 UINT32 start_glyph
= regular
->clustermap
[run
->start
];
3632 const DWRITE_GLYPH_RUN
*glyph_run
= ®ular
->run
;
3633 DWRITE_FONT_METRICS font_metrics
;
3634 D2D1_POINT_2F origin
= { 0 };
3637 if (run
->bbox
.top
== run
->bbox
.bottom
) {
3638 IDWriteFontFace_GetMetrics(glyph_run
->fontFace
, &font_metrics
);
3640 for (i
= 0; i
< run
->glyphcount
; i
++) {
3641 D2D1_RECT_F glyph_bbox
;
3644 freetype_get_design_glyph_bbox((IDWriteFontFace4
*)glyph_run
->fontFace
, font_metrics
.designUnitsPerEm
,
3645 glyph_run
->glyphIndices
[i
+ start_glyph
], &design_bbox
);
3647 scale_glyph_bbox(&design_bbox
, glyph_run
->fontEmSize
, font_metrics
.designUnitsPerEm
, &glyph_bbox
);
3648 d2d_rect_offset(&glyph_bbox
, origin
.x
+ glyph_run
->glyphOffsets
[i
+ start_glyph
].advanceOffset
,
3649 origin
.y
+ glyph_run
->glyphOffsets
[i
+ start_glyph
].ascenderOffset
);
3650 d2d_rect_union(&run
->bbox
, &glyph_bbox
);
3652 /* FIXME: take care of vertical/rtl */
3653 origin
.x
+= glyph_run
->glyphAdvances
[i
+ start_glyph
];
3658 d2d_rect_offset(bbox
, run
->origin
.x
+ run
->align_dx
, run
->origin
.y
);
3661 static HRESULT WINAPI
dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout3
*iface
,
3662 DWRITE_OVERHANG_METRICS
*overhangs
)
3664 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3665 struct layout_effective_run
*run
;
3666 D2D1_RECT_F bbox
= { 0 };
3669 TRACE("(%p)->(%p)\n", This
, overhangs
);
3671 memset(overhangs
, 0, sizeof(*overhangs
));
3673 if (!(This
->recompute
& RECOMPUTE_OVERHANGS
)) {
3674 *overhangs
= This
->overhangs
;
3678 hr
= layout_compute_effective_runs(This
);
3682 LIST_FOR_EACH_ENTRY(run
, &This
->eruns
, struct layout_effective_run
, entry
) {
3683 D2D1_RECT_F run_bbox
;
3685 layout_get_erun_bbox(This
, run
, &run_bbox
);
3686 d2d_rect_union(&bbox
, &run_bbox
);
3689 /* FIXME: iterate over inline objects too */
3691 /* deltas from text content metrics */
3692 This
->overhangs
.left
= -bbox
.left
;
3693 This
->overhangs
.top
= -bbox
.top
;
3694 This
->overhangs
.right
= bbox
.right
- This
->metrics
.layoutWidth
;
3695 This
->overhangs
.bottom
= bbox
.bottom
- This
->metrics
.layoutHeight
;
3696 This
->recompute
&= ~RECOMPUTE_OVERHANGS
;
3698 *overhangs
= This
->overhangs
;
3703 static HRESULT WINAPI
dwritetextlayout_GetClusterMetrics(IDWriteTextLayout3
*iface
,
3704 DWRITE_CLUSTER_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
3706 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3709 TRACE("(%p)->(%p %u %p)\n", This
, metrics
, max_count
, count
);
3711 hr
= layout_compute(This
);
3716 memcpy(metrics
, This
->clustermetrics
, sizeof(DWRITE_CLUSTER_METRICS
)*min(max_count
, This
->cluster_count
));
3718 *count
= This
->cluster_count
;
3719 return max_count
>= This
->cluster_count
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
3722 static HRESULT WINAPI
dwritetextlayout_DetermineMinWidth(IDWriteTextLayout3
*iface
, FLOAT
* min_width
)
3724 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3729 TRACE("(%p)->(%p)\n", This
, min_width
);
3732 return E_INVALIDARG
;
3734 if (!(This
->recompute
& RECOMPUTE_MINIMAL_WIDTH
))
3738 hr
= layout_compute(This
);
3742 /* Find widest word without emergency breaking between clusters, trailing whitespaces
3743 preceding breaking point do not contribute to word width. */
3744 for (start
= 0; start
< This
->cluster_count
;) {
3745 UINT32 end
= start
, j
, next
;
3747 /* Last cluster always could be wrapped after. */
3748 while (!This
->clustermetrics
[end
].canWrapLineAfter
)
3750 /* make is so current cluster range that we can wrap after is [start,end) */
3755 /* Ignore trailing whitespace clusters, in case of single space range will
3756 be reduced to empty range, or [start,start+1). */
3757 while (end
> start
&& This
->clustermetrics
[end
-1].isWhitespace
)
3760 /* check if cluster range exceeds last minimal width */
3762 for (j
= start
; j
< end
; j
++)
3763 width
+= This
->clustermetrics
[j
].width
;
3767 if (width
> This
->minwidth
)
3768 This
->minwidth
= width
;
3770 This
->recompute
&= ~RECOMPUTE_MINIMAL_WIDTH
;
3773 *min_width
= This
->minwidth
;
3777 static HRESULT WINAPI
dwritetextlayout_HitTestPoint(IDWriteTextLayout3
*iface
,
3778 FLOAT pointX
, FLOAT pointY
, BOOL
* is_trailinghit
, BOOL
* is_inside
, DWRITE_HIT_TEST_METRICS
*metrics
)
3780 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3781 FIXME("(%p)->(%f %f %p %p %p): stub\n", This
, pointX
, pointY
, is_trailinghit
, is_inside
, metrics
);
3785 static HRESULT WINAPI
dwritetextlayout_HitTestTextPosition(IDWriteTextLayout3
*iface
,
3786 UINT32 textPosition
, BOOL is_trailinghit
, FLOAT
* pointX
, FLOAT
* pointY
, DWRITE_HIT_TEST_METRICS
*metrics
)
3788 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3789 FIXME("(%p)->(%u %d %p %p %p): stub\n", This
, textPosition
, is_trailinghit
, pointX
, pointY
, metrics
);
3793 static HRESULT WINAPI
dwritetextlayout_HitTestTextRange(IDWriteTextLayout3
*iface
,
3794 UINT32 textPosition
, UINT32 textLength
, FLOAT originX
, FLOAT originY
,
3795 DWRITE_HIT_TEST_METRICS
*metrics
, UINT32 max_metricscount
, UINT32
* actual_metricscount
)
3797 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3798 FIXME("(%p)->(%u %u %f %f %p %u %p): stub\n", This
, textPosition
, textLength
, originX
, originY
, metrics
,
3799 max_metricscount
, actual_metricscount
);
3803 static HRESULT WINAPI
dwritetextlayout1_SetPairKerning(IDWriteTextLayout3
*iface
, BOOL is_pairkerning_enabled
,
3804 DWRITE_TEXT_RANGE range
)
3806 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3807 struct layout_range_attr_value value
;
3809 TRACE("(%p)->(%d %s)\n", This
, is_pairkerning_enabled
, debugstr_range(&range
));
3811 value
.range
= range
;
3812 value
.u
.pair_kerning
= !!is_pairkerning_enabled
;
3813 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_PAIR_KERNING
, &value
);
3816 static HRESULT WINAPI
dwritetextlayout1_GetPairKerning(IDWriteTextLayout3
*iface
, UINT32 position
, BOOL
*is_pairkerning_enabled
,
3817 DWRITE_TEXT_RANGE
*r
)
3819 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3820 struct layout_range
*range
;
3822 TRACE("(%p)->(%u %p %p)\n", This
, position
, is_pairkerning_enabled
, r
);
3824 if (position
>= This
->len
)
3827 range
= get_layout_range_by_pos(This
, position
);
3828 *is_pairkerning_enabled
= range
->pair_kerning
;
3830 return return_range(&range
->h
, r
);
3833 static HRESULT WINAPI
dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout3
*iface
, FLOAT leading
, FLOAT trailing
,
3834 FLOAT min_advance
, DWRITE_TEXT_RANGE range
)
3836 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3837 struct layout_range_attr_value value
;
3839 TRACE("(%p)->(%.2f %.2f %.2f %s)\n", This
, leading
, trailing
, min_advance
, debugstr_range(&range
));
3841 if (min_advance
< 0.0f
)
3842 return E_INVALIDARG
;
3844 value
.range
= range
;
3845 value
.u
.spacing
.leading
= leading
;
3846 value
.u
.spacing
.trailing
= trailing
;
3847 value
.u
.spacing
.min_advance
= min_advance
;
3848 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_SPACING
, &value
);
3851 static HRESULT WINAPI
dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout3
*iface
, UINT32 position
, FLOAT
*leading
,
3852 FLOAT
*trailing
, FLOAT
*min_advance
, DWRITE_TEXT_RANGE
*r
)
3854 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3855 struct layout_range_spacing
*range
;
3857 TRACE("(%p)->(%u %p %p %p %p)\n", This
, position
, leading
, trailing
, min_advance
, r
);
3859 range
= (struct layout_range_spacing
*)get_layout_range_header_by_pos(&This
->spacing
, position
);
3860 *leading
= range
->leading
;
3861 *trailing
= range
->trailing
;
3862 *min_advance
= range
->min_advance
;
3864 return return_range(&range
->h
, r
);
3867 static HRESULT WINAPI
dwritetextlayout2_GetMetrics(IDWriteTextLayout3
*iface
, DWRITE_TEXT_METRICS1
*metrics
)
3869 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3872 TRACE("(%p)->(%p)\n", This
, metrics
);
3874 hr
= layout_compute_effective_runs(This
);
3878 *metrics
= This
->metrics
;
3882 static HRESULT WINAPI
dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout3
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
3884 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3886 TRACE("(%p)->(%d)\n", This
, orientation
);
3888 if ((UINT32
)orientation
> DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED
)
3889 return E_INVALIDARG
;
3891 This
->format
.vertical_orientation
= orientation
;
3895 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout3
*iface
)
3897 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3898 TRACE("(%p)\n", This
);
3899 return This
->format
.vertical_orientation
;
3902 static HRESULT WINAPI
dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout3
*iface
, BOOL lastline_wrapping_enabled
)
3904 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3905 TRACE("(%p)->(%d)\n", This
, lastline_wrapping_enabled
);
3906 return IDWriteTextFormat1_SetLastLineWrapping(&This
->IDWriteTextFormat1_iface
, lastline_wrapping_enabled
);
3909 static BOOL WINAPI
dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout3
*iface
)
3911 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3912 TRACE("(%p)\n", This
);
3913 return IDWriteTextFormat1_GetLastLineWrapping(&This
->IDWriteTextFormat1_iface
);
3916 static HRESULT WINAPI
dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout3
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
3918 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3919 TRACE("(%p)->(%d)\n", This
, alignment
);
3920 return IDWriteTextFormat1_SetOpticalAlignment(&This
->IDWriteTextFormat1_iface
, alignment
);
3923 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout3
*iface
)
3925 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3926 TRACE("(%p)\n", This
);
3927 return IDWriteTextFormat1_GetOpticalAlignment(&This
->IDWriteTextFormat1_iface
);
3930 static HRESULT WINAPI
dwritetextlayout2_SetFontFallback(IDWriteTextLayout3
*iface
, IDWriteFontFallback
*fallback
)
3932 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3933 TRACE("(%p)->(%p)\n", This
, fallback
);
3934 return set_fontfallback_for_format(&This
->format
, fallback
);
3937 static HRESULT WINAPI
dwritetextlayout2_GetFontFallback(IDWriteTextLayout3
*iface
, IDWriteFontFallback
**fallback
)
3939 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3940 TRACE("(%p)->(%p)\n", This
, fallback
);
3941 return get_fontfallback_from_format(&This
->format
, fallback
);
3944 static HRESULT WINAPI
dwritetextlayout3_InvalidateLayout(IDWriteTextLayout3
*iface
)
3946 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3948 TRACE("(%p)\n", This
);
3950 This
->recompute
= RECOMPUTE_EVERYTHING
;
3954 static HRESULT WINAPI
dwritetextlayout3_SetLineSpacing(IDWriteTextLayout3
*iface
, DWRITE_LINE_SPACING
const *spacing
)
3956 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3960 TRACE("(%p)->(%p)\n", This
, spacing
);
3962 hr
= format_set_linespacing(&This
->format
, spacing
, &changed
);
3967 if (!(This
->recompute
& RECOMPUTE_LINES
)) {
3970 switch (This
->format
.spacing
.method
)
3972 case DWRITE_LINE_SPACING_METHOD_DEFAULT
:
3973 for (line
= 0; line
< This
->metrics
.lineCount
; line
++) {
3974 This
->linemetrics
[line
].height
= This
->lines
[line
].height
;
3975 This
->linemetrics
[line
].baseline
= This
->lines
[line
].baseline
;
3978 case DWRITE_LINE_SPACING_METHOD_UNIFORM
:
3979 for (line
= 0; line
< This
->metrics
.lineCount
; line
++) {
3980 This
->linemetrics
[line
].height
= This
->format
.spacing
.height
;
3981 This
->linemetrics
[line
].baseline
= This
->format
.spacing
.baseline
;
3984 case DWRITE_LINE_SPACING_METHOD_PROPORTIONAL
:
3985 for (line
= 0; line
< This
->metrics
.lineCount
; line
++) {
3986 This
->linemetrics
[line
].height
= This
->format
.spacing
.height
* This
->lines
[line
].height
;
3987 This
->linemetrics
[line
].baseline
= This
->format
.spacing
.baseline
* This
->lines
[line
].baseline
;
3994 layout_set_line_positions(This
);
3997 This
->recompute
|= RECOMPUTE_OVERHANGS
;
4003 static HRESULT WINAPI
dwritetextlayout3_GetLineSpacing(IDWriteTextLayout3
*iface
, DWRITE_LINE_SPACING
*spacing
)
4005 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
4007 TRACE("(%p)->(%p)\n", This
, spacing
);
4009 *spacing
= This
->format
.spacing
;
4013 static HRESULT WINAPI
dwritetextlayout3_GetLineMetrics(IDWriteTextLayout3
*iface
, DWRITE_LINE_METRICS1
*metrics
,
4014 UINT32 max_count
, UINT32
*count
)
4016 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
4019 TRACE("(%p)->(%p %u %p)\n", This
, metrics
, max_count
, count
);
4021 hr
= layout_compute_effective_runs(This
);
4026 memcpy(metrics
, This
->linemetrics
, sizeof(*metrics
) * min(max_count
, This
->metrics
.lineCount
));
4028 *count
= This
->metrics
.lineCount
;
4029 return max_count
>= This
->metrics
.lineCount
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
4032 static const IDWriteTextLayout3Vtbl dwritetextlayoutvtbl
= {
4033 dwritetextlayout_QueryInterface
,
4034 dwritetextlayout_AddRef
,
4035 dwritetextlayout_Release
,
4036 dwritetextlayout_SetTextAlignment
,
4037 dwritetextlayout_SetParagraphAlignment
,
4038 dwritetextlayout_SetWordWrapping
,
4039 dwritetextlayout_SetReadingDirection
,
4040 dwritetextlayout_SetFlowDirection
,
4041 dwritetextlayout_SetIncrementalTabStop
,
4042 dwritetextlayout_SetTrimming
,
4043 dwritetextlayout_SetLineSpacing
,
4044 dwritetextlayout_GetTextAlignment
,
4045 dwritetextlayout_GetParagraphAlignment
,
4046 dwritetextlayout_GetWordWrapping
,
4047 dwritetextlayout_GetReadingDirection
,
4048 dwritetextlayout_GetFlowDirection
,
4049 dwritetextlayout_GetIncrementalTabStop
,
4050 dwritetextlayout_GetTrimming
,
4051 dwritetextlayout_GetLineSpacing
,
4052 dwritetextlayout_GetFontCollection
,
4053 dwritetextlayout_GetFontFamilyNameLength
,
4054 dwritetextlayout_GetFontFamilyName
,
4055 dwritetextlayout_GetFontWeight
,
4056 dwritetextlayout_GetFontStyle
,
4057 dwritetextlayout_GetFontStretch
,
4058 dwritetextlayout_GetFontSize
,
4059 dwritetextlayout_GetLocaleNameLength
,
4060 dwritetextlayout_GetLocaleName
,
4061 dwritetextlayout_SetMaxWidth
,
4062 dwritetextlayout_SetMaxHeight
,
4063 dwritetextlayout_SetFontCollection
,
4064 dwritetextlayout_SetFontFamilyName
,
4065 dwritetextlayout_SetFontWeight
,
4066 dwritetextlayout_SetFontStyle
,
4067 dwritetextlayout_SetFontStretch
,
4068 dwritetextlayout_SetFontSize
,
4069 dwritetextlayout_SetUnderline
,
4070 dwritetextlayout_SetStrikethrough
,
4071 dwritetextlayout_SetDrawingEffect
,
4072 dwritetextlayout_SetInlineObject
,
4073 dwritetextlayout_SetTypography
,
4074 dwritetextlayout_SetLocaleName
,
4075 dwritetextlayout_GetMaxWidth
,
4076 dwritetextlayout_GetMaxHeight
,
4077 dwritetextlayout_layout_GetFontCollection
,
4078 dwritetextlayout_layout_GetFontFamilyNameLength
,
4079 dwritetextlayout_layout_GetFontFamilyName
,
4080 dwritetextlayout_layout_GetFontWeight
,
4081 dwritetextlayout_layout_GetFontStyle
,
4082 dwritetextlayout_layout_GetFontStretch
,
4083 dwritetextlayout_layout_GetFontSize
,
4084 dwritetextlayout_GetUnderline
,
4085 dwritetextlayout_GetStrikethrough
,
4086 dwritetextlayout_GetDrawingEffect
,
4087 dwritetextlayout_GetInlineObject
,
4088 dwritetextlayout_GetTypography
,
4089 dwritetextlayout_layout_GetLocaleNameLength
,
4090 dwritetextlayout_layout_GetLocaleName
,
4091 dwritetextlayout_Draw
,
4092 dwritetextlayout_GetLineMetrics
,
4093 dwritetextlayout_GetMetrics
,
4094 dwritetextlayout_GetOverhangMetrics
,
4095 dwritetextlayout_GetClusterMetrics
,
4096 dwritetextlayout_DetermineMinWidth
,
4097 dwritetextlayout_HitTestPoint
,
4098 dwritetextlayout_HitTestTextPosition
,
4099 dwritetextlayout_HitTestTextRange
,
4100 dwritetextlayout1_SetPairKerning
,
4101 dwritetextlayout1_GetPairKerning
,
4102 dwritetextlayout1_SetCharacterSpacing
,
4103 dwritetextlayout1_GetCharacterSpacing
,
4104 dwritetextlayout2_GetMetrics
,
4105 dwritetextlayout2_SetVerticalGlyphOrientation
,
4106 dwritetextlayout2_GetVerticalGlyphOrientation
,
4107 dwritetextlayout2_SetLastLineWrapping
,
4108 dwritetextlayout2_GetLastLineWrapping
,
4109 dwritetextlayout2_SetOpticalAlignment
,
4110 dwritetextlayout2_GetOpticalAlignment
,
4111 dwritetextlayout2_SetFontFallback
,
4112 dwritetextlayout2_GetFontFallback
,
4113 dwritetextlayout3_InvalidateLayout
,
4114 dwritetextlayout3_SetLineSpacing
,
4115 dwritetextlayout3_GetLineSpacing
,
4116 dwritetextlayout3_GetLineMetrics
4119 static HRESULT WINAPI
dwritetextformat_layout_QueryInterface(IDWriteTextFormat1
*iface
, REFIID riid
, void **obj
)
4121 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4122 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
4123 return IDWriteTextLayout3_QueryInterface(&This
->IDWriteTextLayout3_iface
, riid
, obj
);
4126 static ULONG WINAPI
dwritetextformat_layout_AddRef(IDWriteTextFormat1
*iface
)
4128 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4129 return IDWriteTextLayout3_AddRef(&This
->IDWriteTextLayout3_iface
);
4132 static ULONG WINAPI
dwritetextformat_layout_Release(IDWriteTextFormat1
*iface
)
4134 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4135 return IDWriteTextLayout3_Release(&This
->IDWriteTextLayout3_iface
);
4138 static HRESULT WINAPI
dwritetextformat_layout_SetTextAlignment(IDWriteTextFormat1
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
4140 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4144 TRACE("(%p)->(%d)\n", This
, alignment
);
4146 hr
= format_set_textalignment(&This
->format
, alignment
, &changed
);
4151 /* if layout is not ready there's nothing to align */
4152 if (!(This
->recompute
& RECOMPUTE_LINES
))
4153 layout_apply_text_alignment(This
);
4154 This
->recompute
|= RECOMPUTE_OVERHANGS
;
4160 static HRESULT WINAPI
dwritetextformat_layout_SetParagraphAlignment(IDWriteTextFormat1
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
4162 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4166 TRACE("(%p)->(%d)\n", This
, alignment
);
4168 hr
= format_set_paralignment(&This
->format
, alignment
, &changed
);
4173 /* if layout is not ready there's nothing to align */
4174 if (!(This
->recompute
& RECOMPUTE_LINES
))
4175 layout_apply_par_alignment(This
);
4176 This
->recompute
|= RECOMPUTE_OVERHANGS
;
4182 static HRESULT WINAPI
dwritetextformat_layout_SetWordWrapping(IDWriteTextFormat1
*iface
, DWRITE_WORD_WRAPPING wrapping
)
4184 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4188 TRACE("(%p)->(%d)\n", This
, wrapping
);
4190 hr
= format_set_wordwrapping(&This
->format
, wrapping
, &changed
);
4195 This
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
4200 static HRESULT WINAPI
dwritetextformat_layout_SetReadingDirection(IDWriteTextFormat1
*iface
, DWRITE_READING_DIRECTION direction
)
4202 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4206 TRACE("(%p)->(%d)\n", This
, direction
);
4208 hr
= format_set_readingdirection(&This
->format
, direction
, &changed
);
4213 This
->recompute
= RECOMPUTE_EVERYTHING
;
4218 static HRESULT WINAPI
dwritetextformat_layout_SetFlowDirection(IDWriteTextFormat1
*iface
, DWRITE_FLOW_DIRECTION direction
)
4220 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4224 TRACE("(%p)->(%d)\n", This
, direction
);
4226 hr
= format_set_flowdirection(&This
->format
, direction
, &changed
);
4231 This
->recompute
= RECOMPUTE_EVERYTHING
;
4236 static HRESULT WINAPI
dwritetextformat_layout_SetIncrementalTabStop(IDWriteTextFormat1
*iface
, FLOAT tabstop
)
4238 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4239 FIXME("(%p)->(%f): stub\n", This
, tabstop
);
4243 static HRESULT WINAPI
dwritetextformat_layout_SetTrimming(IDWriteTextFormat1
*iface
, DWRITE_TRIMMING
const *trimming
,
4244 IDWriteInlineObject
*trimming_sign
)
4246 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4250 TRACE("(%p)->(%p %p)\n", This
, trimming
, trimming_sign
);
4252 hr
= format_set_trimming(&This
->format
, trimming
, trimming_sign
, &changed
);
4255 This
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
4260 static HRESULT WINAPI
dwritetextformat_layout_SetLineSpacing(IDWriteTextFormat1
*iface
, DWRITE_LINE_SPACING_METHOD method
,
4261 FLOAT height
, FLOAT baseline
)
4263 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4264 DWRITE_LINE_SPACING spacing
;
4266 TRACE("(%p)->(%d %f %f)\n", This
, method
, height
, baseline
);
4268 spacing
= This
->format
.spacing
;
4269 spacing
.method
= method
;
4270 spacing
.height
= height
;
4271 spacing
.baseline
= baseline
;
4272 return IDWriteTextLayout3_SetLineSpacing(&This
->IDWriteTextLayout3_iface
, &spacing
);
4275 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextformat_layout_GetTextAlignment(IDWriteTextFormat1
*iface
)
4277 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4278 TRACE("(%p)\n", This
);
4279 return This
->format
.textalignment
;
4282 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextformat_layout_GetParagraphAlignment(IDWriteTextFormat1
*iface
)
4284 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4285 TRACE("(%p)\n", This
);
4286 return This
->format
.paralign
;
4289 static DWRITE_WORD_WRAPPING WINAPI
dwritetextformat_layout_GetWordWrapping(IDWriteTextFormat1
*iface
)
4291 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4292 TRACE("(%p)\n", This
);
4293 return This
->format
.wrapping
;
4296 static DWRITE_READING_DIRECTION WINAPI
dwritetextformat_layout_GetReadingDirection(IDWriteTextFormat1
*iface
)
4298 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4299 TRACE("(%p)\n", This
);
4300 return This
->format
.readingdir
;
4303 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextformat_layout_GetFlowDirection(IDWriteTextFormat1
*iface
)
4305 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4306 TRACE("(%p)\n", This
);
4307 return This
->format
.flow
;
4310 static FLOAT WINAPI
dwritetextformat_layout_GetIncrementalTabStop(IDWriteTextFormat1
*iface
)
4312 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4313 FIXME("(%p): stub\n", This
);
4317 static HRESULT WINAPI
dwritetextformat_layout_GetTrimming(IDWriteTextFormat1
*iface
, DWRITE_TRIMMING
*options
,
4318 IDWriteInlineObject
**trimming_sign
)
4320 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4322 TRACE("(%p)->(%p %p)\n", This
, options
, trimming_sign
);
4324 *options
= This
->format
.trimming
;
4325 *trimming_sign
= This
->format
.trimmingsign
;
4327 IDWriteInlineObject_AddRef(*trimming_sign
);
4331 static HRESULT WINAPI
dwritetextformat_layout_GetLineSpacing(IDWriteTextFormat1
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
4332 FLOAT
*spacing
, FLOAT
*baseline
)
4334 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4336 TRACE("(%p)->(%p %p %p)\n", This
, method
, spacing
, baseline
);
4338 *method
= This
->format
.spacing
.method
;
4339 *spacing
= This
->format
.spacing
.height
;
4340 *baseline
= This
->format
.spacing
.baseline
;
4344 static HRESULT WINAPI
dwritetextformat_layout_GetFontCollection(IDWriteTextFormat1
*iface
, IDWriteFontCollection
**collection
)
4346 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4348 TRACE("(%p)->(%p)\n", This
, collection
);
4350 *collection
= This
->format
.collection
;
4352 IDWriteFontCollection_AddRef(*collection
);
4356 static UINT32 WINAPI
dwritetextformat_layout_GetFontFamilyNameLength(IDWriteTextFormat1
*iface
)
4358 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4359 TRACE("(%p)\n", This
);
4360 return This
->format
.family_len
;
4363 static HRESULT WINAPI
dwritetextformat_layout_GetFontFamilyName(IDWriteTextFormat1
*iface
, WCHAR
*name
, UINT32 size
)
4365 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4367 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
4369 if (size
<= This
->format
.family_len
) return E_NOT_SUFFICIENT_BUFFER
;
4370 strcpyW(name
, This
->format
.family_name
);
4374 static DWRITE_FONT_WEIGHT WINAPI
dwritetextformat_layout_GetFontWeight(IDWriteTextFormat1
*iface
)
4376 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4377 TRACE("(%p)\n", This
);
4378 return This
->format
.weight
;
4381 static DWRITE_FONT_STYLE WINAPI
dwritetextformat_layout_GetFontStyle(IDWriteTextFormat1
*iface
)
4383 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4384 TRACE("(%p)\n", This
);
4385 return This
->format
.style
;
4388 static DWRITE_FONT_STRETCH WINAPI
dwritetextformat_layout_GetFontStretch(IDWriteTextFormat1
*iface
)
4390 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4391 TRACE("(%p)\n", This
);
4392 return This
->format
.stretch
;
4395 static FLOAT WINAPI
dwritetextformat_layout_GetFontSize(IDWriteTextFormat1
*iface
)
4397 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4398 TRACE("(%p)\n", This
);
4399 return This
->format
.fontsize
;
4402 static UINT32 WINAPI
dwritetextformat_layout_GetLocaleNameLength(IDWriteTextFormat1
*iface
)
4404 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4405 TRACE("(%p)\n", This
);
4406 return This
->format
.locale_len
;
4409 static HRESULT WINAPI
dwritetextformat_layout_GetLocaleName(IDWriteTextFormat1
*iface
, WCHAR
*name
, UINT32 size
)
4411 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4413 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
4415 if (size
<= This
->format
.locale_len
) return E_NOT_SUFFICIENT_BUFFER
;
4416 strcpyW(name
, This
->format
.locale
);
4420 static HRESULT WINAPI
dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat1
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
4422 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4423 FIXME("(%p)->(%d): stub\n", This
, orientation
);
4427 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat1
*iface
)
4429 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4430 FIXME("(%p): stub\n", This
);
4431 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
4434 static HRESULT WINAPI
dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat1
*iface
, BOOL lastline_wrapping_enabled
)
4436 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4438 TRACE("(%p)->(%d)\n", This
, lastline_wrapping_enabled
);
4440 This
->format
.last_line_wrapping
= !!lastline_wrapping_enabled
;
4444 static BOOL WINAPI
dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat1
*iface
)
4446 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4447 TRACE("(%p)\n", This
);
4448 return This
->format
.last_line_wrapping
;
4451 static HRESULT WINAPI
dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat1
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
4453 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4454 TRACE("(%p)->(%d)\n", This
, alignment
);
4455 return format_set_optical_alignment(&This
->format
, alignment
);
4458 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat1
*iface
)
4460 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4461 TRACE("(%p)\n", This
);
4462 return This
->format
.optical_alignment
;
4465 static HRESULT WINAPI
dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat1
*iface
, IDWriteFontFallback
*fallback
)
4467 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4468 TRACE("(%p)->(%p)\n", This
, fallback
);
4469 return IDWriteTextLayout3_SetFontFallback(&This
->IDWriteTextLayout3_iface
, fallback
);
4472 static HRESULT WINAPI
dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat1
*iface
, IDWriteFontFallback
**fallback
)
4474 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4475 TRACE("(%p)->(%p)\n", This
, fallback
);
4476 return IDWriteTextLayout3_GetFontFallback(&This
->IDWriteTextLayout3_iface
, fallback
);
4479 static const IDWriteTextFormat1Vtbl dwritetextformat1_layout_vtbl
= {
4480 dwritetextformat_layout_QueryInterface
,
4481 dwritetextformat_layout_AddRef
,
4482 dwritetextformat_layout_Release
,
4483 dwritetextformat_layout_SetTextAlignment
,
4484 dwritetextformat_layout_SetParagraphAlignment
,
4485 dwritetextformat_layout_SetWordWrapping
,
4486 dwritetextformat_layout_SetReadingDirection
,
4487 dwritetextformat_layout_SetFlowDirection
,
4488 dwritetextformat_layout_SetIncrementalTabStop
,
4489 dwritetextformat_layout_SetTrimming
,
4490 dwritetextformat_layout_SetLineSpacing
,
4491 dwritetextformat_layout_GetTextAlignment
,
4492 dwritetextformat_layout_GetParagraphAlignment
,
4493 dwritetextformat_layout_GetWordWrapping
,
4494 dwritetextformat_layout_GetReadingDirection
,
4495 dwritetextformat_layout_GetFlowDirection
,
4496 dwritetextformat_layout_GetIncrementalTabStop
,
4497 dwritetextformat_layout_GetTrimming
,
4498 dwritetextformat_layout_GetLineSpacing
,
4499 dwritetextformat_layout_GetFontCollection
,
4500 dwritetextformat_layout_GetFontFamilyNameLength
,
4501 dwritetextformat_layout_GetFontFamilyName
,
4502 dwritetextformat_layout_GetFontWeight
,
4503 dwritetextformat_layout_GetFontStyle
,
4504 dwritetextformat_layout_GetFontStretch
,
4505 dwritetextformat_layout_GetFontSize
,
4506 dwritetextformat_layout_GetLocaleNameLength
,
4507 dwritetextformat_layout_GetLocaleName
,
4508 dwritetextformat1_layout_SetVerticalGlyphOrientation
,
4509 dwritetextformat1_layout_GetVerticalGlyphOrientation
,
4510 dwritetextformat1_layout_SetLastLineWrapping
,
4511 dwritetextformat1_layout_GetLastLineWrapping
,
4512 dwritetextformat1_layout_SetOpticalAlignment
,
4513 dwritetextformat1_layout_GetOpticalAlignment
,
4514 dwritetextformat1_layout_SetFontFallback
,
4515 dwritetextformat1_layout_GetFontFallback
,
4518 static HRESULT WINAPI
dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink1
*iface
,
4519 REFIID riid
, void **obj
)
4521 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSink1
) ||
4522 IsEqualIID(riid
, &IID_IDWriteTextAnalysisSink
) ||
4523 IsEqualIID(riid
, &IID_IUnknown
))
4526 IDWriteTextAnalysisSink1_AddRef(iface
);
4531 return E_NOINTERFACE
;
4534 static ULONG WINAPI
dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink1
*iface
)
4536 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4537 return IDWriteTextLayout3_AddRef(&layout
->IDWriteTextLayout3_iface
);
4540 static ULONG WINAPI
dwritetextlayout_sink_Release(IDWriteTextAnalysisSink1
*iface
)
4542 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4543 return IDWriteTextLayout3_Release(&layout
->IDWriteTextLayout3_iface
);
4546 static HRESULT WINAPI
dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink1
*iface
,
4547 UINT32 position
, UINT32 length
, DWRITE_SCRIPT_ANALYSIS
const* sa
)
4549 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4550 struct layout_run
*run
;
4552 TRACE("[%u,%u) script=%u:%s\n", position
, position
+ length
, sa
->script
, debugstr_sa_script(sa
->script
));
4554 run
= alloc_layout_run(LAYOUT_RUN_REGULAR
, position
);
4556 return E_OUTOFMEMORY
;
4558 run
->u
.regular
.descr
.string
= &layout
->str
[position
];
4559 run
->u
.regular
.descr
.stringLength
= length
;
4560 run
->u
.regular
.descr
.textPosition
= position
;
4561 run
->u
.regular
.sa
= *sa
;
4562 list_add_tail(&layout
->runs
, &run
->entry
);
4566 static HRESULT WINAPI
dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink1
*iface
,
4567 UINT32 position
, UINT32 length
, DWRITE_LINE_BREAKPOINT
const* breakpoints
)
4569 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4571 if (position
+ length
> layout
->len
)
4574 memcpy(&layout
->nominal_breakpoints
[position
], breakpoints
, length
*sizeof(DWRITE_LINE_BREAKPOINT
));
4578 static HRESULT WINAPI
dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink1
*iface
, UINT32 position
,
4579 UINT32 length
, UINT8 explicitLevel
, UINT8 resolvedLevel
)
4581 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4582 struct layout_run
*cur_run
;
4584 TRACE("[%u,%u) %u %u\n", position
, position
+ length
, explicitLevel
, resolvedLevel
);
4586 LIST_FOR_EACH_ENTRY(cur_run
, &layout
->runs
, struct layout_run
, entry
) {
4587 struct regular_layout_run
*cur
= &cur_run
->u
.regular
;
4588 struct layout_run
*run
;
4590 if (cur_run
->kind
== LAYOUT_RUN_INLINE
)
4593 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
4594 if (position
< cur
->descr
.textPosition
|| position
>= cur
->descr
.textPosition
+ cur
->descr
.stringLength
)
4597 /* full hit - just set run level */
4598 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
== length
) {
4599 cur
->run
.bidiLevel
= resolvedLevel
;
4603 /* current run is fully covered, move to next one */
4604 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
< length
) {
4605 cur
->run
.bidiLevel
= resolvedLevel
;
4606 position
+= cur
->descr
.stringLength
;
4607 length
-= cur
->descr
.stringLength
;
4611 /* all fully covered runs are processed at this point, reuse existing run for remaining
4612 reported bidi range and add another run for the rest of original one */
4614 run
= alloc_layout_run(LAYOUT_RUN_REGULAR
, position
+ length
);
4616 return E_OUTOFMEMORY
;
4619 run
->u
.regular
.descr
.textPosition
= position
+ length
;
4620 run
->u
.regular
.descr
.stringLength
= cur
->descr
.stringLength
- length
;
4621 run
->u
.regular
.descr
.string
= &layout
->str
[position
+ length
];
4623 /* reduce existing run */
4624 cur
->run
.bidiLevel
= resolvedLevel
;
4625 cur
->descr
.stringLength
= length
;
4627 list_add_after(&cur_run
->entry
, &run
->entry
);
4634 static HRESULT WINAPI
dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink1
*iface
,
4635 UINT32 position
, UINT32 length
, IDWriteNumberSubstitution
* substitution
)
4640 static HRESULT WINAPI
dwritetextlayout_sink_SetGlyphOrientation(IDWriteTextAnalysisSink1
*iface
,
4641 UINT32 position
, UINT32 length
, DWRITE_GLYPH_ORIENTATION_ANGLE angle
, UINT8 adjusted_bidi_level
,
4642 BOOL is_sideways
, BOOL is_rtl
)
4647 static const IDWriteTextAnalysisSink1Vtbl dwritetextlayoutsinkvtbl
= {
4648 dwritetextlayout_sink_QueryInterface
,
4649 dwritetextlayout_sink_AddRef
,
4650 dwritetextlayout_sink_Release
,
4651 dwritetextlayout_sink_SetScriptAnalysis
,
4652 dwritetextlayout_sink_SetLineBreakpoints
,
4653 dwritetextlayout_sink_SetBidiLevel
,
4654 dwritetextlayout_sink_SetNumberSubstitution
,
4655 dwritetextlayout_sink_SetGlyphOrientation
4658 static HRESULT WINAPI
dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource1
*iface
,
4659 REFIID riid
, void **obj
)
4661 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSource1
) ||
4662 IsEqualIID(riid
, &IID_IDWriteTextAnalysisSource
) ||
4663 IsEqualIID(riid
, &IID_IUnknown
))
4666 IDWriteTextAnalysisSource1_AddRef(iface
);
4671 return E_NOINTERFACE
;
4674 static ULONG WINAPI
dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource1
*iface
)
4676 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4677 return IDWriteTextLayout3_AddRef(&layout
->IDWriteTextLayout3_iface
);
4680 static ULONG WINAPI
dwritetextlayout_source_Release(IDWriteTextAnalysisSource1
*iface
)
4682 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4683 return IDWriteTextLayout3_Release(&layout
->IDWriteTextLayout3_iface
);
4686 static HRESULT WINAPI
dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource1
*iface
,
4687 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
4689 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4691 TRACE("(%p)->(%u %p %p)\n", layout
, position
, text
, text_len
);
4693 if (position
< layout
->len
) {
4694 *text
= &layout
->str
[position
];
4695 *text_len
= layout
->len
- position
;
4705 static HRESULT WINAPI
dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource1
*iface
,
4706 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
4708 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4710 TRACE("(%p)->(%u %p %p)\n", layout
, position
, text
, text_len
);
4712 if (position
> 0 && position
< layout
->len
) {
4713 *text
= layout
->str
;
4714 *text_len
= position
;
4724 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource1
*iface
)
4726 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4727 return IDWriteTextLayout3_GetReadingDirection(&layout
->IDWriteTextLayout3_iface
);
4730 static HRESULT WINAPI
dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource1
*iface
,
4731 UINT32 position
, UINT32
* text_len
, WCHAR
const** locale
)
4733 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4734 struct layout_range
*range
= get_layout_range_by_pos(layout
, position
);
4736 if (position
< layout
->len
) {
4737 struct layout_range
*next
;
4739 *locale
= range
->locale
;
4740 *text_len
= range
->h
.range
.length
- position
;
4742 next
= LIST_ENTRY(list_next(&layout
->ranges
, &range
->h
.entry
), struct layout_range
, h
.entry
);
4743 while (next
&& next
->h
.range
.startPosition
< layout
->len
&& !strcmpW(range
->locale
, next
->locale
)) {
4744 *text_len
+= next
->h
.range
.length
;
4745 next
= LIST_ENTRY(list_next(&layout
->ranges
, &next
->h
.entry
), struct layout_range
, h
.entry
);
4748 *text_len
= min(*text_len
, layout
->len
- position
);
4758 static HRESULT WINAPI
dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource1
*iface
,
4759 UINT32 position
, UINT32
* text_len
, IDWriteNumberSubstitution
**substitution
)
4761 FIXME("%u %p %p: stub\n", position
, text_len
, substitution
);
4765 static HRESULT WINAPI
dwritetextlayout_source_GetVerticalGlyphOrientation(IDWriteTextAnalysisSource1
*iface
,
4766 UINT32 position
, UINT32
*length
, DWRITE_VERTICAL_GLYPH_ORIENTATION
*orientation
, UINT8
*bidi_level
)
4768 FIXME("%u %p %p %p: stub\n", position
, length
, orientation
, bidi_level
);
4772 static const IDWriteTextAnalysisSource1Vtbl dwritetextlayoutsourcevtbl
= {
4773 dwritetextlayout_source_QueryInterface
,
4774 dwritetextlayout_source_AddRef
,
4775 dwritetextlayout_source_Release
,
4776 dwritetextlayout_source_GetTextAtPosition
,
4777 dwritetextlayout_source_GetTextBeforePosition
,
4778 dwritetextlayout_source_GetParagraphReadingDirection
,
4779 dwritetextlayout_source_GetLocaleName
,
4780 dwritetextlayout_source_GetNumberSubstitution
,
4781 dwritetextlayout_source_GetVerticalGlyphOrientation
4784 static HRESULT
layout_format_from_textformat(struct dwrite_textlayout
*layout
, IDWriteTextFormat
*format
)
4786 struct dwrite_textformat
*textformat
;
4787 IDWriteTextFormat1
*format1
;
4791 if ((textformat
= unsafe_impl_from_IDWriteTextFormat(format
))) {
4792 layout
->format
= textformat
->format
;
4794 layout
->format
.locale
= heap_strdupW(textformat
->format
.locale
);
4795 layout
->format
.family_name
= heap_strdupW(textformat
->format
.family_name
);
4796 if (!layout
->format
.locale
|| !layout
->format
.family_name
)
4798 heap_free(layout
->format
.locale
);
4799 heap_free(layout
->format
.family_name
);
4800 return E_OUTOFMEMORY
;
4803 if (layout
->format
.trimmingsign
)
4804 IDWriteInlineObject_AddRef(layout
->format
.trimmingsign
);
4805 if (layout
->format
.collection
)
4806 IDWriteFontCollection_AddRef(layout
->format
.collection
);
4807 if (layout
->format
.fallback
)
4808 IDWriteFontFallback_AddRef(layout
->format
.fallback
);
4813 layout
->format
.weight
= IDWriteTextFormat_GetFontWeight(format
);
4814 layout
->format
.style
= IDWriteTextFormat_GetFontStyle(format
);
4815 layout
->format
.stretch
= IDWriteTextFormat_GetFontStretch(format
);
4816 layout
->format
.fontsize
= IDWriteTextFormat_GetFontSize(format
);
4817 layout
->format
.textalignment
= IDWriteTextFormat_GetTextAlignment(format
);
4818 layout
->format
.paralign
= IDWriteTextFormat_GetParagraphAlignment(format
);
4819 layout
->format
.wrapping
= IDWriteTextFormat_GetWordWrapping(format
);
4820 layout
->format
.readingdir
= IDWriteTextFormat_GetReadingDirection(format
);
4821 layout
->format
.flow
= IDWriteTextFormat_GetFlowDirection(format
);
4822 layout
->format
.fallback
= NULL
;
4823 layout
->format
.spacing
.leadingBefore
= 0.0f
;
4824 layout
->format
.spacing
.fontLineGapUsage
= DWRITE_FONT_LINE_GAP_USAGE_DEFAULT
;
4825 hr
= IDWriteTextFormat_GetLineSpacing(format
, &layout
->format
.spacing
.method
,
4826 &layout
->format
.spacing
.height
, &layout
->format
.spacing
.baseline
);
4830 hr
= IDWriteTextFormat_GetTrimming(format
, &layout
->format
.trimming
, &layout
->format
.trimmingsign
);
4834 /* locale name and length */
4835 len
= IDWriteTextFormat_GetLocaleNameLength(format
);
4836 layout
->format
.locale
= heap_alloc((len
+1)*sizeof(WCHAR
));
4837 if (!layout
->format
.locale
)
4838 return E_OUTOFMEMORY
;
4840 hr
= IDWriteTextFormat_GetLocaleName(format
, layout
->format
.locale
, len
+1);
4843 layout
->format
.locale_len
= len
;
4845 /* font family name and length */
4846 len
= IDWriteTextFormat_GetFontFamilyNameLength(format
);
4847 layout
->format
.family_name
= heap_alloc((len
+1)*sizeof(WCHAR
));
4848 if (!layout
->format
.family_name
)
4849 return E_OUTOFMEMORY
;
4851 hr
= IDWriteTextFormat_GetFontFamilyName(format
, layout
->format
.family_name
, len
+1);
4854 layout
->format
.family_len
= len
;
4856 hr
= IDWriteTextFormat_QueryInterface(format
, &IID_IDWriteTextFormat1
, (void**)&format1
);
4858 IDWriteTextFormat2
*format2
;
4860 layout
->format
.vertical_orientation
= IDWriteTextFormat1_GetVerticalGlyphOrientation(format1
);
4861 layout
->format
.optical_alignment
= IDWriteTextFormat1_GetOpticalAlignment(format1
);
4862 IDWriteTextFormat1_GetFontFallback(format1
, &layout
->format
.fallback
);
4864 if (IDWriteTextFormat1_QueryInterface(format1
, &IID_IDWriteTextFormat2
, (void**)&format2
) == S_OK
) {
4865 IDWriteTextFormat2_GetLineSpacing(format2
, &layout
->format
.spacing
);
4866 IDWriteTextFormat2_Release(format2
);
4869 IDWriteTextFormat1_Release(format1
);
4872 layout
->format
.vertical_orientation
= DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
4873 layout
->format
.optical_alignment
= DWRITE_OPTICAL_ALIGNMENT_NONE
;
4876 return IDWriteTextFormat_GetFontCollection(format
, &layout
->format
.collection
);
4879 static HRESULT
init_textlayout(const struct textlayout_desc
*desc
, struct dwrite_textlayout
*layout
)
4881 struct layout_range_header
*range
, *strike
, *underline
, *effect
, *spacing
, *typography
;
4882 static const DWRITE_TEXT_RANGE r
= { 0, ~0u };
4885 layout
->IDWriteTextLayout3_iface
.lpVtbl
= &dwritetextlayoutvtbl
;
4886 layout
->IDWriteTextFormat1_iface
.lpVtbl
= &dwritetextformat1_layout_vtbl
;
4887 layout
->IDWriteTextAnalysisSink1_iface
.lpVtbl
= &dwritetextlayoutsinkvtbl
;
4888 layout
->IDWriteTextAnalysisSource1_iface
.lpVtbl
= &dwritetextlayoutsourcevtbl
;
4890 layout
->len
= desc
->length
;
4891 layout
->recompute
= RECOMPUTE_EVERYTHING
;
4892 layout
->nominal_breakpoints
= NULL
;
4893 layout
->actual_breakpoints
= NULL
;
4894 layout
->cluster_count
= 0;
4895 layout
->clustermetrics
= NULL
;
4896 layout
->clusters
= NULL
;
4897 layout
->linemetrics
= NULL
;
4898 layout
->lines
= NULL
;
4899 layout
->line_alloc
= 0;
4900 layout
->minwidth
= 0.0f
;
4901 list_init(&layout
->eruns
);
4902 list_init(&layout
->inlineobjects
);
4903 list_init(&layout
->underlines
);
4904 list_init(&layout
->strikethrough
);
4905 list_init(&layout
->runs
);
4906 list_init(&layout
->ranges
);
4907 list_init(&layout
->strike_ranges
);
4908 list_init(&layout
->underline_ranges
);
4909 list_init(&layout
->effects
);
4910 list_init(&layout
->spacing
);
4911 list_init(&layout
->typographies
);
4912 memset(&layout
->format
, 0, sizeof(layout
->format
));
4913 memset(&layout
->metrics
, 0, sizeof(layout
->metrics
));
4914 layout
->metrics
.layoutWidth
= desc
->max_width
;
4915 layout
->metrics
.layoutHeight
= desc
->max_height
;
4916 layout
->measuringmode
= DWRITE_MEASURING_MODE_NATURAL
;
4918 layout
->ppdip
= 0.0f
;
4919 memset(&layout
->transform
, 0, sizeof(layout
->transform
));
4921 layout
->str
= heap_strdupnW(desc
->string
, desc
->length
);
4922 if (desc
->length
&& !layout
->str
) {
4927 hr
= layout_format_from_textformat(layout
, desc
->format
);
4931 range
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_REGULAR
);
4932 strike
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_STRIKETHROUGH
);
4933 underline
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_UNDERLINE
);
4934 effect
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_EFFECT
);
4935 spacing
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_SPACING
);
4936 typography
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_TYPOGRAPHY
);
4937 if (!range
|| !strike
|| !effect
|| !spacing
|| !typography
|| !underline
) {
4938 free_layout_range(range
);
4939 free_layout_range(strike
);
4940 free_layout_range(underline
);
4941 free_layout_range(effect
);
4942 free_layout_range(spacing
);
4943 free_layout_range(typography
);
4948 if (desc
->is_gdi_compatible
)
4949 layout
->measuringmode
= desc
->use_gdi_natural
? DWRITE_MEASURING_MODE_GDI_NATURAL
: DWRITE_MEASURING_MODE_GDI_CLASSIC
;
4951 layout
->measuringmode
= DWRITE_MEASURING_MODE_NATURAL
;
4952 layout
->ppdip
= desc
->ppdip
;
4953 layout
->transform
= desc
->transform
? *desc
->transform
: identity
;
4955 layout
->factory
= desc
->factory
;
4956 IDWriteFactory5_AddRef(layout
->factory
);
4957 list_add_head(&layout
->ranges
, &range
->entry
);
4958 list_add_head(&layout
->strike_ranges
, &strike
->entry
);
4959 list_add_head(&layout
->underline_ranges
, &underline
->entry
);
4960 list_add_head(&layout
->effects
, &effect
->entry
);
4961 list_add_head(&layout
->spacing
, &spacing
->entry
);
4962 list_add_head(&layout
->typographies
, &typography
->entry
);
4966 IDWriteTextLayout3_Release(&layout
->IDWriteTextLayout3_iface
);
4970 HRESULT
create_textlayout(const struct textlayout_desc
*desc
, IDWriteTextLayout
**ret
)
4972 struct dwrite_textlayout
*layout
;
4977 if (!desc
->format
|| !desc
->string
)
4978 return E_INVALIDARG
;
4980 layout
= heap_alloc(sizeof(struct dwrite_textlayout
));
4981 if (!layout
) return E_OUTOFMEMORY
;
4983 hr
= init_textlayout(desc
, layout
);
4985 *ret
= (IDWriteTextLayout
*)&layout
->IDWriteTextLayout3_iface
;
4990 static HRESULT WINAPI
dwritetrimmingsign_QueryInterface(IDWriteInlineObject
*iface
, REFIID riid
, void **obj
)
4992 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
4994 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
4996 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDWriteInlineObject
)) {
4998 IDWriteInlineObject_AddRef(iface
);
5003 return E_NOINTERFACE
;
5006 static ULONG WINAPI
dwritetrimmingsign_AddRef(IDWriteInlineObject
*iface
)
5008 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5009 ULONG ref
= InterlockedIncrement(&This
->ref
);
5010 TRACE("(%p)->(%d)\n", This
, ref
);
5014 static ULONG WINAPI
dwritetrimmingsign_Release(IDWriteInlineObject
*iface
)
5016 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5017 ULONG ref
= InterlockedDecrement(&This
->ref
);
5019 TRACE("(%p)->(%d)\n", This
, ref
);
5022 IDWriteTextLayout_Release(This
->layout
);
5029 static HRESULT WINAPI
dwritetrimmingsign_Draw(IDWriteInlineObject
*iface
, void *context
, IDWriteTextRenderer
*renderer
,
5030 FLOAT originX
, FLOAT originY
, BOOL is_sideways
, BOOL is_rtl
, IUnknown
*effect
)
5032 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5033 DWRITE_TEXT_METRICS metrics
;
5034 DWRITE_LINE_METRICS line
;
5037 TRACE("(%p)->(%p %p %.2f %.2f %d %d %p)\n", This
, context
, renderer
, originX
, originY
, is_sideways
, is_rtl
, effect
);
5039 IDWriteTextLayout_GetLineMetrics(This
->layout
, &line
, 1, &line_count
);
5040 IDWriteTextLayout_GetMetrics(This
->layout
, &metrics
);
5041 return IDWriteTextLayout_Draw(This
->layout
, context
, renderer
, originX
, originY
- line
.baseline
);
5044 static HRESULT WINAPI
dwritetrimmingsign_GetMetrics(IDWriteInlineObject
*iface
, DWRITE_INLINE_OBJECT_METRICS
*ret
)
5046 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5047 DWRITE_TEXT_METRICS metrics
;
5050 TRACE("(%p)->(%p)\n", This
, ret
);
5052 hr
= IDWriteTextLayout_GetMetrics(This
->layout
, &metrics
);
5054 memset(ret
, 0, sizeof(*ret
));
5058 ret
->width
= metrics
.width
;
5060 ret
->baseline
= 0.0f
;
5061 ret
->supportsSideways
= FALSE
;
5065 static HRESULT WINAPI
dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject
*iface
, DWRITE_OVERHANG_METRICS
*overhangs
)
5067 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5068 TRACE("(%p)->(%p)\n", This
, overhangs
);
5069 return IDWriteTextLayout_GetOverhangMetrics(This
->layout
, overhangs
);
5072 static HRESULT WINAPI
dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject
*iface
, DWRITE_BREAK_CONDITION
*before
,
5073 DWRITE_BREAK_CONDITION
*after
)
5075 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5077 TRACE("(%p)->(%p %p)\n", This
, before
, after
);
5079 *before
= *after
= DWRITE_BREAK_CONDITION_NEUTRAL
;
5083 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl
= {
5084 dwritetrimmingsign_QueryInterface
,
5085 dwritetrimmingsign_AddRef
,
5086 dwritetrimmingsign_Release
,
5087 dwritetrimmingsign_Draw
,
5088 dwritetrimmingsign_GetMetrics
,
5089 dwritetrimmingsign_GetOverhangMetrics
,
5090 dwritetrimmingsign_GetBreakConditions
5093 static inline BOOL
is_reading_direction_horz(DWRITE_READING_DIRECTION direction
)
5095 return (direction
== DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
) ||
5096 (direction
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
);
5099 static inline BOOL
is_reading_direction_vert(DWRITE_READING_DIRECTION direction
)
5101 return (direction
== DWRITE_READING_DIRECTION_TOP_TO_BOTTOM
) ||
5102 (direction
== DWRITE_READING_DIRECTION_BOTTOM_TO_TOP
);
5105 static inline BOOL
is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction
)
5107 return (direction
== DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT
) ||
5108 (direction
== DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT
);
5111 static inline BOOL
is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction
)
5113 return (direction
== DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM
) ||
5114 (direction
== DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP
);
5117 HRESULT
create_trimmingsign(IDWriteFactory5
*factory
, IDWriteTextFormat
*format
, IDWriteInlineObject
**sign
)
5119 static const WCHAR ellipsisW
= 0x2026;
5120 struct dwrite_trimmingsign
*This
;
5121 DWRITE_READING_DIRECTION reading
;
5122 DWRITE_FLOW_DIRECTION flow
;
5127 /* Validate reading/flow direction here, layout creation won't complain about
5128 invalid combinations. */
5129 reading
= IDWriteTextFormat_GetReadingDirection(format
);
5130 flow
= IDWriteTextFormat_GetFlowDirection(format
);
5132 if ((is_reading_direction_horz(reading
) && is_flow_direction_horz(flow
)) ||
5133 (is_reading_direction_vert(reading
) && is_flow_direction_vert(flow
)))
5134 return DWRITE_E_FLOWDIRECTIONCONFLICTS
;
5136 This
= heap_alloc(sizeof(*This
));
5138 return E_OUTOFMEMORY
;
5140 This
->IDWriteInlineObject_iface
.lpVtbl
= &dwritetrimmingsignvtbl
;
5143 hr
= IDWriteFactory5_CreateTextLayout(factory
, &ellipsisW
, 1, format
, 0.0f
, 0.0f
, &This
->layout
);
5149 IDWriteTextLayout_SetWordWrapping(This
->layout
, DWRITE_WORD_WRAPPING_NO_WRAP
);
5150 IDWriteTextLayout_SetParagraphAlignment(This
->layout
, DWRITE_PARAGRAPH_ALIGNMENT_NEAR
);
5151 *sign
= &This
->IDWriteInlineObject_iface
;
5156 static HRESULT WINAPI
dwritetextformat_QueryInterface(IDWriteTextFormat2
*iface
, REFIID riid
, void **obj
)
5158 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5160 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
5162 if (IsEqualIID(riid
, &IID_IDWriteTextFormat2
) ||
5163 IsEqualIID(riid
, &IID_IDWriteTextFormat1
) ||
5164 IsEqualIID(riid
, &IID_IDWriteTextFormat
) ||
5165 IsEqualIID(riid
, &IID_IUnknown
))
5168 IDWriteTextFormat2_AddRef(iface
);
5174 return E_NOINTERFACE
;
5177 static ULONG WINAPI
dwritetextformat_AddRef(IDWriteTextFormat2
*iface
)
5179 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5180 ULONG ref
= InterlockedIncrement(&This
->ref
);
5181 TRACE("(%p)->(%d)\n", This
, ref
);
5185 static ULONG WINAPI
dwritetextformat_Release(IDWriteTextFormat2
*iface
)
5187 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5188 ULONG ref
= InterlockedDecrement(&This
->ref
);
5190 TRACE("(%p)->(%d)\n", This
, ref
);
5194 release_format_data(&This
->format
);
5201 static HRESULT WINAPI
dwritetextformat_SetTextAlignment(IDWriteTextFormat2
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
5203 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5204 TRACE("(%p)->(%d)\n", This
, alignment
);
5205 return format_set_textalignment(&This
->format
, alignment
, NULL
);
5208 static HRESULT WINAPI
dwritetextformat_SetParagraphAlignment(IDWriteTextFormat2
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
5210 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5211 TRACE("(%p)->(%d)\n", This
, alignment
);
5212 return format_set_paralignment(&This
->format
, alignment
, NULL
);
5215 static HRESULT WINAPI
dwritetextformat_SetWordWrapping(IDWriteTextFormat2
*iface
, DWRITE_WORD_WRAPPING wrapping
)
5217 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5218 TRACE("(%p)->(%d)\n", This
, wrapping
);
5219 return format_set_wordwrapping(&This
->format
, wrapping
, NULL
);
5222 static HRESULT WINAPI
dwritetextformat_SetReadingDirection(IDWriteTextFormat2
*iface
, DWRITE_READING_DIRECTION direction
)
5224 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5225 TRACE("(%p)->(%d)\n", This
, direction
);
5226 return format_set_readingdirection(&This
->format
, direction
, NULL
);
5229 static HRESULT WINAPI
dwritetextformat_SetFlowDirection(IDWriteTextFormat2
*iface
, DWRITE_FLOW_DIRECTION direction
)
5231 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5232 TRACE("(%p)->(%d)\n", This
, direction
);
5233 return format_set_flowdirection(&This
->format
, direction
, NULL
);
5236 static HRESULT WINAPI
dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat2
*iface
, FLOAT tabstop
)
5238 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5239 FIXME("(%p)->(%f): stub\n", This
, tabstop
);
5243 static HRESULT WINAPI
dwritetextformat_SetTrimming(IDWriteTextFormat2
*iface
, DWRITE_TRIMMING
const *trimming
,
5244 IDWriteInlineObject
*trimming_sign
)
5246 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5247 TRACE("(%p)->(%p %p)\n", This
, trimming
, trimming_sign
);
5248 return format_set_trimming(&This
->format
, trimming
, trimming_sign
, NULL
);
5251 static HRESULT WINAPI
dwritetextformat_SetLineSpacing(IDWriteTextFormat2
*iface
, DWRITE_LINE_SPACING_METHOD method
,
5252 FLOAT height
, FLOAT baseline
)
5254 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5255 DWRITE_LINE_SPACING spacing
;
5257 TRACE("(%p)->(%d %f %f)\n", This
, method
, height
, baseline
);
5259 spacing
= This
->format
.spacing
;
5260 spacing
.method
= method
;
5261 spacing
.height
= height
;
5262 spacing
.baseline
= baseline
;
5264 return format_set_linespacing(&This
->format
, &spacing
, NULL
);
5267 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextformat_GetTextAlignment(IDWriteTextFormat2
*iface
)
5269 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5270 TRACE("(%p)\n", This
);
5271 return This
->format
.textalignment
;
5274 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextformat_GetParagraphAlignment(IDWriteTextFormat2
*iface
)
5276 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5277 TRACE("(%p)\n", This
);
5278 return This
->format
.paralign
;
5281 static DWRITE_WORD_WRAPPING WINAPI
dwritetextformat_GetWordWrapping(IDWriteTextFormat2
*iface
)
5283 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5284 TRACE("(%p)\n", This
);
5285 return This
->format
.wrapping
;
5288 static DWRITE_READING_DIRECTION WINAPI
dwritetextformat_GetReadingDirection(IDWriteTextFormat2
*iface
)
5290 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5291 TRACE("(%p)\n", This
);
5292 return This
->format
.readingdir
;
5295 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextformat_GetFlowDirection(IDWriteTextFormat2
*iface
)
5297 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5298 TRACE("(%p)\n", This
);
5299 return This
->format
.flow
;
5302 static FLOAT WINAPI
dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat2
*iface
)
5304 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5305 FIXME("(%p): stub\n", This
);
5309 static HRESULT WINAPI
dwritetextformat_GetTrimming(IDWriteTextFormat2
*iface
, DWRITE_TRIMMING
*options
,
5310 IDWriteInlineObject
**trimming_sign
)
5312 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5313 TRACE("(%p)->(%p %p)\n", This
, options
, trimming_sign
);
5315 *options
= This
->format
.trimming
;
5316 if ((*trimming_sign
= This
->format
.trimmingsign
))
5317 IDWriteInlineObject_AddRef(*trimming_sign
);
5322 static HRESULT WINAPI
dwritetextformat_GetLineSpacing(IDWriteTextFormat2
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
5323 FLOAT
*spacing
, FLOAT
*baseline
)
5325 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5326 TRACE("(%p)->(%p %p %p)\n", This
, method
, spacing
, baseline
);
5328 *method
= This
->format
.spacing
.method
;
5329 *spacing
= This
->format
.spacing
.height
;
5330 *baseline
= This
->format
.spacing
.baseline
;
5334 static HRESULT WINAPI
dwritetextformat_GetFontCollection(IDWriteTextFormat2
*iface
, IDWriteFontCollection
**collection
)
5336 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5338 TRACE("(%p)->(%p)\n", This
, collection
);
5340 *collection
= This
->format
.collection
;
5341 IDWriteFontCollection_AddRef(*collection
);
5346 static UINT32 WINAPI
dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat2
*iface
)
5348 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5349 TRACE("(%p)\n", This
);
5350 return This
->format
.family_len
;
5353 static HRESULT WINAPI
dwritetextformat_GetFontFamilyName(IDWriteTextFormat2
*iface
, WCHAR
*name
, UINT32 size
)
5355 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5357 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
5359 if (size
<= This
->format
.family_len
) return E_NOT_SUFFICIENT_BUFFER
;
5360 strcpyW(name
, This
->format
.family_name
);
5364 static DWRITE_FONT_WEIGHT WINAPI
dwritetextformat_GetFontWeight(IDWriteTextFormat2
*iface
)
5366 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5367 TRACE("(%p)\n", This
);
5368 return This
->format
.weight
;
5371 static DWRITE_FONT_STYLE WINAPI
dwritetextformat_GetFontStyle(IDWriteTextFormat2
*iface
)
5373 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5374 TRACE("(%p)\n", This
);
5375 return This
->format
.style
;
5378 static DWRITE_FONT_STRETCH WINAPI
dwritetextformat_GetFontStretch(IDWriteTextFormat2
*iface
)
5380 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5381 TRACE("(%p)\n", This
);
5382 return This
->format
.stretch
;
5385 static FLOAT WINAPI
dwritetextformat_GetFontSize(IDWriteTextFormat2
*iface
)
5387 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5388 TRACE("(%p)\n", This
);
5389 return This
->format
.fontsize
;
5392 static UINT32 WINAPI
dwritetextformat_GetLocaleNameLength(IDWriteTextFormat2
*iface
)
5394 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5395 TRACE("(%p)\n", This
);
5396 return This
->format
.locale_len
;
5399 static HRESULT WINAPI
dwritetextformat_GetLocaleName(IDWriteTextFormat2
*iface
, WCHAR
*name
, UINT32 size
)
5401 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5403 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
5405 if (size
<= This
->format
.locale_len
) return E_NOT_SUFFICIENT_BUFFER
;
5406 strcpyW(name
, This
->format
.locale
);
5410 static HRESULT WINAPI
dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat2
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
5412 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5414 TRACE("(%p)->(%d)\n", This
, orientation
);
5416 if ((UINT32
)orientation
> DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED
)
5417 return E_INVALIDARG
;
5419 This
->format
.vertical_orientation
= orientation
;
5423 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat2
*iface
)
5425 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5426 TRACE("(%p)\n", This
);
5427 return This
->format
.vertical_orientation
;
5430 static HRESULT WINAPI
dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat2
*iface
, BOOL lastline_wrapping_enabled
)
5432 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5434 TRACE("(%p)->(%d)\n", This
, lastline_wrapping_enabled
);
5436 This
->format
.last_line_wrapping
= !!lastline_wrapping_enabled
;
5440 static BOOL WINAPI
dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat2
*iface
)
5442 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5443 TRACE("(%p)\n", This
);
5444 return This
->format
.last_line_wrapping
;
5447 static HRESULT WINAPI
dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat2
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
5449 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5450 TRACE("(%p)->(%d)\n", This
, alignment
);
5451 return format_set_optical_alignment(&This
->format
, alignment
);
5454 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat2
*iface
)
5456 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5457 TRACE("(%p)\n", This
);
5458 return This
->format
.optical_alignment
;
5461 static HRESULT WINAPI
dwritetextformat1_SetFontFallback(IDWriteTextFormat2
*iface
, IDWriteFontFallback
*fallback
)
5463 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5464 TRACE("(%p)->(%p)\n", This
, fallback
);
5465 return set_fontfallback_for_format(&This
->format
, fallback
);
5468 static HRESULT WINAPI
dwritetextformat1_GetFontFallback(IDWriteTextFormat2
*iface
, IDWriteFontFallback
**fallback
)
5470 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5471 TRACE("(%p)->(%p)\n", This
, fallback
);
5472 return get_fontfallback_from_format(&This
->format
, fallback
);
5475 static HRESULT WINAPI
dwritetextformat2_SetLineSpacing(IDWriteTextFormat2
*iface
, DWRITE_LINE_SPACING
const *spacing
)
5477 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5478 TRACE("(%p)->(%p)\n", This
, spacing
);
5479 return format_set_linespacing(&This
->format
, spacing
, NULL
);
5482 static HRESULT WINAPI
dwritetextformat2_GetLineSpacing(IDWriteTextFormat2
*iface
, DWRITE_LINE_SPACING
*spacing
)
5484 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5486 TRACE("(%p)->(%p)\n", This
, spacing
);
5488 *spacing
= This
->format
.spacing
;
5492 static const IDWriteTextFormat2Vtbl dwritetextformatvtbl
= {
5493 dwritetextformat_QueryInterface
,
5494 dwritetextformat_AddRef
,
5495 dwritetextformat_Release
,
5496 dwritetextformat_SetTextAlignment
,
5497 dwritetextformat_SetParagraphAlignment
,
5498 dwritetextformat_SetWordWrapping
,
5499 dwritetextformat_SetReadingDirection
,
5500 dwritetextformat_SetFlowDirection
,
5501 dwritetextformat_SetIncrementalTabStop
,
5502 dwritetextformat_SetTrimming
,
5503 dwritetextformat_SetLineSpacing
,
5504 dwritetextformat_GetTextAlignment
,
5505 dwritetextformat_GetParagraphAlignment
,
5506 dwritetextformat_GetWordWrapping
,
5507 dwritetextformat_GetReadingDirection
,
5508 dwritetextformat_GetFlowDirection
,
5509 dwritetextformat_GetIncrementalTabStop
,
5510 dwritetextformat_GetTrimming
,
5511 dwritetextformat_GetLineSpacing
,
5512 dwritetextformat_GetFontCollection
,
5513 dwritetextformat_GetFontFamilyNameLength
,
5514 dwritetextformat_GetFontFamilyName
,
5515 dwritetextformat_GetFontWeight
,
5516 dwritetextformat_GetFontStyle
,
5517 dwritetextformat_GetFontStretch
,
5518 dwritetextformat_GetFontSize
,
5519 dwritetextformat_GetLocaleNameLength
,
5520 dwritetextformat_GetLocaleName
,
5521 dwritetextformat1_SetVerticalGlyphOrientation
,
5522 dwritetextformat1_GetVerticalGlyphOrientation
,
5523 dwritetextformat1_SetLastLineWrapping
,
5524 dwritetextformat1_GetLastLineWrapping
,
5525 dwritetextformat1_SetOpticalAlignment
,
5526 dwritetextformat1_GetOpticalAlignment
,
5527 dwritetextformat1_SetFontFallback
,
5528 dwritetextformat1_GetFontFallback
,
5529 dwritetextformat2_SetLineSpacing
,
5530 dwritetextformat2_GetLineSpacing
5533 static struct dwrite_textformat
*unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat
*iface
)
5535 return (iface
->lpVtbl
== (IDWriteTextFormatVtbl
*)&dwritetextformatvtbl
) ?
5536 CONTAINING_RECORD(iface
, struct dwrite_textformat
, IDWriteTextFormat2_iface
) : NULL
;
5539 HRESULT
create_textformat(const WCHAR
*family_name
, IDWriteFontCollection
*collection
, DWRITE_FONT_WEIGHT weight
, DWRITE_FONT_STYLE style
,
5540 DWRITE_FONT_STRETCH stretch
, FLOAT size
, const WCHAR
*locale
, IDWriteTextFormat
**format
)
5542 struct dwrite_textformat
*This
;
5547 return E_INVALIDARG
;
5549 if (((UINT32
)weight
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
) ||
5550 ((UINT32
)stretch
> DWRITE_FONT_STRETCH_ULTRA_EXPANDED
) ||
5551 ((UINT32
)style
> DWRITE_FONT_STYLE_ITALIC
))
5552 return E_INVALIDARG
;
5554 This
= heap_alloc(sizeof(struct dwrite_textformat
));
5555 if (!This
) return E_OUTOFMEMORY
;
5557 This
->IDWriteTextFormat2_iface
.lpVtbl
= &dwritetextformatvtbl
;
5559 This
->format
.family_name
= heap_strdupW(family_name
);
5560 This
->format
.family_len
= strlenW(family_name
);
5561 This
->format
.locale
= heap_strdupW(locale
);
5562 This
->format
.locale_len
= strlenW(locale
);
5563 /* force locale name to lower case, layout will inherit this modified value */
5564 strlwrW(This
->format
.locale
);
5565 This
->format
.weight
= weight
;
5566 This
->format
.style
= style
;
5567 This
->format
.fontsize
= size
;
5568 This
->format
.stretch
= stretch
;
5569 This
->format
.textalignment
= DWRITE_TEXT_ALIGNMENT_LEADING
;
5570 This
->format
.optical_alignment
= DWRITE_OPTICAL_ALIGNMENT_NONE
;
5571 This
->format
.paralign
= DWRITE_PARAGRAPH_ALIGNMENT_NEAR
;
5572 This
->format
.wrapping
= DWRITE_WORD_WRAPPING_WRAP
;
5573 This
->format
.last_line_wrapping
= TRUE
;
5574 This
->format
.readingdir
= DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
;
5575 This
->format
.flow
= DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM
;
5576 This
->format
.spacing
.method
= DWRITE_LINE_SPACING_METHOD_DEFAULT
;
5577 This
->format
.spacing
.height
= 0.0f
;
5578 This
->format
.spacing
.baseline
= 0.0f
;
5579 This
->format
.spacing
.leadingBefore
= 0.0f
;
5580 This
->format
.spacing
.fontLineGapUsage
= DWRITE_FONT_LINE_GAP_USAGE_DEFAULT
;
5581 This
->format
.vertical_orientation
= DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
5582 This
->format
.trimming
.granularity
= DWRITE_TRIMMING_GRANULARITY_NONE
;
5583 This
->format
.trimming
.delimiter
= 0;
5584 This
->format
.trimming
.delimiterCount
= 0;
5585 This
->format
.trimmingsign
= NULL
;
5586 This
->format
.collection
= collection
;
5587 This
->format
.fallback
= NULL
;
5588 IDWriteFontCollection_AddRef(collection
);
5590 *format
= (IDWriteTextFormat
*)&This
->IDWriteTextFormat2_iface
;
5595 static HRESULT WINAPI
dwritetypography_QueryInterface(IDWriteTypography
*iface
, REFIID riid
, void **obj
)
5597 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5599 TRACE("(%p)->(%s %p)\n", typography
, debugstr_guid(riid
), obj
);
5601 if (IsEqualIID(riid
, &IID_IDWriteTypography
) || IsEqualIID(riid
, &IID_IUnknown
)) {
5603 IDWriteTypography_AddRef(iface
);
5609 return E_NOINTERFACE
;
5612 static ULONG WINAPI
dwritetypography_AddRef(IDWriteTypography
*iface
)
5614 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5615 ULONG ref
= InterlockedIncrement(&typography
->ref
);
5616 TRACE("(%p)->(%d)\n", typography
, ref
);
5620 static ULONG WINAPI
dwritetypography_Release(IDWriteTypography
*iface
)
5622 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5623 ULONG ref
= InterlockedDecrement(&typography
->ref
);
5625 TRACE("(%p)->(%d)\n", typography
, ref
);
5628 heap_free(typography
->features
);
5629 heap_free(typography
);
5635 static HRESULT WINAPI
dwritetypography_AddFontFeature(IDWriteTypography
*iface
, DWRITE_FONT_FEATURE feature
)
5637 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5639 TRACE("(%p)->(%x %u)\n", typography
, feature
.nameTag
, feature
.parameter
);
5641 if (typography
->count
== typography
->allocated
) {
5642 DWRITE_FONT_FEATURE
*ptr
= heap_realloc(typography
->features
, 2*typography
->allocated
*sizeof(DWRITE_FONT_FEATURE
));
5644 return E_OUTOFMEMORY
;
5646 typography
->features
= ptr
;
5647 typography
->allocated
*= 2;
5650 typography
->features
[typography
->count
++] = feature
;
5654 static UINT32 WINAPI
dwritetypography_GetFontFeatureCount(IDWriteTypography
*iface
)
5656 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5657 TRACE("(%p)\n", typography
);
5658 return typography
->count
;
5661 static HRESULT WINAPI
dwritetypography_GetFontFeature(IDWriteTypography
*iface
, UINT32 index
, DWRITE_FONT_FEATURE
*feature
)
5663 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5665 TRACE("(%p)->(%u %p)\n", typography
, index
, feature
);
5667 if (index
>= typography
->count
)
5668 return E_INVALIDARG
;
5670 *feature
= typography
->features
[index
];
5674 static const IDWriteTypographyVtbl dwritetypographyvtbl
= {
5675 dwritetypography_QueryInterface
,
5676 dwritetypography_AddRef
,
5677 dwritetypography_Release
,
5678 dwritetypography_AddFontFeature
,
5679 dwritetypography_GetFontFeatureCount
,
5680 dwritetypography_GetFontFeature
5683 HRESULT
create_typography(IDWriteTypography
**ret
)
5685 struct dwrite_typography
*typography
;
5689 typography
= heap_alloc(sizeof(*typography
));
5691 return E_OUTOFMEMORY
;
5693 typography
->IDWriteTypography_iface
.lpVtbl
= &dwritetypographyvtbl
;
5694 typography
->ref
= 1;
5695 typography
->allocated
= 2;
5696 typography
->count
= 0;
5698 typography
->features
= heap_alloc(typography
->allocated
*sizeof(DWRITE_FONT_FEATURE
));
5699 if (!typography
->features
) {
5700 heap_free(typography
);
5701 return E_OUTOFMEMORY
;
5704 *ret
= &typography
->IDWriteTypography_iface
;