2 * Text format and layout
4 * Copyright 2012, 2014-2016 Nikolay Sivov for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "dwrite_private.h"
31 #include "wine/list.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_LINE_SPACING_METHOD spacingmethod
;
52 DWRITE_VERTICAL_GLYPH_ORIENTATION vertical_orientation
;
53 DWRITE_OPTICAL_ALIGNMENT optical_alignment
;
59 DWRITE_TRIMMING trimming
;
60 IDWriteInlineObject
*trimmingsign
;
62 IDWriteFontCollection
*collection
;
63 IDWriteFontFallback
*fallback
;
66 enum layout_range_attr_kind
{
67 LAYOUT_RANGE_ATTR_WEIGHT
,
68 LAYOUT_RANGE_ATTR_STYLE
,
69 LAYOUT_RANGE_ATTR_STRETCH
,
70 LAYOUT_RANGE_ATTR_FONTSIZE
,
71 LAYOUT_RANGE_ATTR_EFFECT
,
72 LAYOUT_RANGE_ATTR_INLINE
,
73 LAYOUT_RANGE_ATTR_UNDERLINE
,
74 LAYOUT_RANGE_ATTR_STRIKETHROUGH
,
75 LAYOUT_RANGE_ATTR_PAIR_KERNING
,
76 LAYOUT_RANGE_ATTR_FONTCOLL
,
77 LAYOUT_RANGE_ATTR_LOCALE
,
78 LAYOUT_RANGE_ATTR_FONTFAMILY
,
79 LAYOUT_RANGE_ATTR_SPACING
,
80 LAYOUT_RANGE_ATTR_TYPOGRAPHY
83 struct layout_range_attr_value
{
84 DWRITE_TEXT_RANGE range
;
86 DWRITE_FONT_WEIGHT weight
;
87 DWRITE_FONT_STYLE style
;
88 DWRITE_FONT_STRETCH stretch
;
90 IDWriteInlineObject
*object
;
95 IDWriteFontCollection
*collection
;
97 const WCHAR
*fontfamily
;
98 FLOAT spacing
[3]; /* in arguments order - leading, trailing, advance */
99 IDWriteTypography
*typography
;
103 enum layout_range_kind
{
104 LAYOUT_RANGE_REGULAR
,
105 LAYOUT_RANGE_STRIKETHROUGH
,
107 LAYOUT_RANGE_SPACING
,
108 LAYOUT_RANGE_TYPOGRAPHY
111 struct layout_range_header
{
113 enum layout_range_kind kind
;
114 DWRITE_TEXT_RANGE range
;
117 struct layout_range
{
118 struct layout_range_header h
;
119 DWRITE_FONT_WEIGHT weight
;
120 DWRITE_FONT_STYLE style
;
122 DWRITE_FONT_STRETCH stretch
;
123 IDWriteInlineObject
*object
;
126 IDWriteFontCollection
*collection
;
127 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
131 struct layout_range_bool
{
132 struct layout_range_header h
;
136 struct layout_range_iface
{
137 struct layout_range_header h
;
141 struct layout_range_spacing
{
142 struct layout_range_header h
;
148 enum layout_run_kind
{
153 struct inline_object_run
{
154 IDWriteInlineObject
*object
;
158 struct regular_layout_run
{
159 DWRITE_GLYPH_RUN_DESCRIPTION descr
;
160 DWRITE_GLYPH_RUN run
;
161 DWRITE_SCRIPT_ANALYSIS sa
;
165 DWRITE_GLYPH_OFFSET
*offsets
;
166 /* this is actual glyph count after shaping, it's not necessary the same as reported to Draw() */
172 enum layout_run_kind kind
;
174 struct inline_object_run object
;
175 struct regular_layout_run regular
;
181 struct layout_effective_run
{
183 const struct layout_run
*run
; /* nominal run this one is based on */
184 UINT32 start
; /* relative text position, 0 means first text position of a nominal run */
185 UINT32 length
; /* length in codepoints that this run covers */
186 UINT32 glyphcount
; /* total glyph count in this run */
187 FLOAT origin_x
; /* baseline X position */
188 FLOAT origin_y
; /* baseline Y position */
189 FLOAT align_dx
; /* adjustment from text alignment */
190 FLOAT width
; /* run width */
191 UINT16
*clustermap
; /* effective clustermap, allocated separately, is not reused from nominal map */
195 struct layout_effective_inline
{
197 IDWriteInlineObject
*object
;
208 struct layout_strikethrough
{
210 const struct layout_effective_run
*run
;
211 DWRITE_STRIKETHROUGH s
;
214 struct layout_cluster
{
215 const struct layout_run
*run
; /* link to nominal run this cluster belongs to */
216 UINT32 position
; /* relative to run, first cluster has 0 position */
219 enum layout_recompute_mask
{
220 RECOMPUTE_NOMINAL_RUNS
= 1 << 0,
221 RECOMPUTE_MINIMAL_WIDTH
= 1 << 1,
222 RECOMPUTE_EFFECTIVE_RUNS
= 1 << 2,
223 RECOMPUTE_EVERYTHING
= 0xffff
226 struct dwrite_textlayout
{
227 IDWriteTextLayout2 IDWriteTextLayout2_iface
;
228 IDWriteTextFormat1 IDWriteTextFormat1_iface
;
229 IDWriteTextAnalysisSink IDWriteTextAnalysisSink_iface
;
230 IDWriteTextAnalysisSource IDWriteTextAnalysisSource_iface
;
235 struct dwrite_textformat_data format
;
236 struct list strike_ranges
;
237 struct list typographies
;
242 /* lists ready to use by Draw() */
244 struct list inlineobjects
;
245 struct list strikethrough
;
248 DWRITE_LINE_BREAKPOINT
*nominal_breakpoints
;
249 DWRITE_LINE_BREAKPOINT
*actual_breakpoints
;
251 struct layout_cluster
*clusters
;
252 DWRITE_CLUSTER_METRICS
*clustermetrics
;
253 UINT32 cluster_count
;
256 DWRITE_LINE_METRICS
*lines
;
259 DWRITE_TEXT_METRICS1 metrics
;
261 DWRITE_MEASURING_MODE measuringmode
;
263 /* gdi-compatible layout specifics */
265 DWRITE_MATRIX transform
;
268 struct dwrite_textformat
{
269 IDWriteTextFormat1 IDWriteTextFormat1_iface
;
271 struct dwrite_textformat_data format
;
274 struct dwrite_trimmingsign
{
275 IDWriteInlineObject IDWriteInlineObject_iface
;
278 IDWriteTextLayout
*layout
;
281 struct dwrite_typography
{
282 IDWriteTypography IDWriteTypography_iface
;
285 DWRITE_FONT_FEATURE
*features
;
295 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl
;
297 static void release_format_data(struct dwrite_textformat_data
*data
)
299 if (data
->collection
) IDWriteFontCollection_Release(data
->collection
);
300 if (data
->fallback
) IDWriteFontFallback_Release(data
->fallback
);
301 if (data
->trimmingsign
) IDWriteInlineObject_Release(data
->trimmingsign
);
302 heap_free(data
->family_name
);
303 heap_free(data
->locale
);
306 static inline struct dwrite_textlayout
*impl_from_IDWriteTextLayout2(IDWriteTextLayout2
*iface
)
308 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextLayout2_iface
);
311 static inline struct dwrite_textlayout
*impl_layout_form_IDWriteTextFormat1(IDWriteTextFormat1
*iface
)
313 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextFormat1_iface
);
316 static inline struct dwrite_textlayout
*impl_from_IDWriteTextAnalysisSink(IDWriteTextAnalysisSink
*iface
)
318 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextAnalysisSink_iface
);
321 static inline struct dwrite_textlayout
*impl_from_IDWriteTextAnalysisSource(IDWriteTextAnalysisSource
*iface
)
323 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextAnalysisSource_iface
);
326 static inline struct dwrite_textformat
*impl_from_IDWriteTextFormat1(IDWriteTextFormat1
*iface
)
328 return CONTAINING_RECORD(iface
, struct dwrite_textformat
, IDWriteTextFormat1_iface
);
331 static struct dwrite_textformat
*unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat
*);
333 static inline struct dwrite_trimmingsign
*impl_from_IDWriteInlineObject(IDWriteInlineObject
*iface
)
335 return CONTAINING_RECORD(iface
, struct dwrite_trimmingsign
, IDWriteInlineObject_iface
);
338 static inline struct dwrite_typography
*impl_from_IDWriteTypography(IDWriteTypography
*iface
)
340 return CONTAINING_RECORD(iface
, struct dwrite_typography
, IDWriteTypography_iface
);
343 static inline const char *debugstr_run(const struct regular_layout_run
*run
)
345 return wine_dbg_sprintf("[%u,%u)", run
->descr
.textPosition
, run
->descr
.textPosition
+
346 run
->descr
.stringLength
);
349 static inline BOOL
is_layout_gdi_compatible(struct dwrite_textlayout
*layout
)
351 return layout
->measuringmode
!= DWRITE_MEASURING_MODE_NATURAL
;
354 static inline HRESULT
format_set_textalignment(struct dwrite_textformat_data
*format
, DWRITE_TEXT_ALIGNMENT alignment
,
357 if ((UINT32
)alignment
> DWRITE_TEXT_ALIGNMENT_JUSTIFIED
)
359 if (changed
) *changed
= format
->textalignment
!= alignment
;
360 format
->textalignment
= alignment
;
364 static inline HRESULT
format_set_paralignment(struct dwrite_textformat_data
*format
,
365 DWRITE_PARAGRAPH_ALIGNMENT alignment
, BOOL
*changed
)
367 if ((UINT32
)alignment
> DWRITE_PARAGRAPH_ALIGNMENT_CENTER
)
369 if (changed
) *changed
= format
->paralign
!= alignment
;
370 format
->paralign
= alignment
;
374 static inline HRESULT
format_set_readingdirection(struct dwrite_textformat_data
*format
,
375 DWRITE_READING_DIRECTION direction
, BOOL
*changed
)
377 if ((UINT32
)direction
> DWRITE_READING_DIRECTION_BOTTOM_TO_TOP
)
379 if (changed
) *changed
= format
->readingdir
!= direction
;
380 format
->readingdir
= direction
;
384 static inline HRESULT
format_set_wordwrapping(struct dwrite_textformat_data
*format
,
385 DWRITE_WORD_WRAPPING wrapping
, BOOL
*changed
)
387 if ((UINT32
)wrapping
> DWRITE_WORD_WRAPPING_CHARACTER
)
389 if (changed
) *changed
= format
->wrapping
!= wrapping
;
390 format
->wrapping
= wrapping
;
394 static HRESULT
get_fontfallback_from_format(const struct dwrite_textformat_data
*format
, IDWriteFontFallback
**fallback
)
396 *fallback
= format
->fallback
;
398 IDWriteFontFallback_AddRef(*fallback
);
402 static HRESULT
set_fontfallback_for_format(struct dwrite_textformat_data
*format
, IDWriteFontFallback
*fallback
)
404 if (format
->fallback
)
405 IDWriteFontFallback_Release(format
->fallback
);
406 format
->fallback
= fallback
;
408 IDWriteFontFallback_AddRef(fallback
);
412 static HRESULT
format_set_optical_alignment(struct dwrite_textformat_data
*format
,
413 DWRITE_OPTICAL_ALIGNMENT alignment
)
415 if ((UINT32
)alignment
> DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS
)
417 format
->optical_alignment
= alignment
;
421 static struct layout_run
*alloc_layout_run(enum layout_run_kind kind
)
423 struct layout_run
*ret
;
425 ret
= heap_alloc(sizeof(*ret
));
426 if (!ret
) return NULL
;
428 memset(ret
, 0, sizeof(*ret
));
430 if (kind
== LAYOUT_RUN_REGULAR
) {
431 ret
->u
.regular
.sa
.script
= Script_Unknown
;
432 ret
->u
.regular
.sa
.shapes
= DWRITE_SCRIPT_SHAPES_DEFAULT
;
438 static void free_layout_runs(struct dwrite_textlayout
*layout
)
440 struct layout_run
*cur
, *cur2
;
441 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->runs
, struct layout_run
, entry
) {
442 list_remove(&cur
->entry
);
443 if (cur
->kind
== LAYOUT_RUN_REGULAR
) {
444 if (cur
->u
.regular
.run
.fontFace
)
445 IDWriteFontFace_Release(cur
->u
.regular
.run
.fontFace
);
446 heap_free(cur
->u
.regular
.glyphs
);
447 heap_free(cur
->u
.regular
.clustermap
);
448 heap_free(cur
->u
.regular
.advances
);
449 heap_free(cur
->u
.regular
.offsets
);
455 static void free_layout_eruns(struct dwrite_textlayout
*layout
)
457 struct layout_effective_inline
*in
, *in2
;
458 struct layout_effective_run
*cur
, *cur2
;
459 struct layout_strikethrough
*s
, *s2
;
461 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->eruns
, struct layout_effective_run
, entry
) {
462 list_remove(&cur
->entry
);
463 heap_free(cur
->clustermap
);
467 LIST_FOR_EACH_ENTRY_SAFE(in
, in2
, &layout
->inlineobjects
, struct layout_effective_inline
, entry
) {
468 list_remove(&in
->entry
);
472 LIST_FOR_EACH_ENTRY_SAFE(s
, s2
, &layout
->strikethrough
, struct layout_strikethrough
, entry
) {
473 list_remove(&s
->entry
);
478 /* Used to resolve break condition by forcing stronger condition over weaker. */
479 static inline DWRITE_BREAK_CONDITION
override_break_condition(DWRITE_BREAK_CONDITION existingbreak
, DWRITE_BREAK_CONDITION newbreak
)
481 switch (existingbreak
) {
482 case DWRITE_BREAK_CONDITION_NEUTRAL
:
484 case DWRITE_BREAK_CONDITION_CAN_BREAK
:
485 return newbreak
== DWRITE_BREAK_CONDITION_NEUTRAL
? existingbreak
: newbreak
;
486 /* let's keep stronger conditions as is */
487 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
:
488 case DWRITE_BREAK_CONDITION_MUST_BREAK
:
491 ERR("unknown break condition %d\n", existingbreak
);
494 return existingbreak
;
497 /* This helper should be used to get effective range length, in other words it returns number of text
498 positions from range starting point to the end of the range, limited by layout text length */
499 static inline UINT32
get_clipped_range_length(const struct dwrite_textlayout
*layout
, const struct layout_range
*range
)
501 if (range
->h
.range
.startPosition
+ range
->h
.range
.length
<= layout
->len
)
502 return range
->h
.range
.length
;
503 return layout
->len
- range
->h
.range
.startPosition
;
506 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
507 static HRESULT
layout_update_breakpoints_range(struct dwrite_textlayout
*layout
, const struct layout_range
*cur
)
509 DWRITE_BREAK_CONDITION before
, after
;
513 /* ignore returned conditions if failed */
514 hr
= IDWriteInlineObject_GetBreakConditions(cur
->object
, &before
, &after
);
516 after
= before
= DWRITE_BREAK_CONDITION_NEUTRAL
;
518 if (!layout
->actual_breakpoints
) {
519 layout
->actual_breakpoints
= heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT
)*layout
->len
);
520 if (!layout
->actual_breakpoints
)
521 return E_OUTOFMEMORY
;
522 memcpy(layout
->actual_breakpoints
, layout
->nominal_breakpoints
, sizeof(DWRITE_LINE_BREAKPOINT
)*layout
->len
);
525 length
= get_clipped_range_length(layout
, cur
);
526 for (i
= cur
->h
.range
.startPosition
; i
< length
+ cur
->h
.range
.startPosition
; i
++) {
527 /* for first codepoint check if there's anything before it and update accordingly */
528 if (i
== cur
->h
.range
.startPosition
) {
530 layout
->actual_breakpoints
[i
].breakConditionBefore
= layout
->actual_breakpoints
[i
-1].breakConditionAfter
=
531 override_break_condition(layout
->actual_breakpoints
[i
-1].breakConditionAfter
, before
);
533 layout
->actual_breakpoints
[i
].breakConditionBefore
= before
;
534 layout
->actual_breakpoints
[i
].breakConditionAfter
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
536 /* similar check for last codepoint */
537 else if (i
== cur
->h
.range
.startPosition
+ length
- 1) {
538 if (i
== layout
->len
- 1)
539 layout
->actual_breakpoints
[i
].breakConditionAfter
= after
;
541 layout
->actual_breakpoints
[i
].breakConditionAfter
= layout
->actual_breakpoints
[i
+1].breakConditionBefore
=
542 override_break_condition(layout
->actual_breakpoints
[i
+1].breakConditionBefore
, after
);
543 layout
->actual_breakpoints
[i
].breakConditionBefore
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
545 /* for all positions within a range disable breaks */
547 layout
->actual_breakpoints
[i
].breakConditionBefore
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
548 layout
->actual_breakpoints
[i
].breakConditionAfter
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
551 layout
->actual_breakpoints
[i
].isWhitespace
= FALSE
;
552 layout
->actual_breakpoints
[i
].isSoftHyphen
= FALSE
;
558 static struct layout_range
*get_layout_range_by_pos(struct dwrite_textlayout
*layout
, UINT32 pos
);
560 static inline DWRITE_LINE_BREAKPOINT
get_effective_breakpoint(const struct dwrite_textlayout
*layout
, UINT32 pos
)
562 if (layout
->actual_breakpoints
)
563 return layout
->actual_breakpoints
[pos
];
564 return layout
->nominal_breakpoints
[pos
];
567 static inline void init_cluster_metrics(const struct dwrite_textlayout
*layout
, const struct regular_layout_run
*run
,
568 UINT16 start_glyph
, UINT16 stop_glyph
, UINT32 stop_position
, UINT16 length
, DWRITE_CLUSTER_METRICS
*metrics
)
570 UINT8 breakcondition
;
574 /* For clusters made of control chars we report zero glyphs, and we need zero cluster
575 width as well; advances are already computed at this point and are not necessary zero. */
576 metrics
->width
= 0.0f
;
577 if (run
->run
.glyphCount
) {
578 for (j
= start_glyph
; j
< stop_glyph
; j
++)
579 metrics
->width
+= run
->run
.glyphAdvances
[j
];
581 metrics
->length
= length
;
583 position
= stop_position
;
584 if (stop_glyph
== run
->glyphcount
)
585 breakcondition
= get_effective_breakpoint(layout
, stop_position
).breakConditionAfter
;
587 breakcondition
= get_effective_breakpoint(layout
, stop_position
).breakConditionBefore
;
588 if (stop_position
) position
= stop_position
- 1;
591 metrics
->canWrapLineAfter
= breakcondition
== DWRITE_BREAK_CONDITION_CAN_BREAK
||
592 breakcondition
== DWRITE_BREAK_CONDITION_MUST_BREAK
;
593 if (metrics
->length
== 1) {
596 GetStringTypeW(CT_CTYPE1
, &layout
->str
[position
], 1, &type
);
597 metrics
->isWhitespace
= !!(type
& C1_SPACE
);
598 metrics
->isNewline
= FALSE
/* FIXME */;
599 metrics
->isSoftHyphen
= layout
->str
[position
] == 0x00ad /* Unicode Soft Hyphen */;
602 metrics
->isWhitespace
= FALSE
;
603 metrics
->isNewline
= FALSE
;
604 metrics
->isSoftHyphen
= FALSE
;
606 metrics
->isRightToLeft
= run
->run
.bidiLevel
& 1;
607 metrics
->padding
= 0;
612 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
613 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
614 Note that there's no need to reallocate anything at this point as we allocate one cluster per
618 static void layout_set_cluster_metrics(struct dwrite_textlayout
*layout
, const struct layout_run
*r
, UINT32
*cluster
)
620 DWRITE_CLUSTER_METRICS
*metrics
= &layout
->clustermetrics
[*cluster
];
621 struct layout_cluster
*c
= &layout
->clusters
[*cluster
];
622 const struct regular_layout_run
*run
= &r
->u
.regular
;
625 for (i
= 0; i
< run
->descr
.stringLength
; i
++) {
626 BOOL end
= i
== run
->descr
.stringLength
- 1;
628 if (run
->descr
.clusterMap
[start
] != run
->descr
.clusterMap
[i
]) {
629 init_cluster_metrics(layout
, run
, run
->descr
.clusterMap
[start
], run
->descr
.clusterMap
[i
], i
,
641 init_cluster_metrics(layout
, run
, run
->descr
.clusterMap
[start
], run
->glyphcount
, i
,
642 i
- start
+ 1, metrics
);
652 static inline FLOAT
get_scaled_font_metric(UINT32 metric
, FLOAT emSize
, const DWRITE_FONT_METRICS
*metrics
)
654 return (FLOAT
)metric
* emSize
/ (FLOAT
)metrics
->designUnitsPerEm
;
657 static HRESULT
layout_compute_runs(struct dwrite_textlayout
*layout
)
659 IDWriteTextAnalyzer
*analyzer
;
660 struct layout_range
*range
;
661 struct layout_run
*r
;
665 free_layout_eruns(layout
);
666 free_layout_runs(layout
);
668 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
669 if (!layout
->clustermetrics
) {
670 layout
->clustermetrics
= heap_alloc(layout
->len
*sizeof(*layout
->clustermetrics
));
671 layout
->clusters
= heap_alloc(layout
->len
*sizeof(*layout
->clusters
));
672 if (!layout
->clustermetrics
|| !layout
->clusters
) {
673 heap_free(layout
->clustermetrics
);
674 heap_free(layout
->clusters
);
675 return E_OUTOFMEMORY
;
678 layout
->cluster_count
= 0;
680 hr
= get_textanalyzer(&analyzer
);
684 LIST_FOR_EACH_ENTRY(range
, &layout
->ranges
, struct layout_range
, h
.entry
) {
685 /* we don't care about ranges that don't contain any text */
686 if (range
->h
.range
.startPosition
>= layout
->len
)
689 /* inline objects override actual text in a range */
691 hr
= layout_update_breakpoints_range(layout
, range
);
695 r
= alloc_layout_run(LAYOUT_RUN_INLINE
);
697 return E_OUTOFMEMORY
;
699 r
->u
.object
.object
= range
->object
;
700 r
->u
.object
.length
= get_clipped_range_length(layout
, range
);
701 list_add_tail(&layout
->runs
, &r
->entry
);
705 /* initial splitting by script */
706 hr
= IDWriteTextAnalyzer_AnalyzeScript(analyzer
, &layout
->IDWriteTextAnalysisSource_iface
,
707 range
->h
.range
.startPosition
, get_clipped_range_length(layout
, range
), &layout
->IDWriteTextAnalysisSink_iface
);
711 /* this splits it further */
712 hr
= IDWriteTextAnalyzer_AnalyzeBidi(analyzer
, &layout
->IDWriteTextAnalysisSource_iface
,
713 range
->h
.range
.startPosition
, get_clipped_range_length(layout
, range
), &layout
->IDWriteTextAnalysisSink_iface
);
719 LIST_FOR_EACH_ENTRY(r
, &layout
->runs
, struct layout_run
, entry
) {
720 DWRITE_SHAPING_GLYPH_PROPERTIES
*glyph_props
= NULL
;
721 DWRITE_SHAPING_TEXT_PROPERTIES
*text_props
= NULL
;
722 struct regular_layout_run
*run
= &r
->u
.regular
;
723 DWRITE_FONT_METRICS fontmetrics
= { 0 };
724 IDWriteFontFamily
*family
;
725 UINT32 index
, max_count
;
729 /* we need to do very little in case of inline objects */
730 if (r
->kind
== LAYOUT_RUN_INLINE
) {
731 DWRITE_CLUSTER_METRICS
*metrics
= &layout
->clustermetrics
[cluster
];
732 struct layout_cluster
*c
= &layout
->clusters
[cluster
];
733 DWRITE_INLINE_OBJECT_METRICS inlinemetrics
;
735 metrics
->width
= 0.0f
;
736 metrics
->length
= r
->u
.object
.length
;
737 metrics
->canWrapLineAfter
= FALSE
;
738 metrics
->isWhitespace
= FALSE
;
739 metrics
->isNewline
= FALSE
;
740 metrics
->isSoftHyphen
= FALSE
;
741 metrics
->isRightToLeft
= FALSE
;
742 metrics
->padding
= 0;
744 c
->position
= 0; /* there's always one cluster per inline object, so 0 is valid value */
747 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
748 hr
= IDWriteInlineObject_GetMetrics(r
->u
.object
.object
, &inlinemetrics
);
750 memset(&inlinemetrics
, 0, sizeof(inlinemetrics
));
753 metrics
->width
= inlinemetrics
.width
;
754 r
->baseline
= inlinemetrics
.baseline
;
755 r
->height
= inlinemetrics
.height
;
757 /* FIXME: use resolved breakpoints in this case too */
762 range
= get_layout_range_by_pos(layout
, run
->descr
.textPosition
);
764 hr
= IDWriteFontCollection_FindFamilyName(range
->collection
, range
->fontfamily
, &index
, &exists
);
765 if (FAILED(hr
) || !exists
) {
766 WARN("%s: family %s not found in collection %p\n", debugstr_run(run
), debugstr_w(range
->fontfamily
), range
->collection
);
770 hr
= IDWriteFontCollection_GetFontFamily(range
->collection
, index
, &family
);
774 hr
= IDWriteFontFamily_GetFirstMatchingFont(family
, range
->weight
, range
->stretch
, range
->style
, &font
);
775 IDWriteFontFamily_Release(family
);
777 WARN("%s: failed to get a matching font\n", debugstr_run(run
));
781 hr
= IDWriteFont_CreateFontFace(font
, &run
->run
.fontFace
);
782 IDWriteFont_Release(font
);
786 run
->run
.fontEmSize
= range
->fontsize
;
787 run
->descr
.localeName
= range
->locale
;
788 run
->clustermap
= heap_alloc(run
->descr
.stringLength
*sizeof(UINT16
));
790 max_count
= 3*run
->descr
.stringLength
/2 + 16;
791 run
->glyphs
= heap_alloc(max_count
*sizeof(UINT16
));
792 if (!run
->clustermap
|| !run
->glyphs
)
795 text_props
= heap_alloc(run
->descr
.stringLength
*sizeof(DWRITE_SHAPING_TEXT_PROPERTIES
));
796 glyph_props
= heap_alloc(max_count
*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES
));
797 if (!text_props
|| !glyph_props
)
801 hr
= IDWriteTextAnalyzer_GetGlyphs(analyzer
, run
->descr
.string
, run
->descr
.stringLength
,
802 run
->run
.fontFace
, run
->run
.isSideways
, run
->run
.bidiLevel
& 1, &run
->sa
, run
->descr
.localeName
,
803 NULL
/* FIXME */, NULL
, NULL
, 0, max_count
, run
->clustermap
, text_props
, run
->glyphs
, glyph_props
,
805 if (hr
== E_NOT_SUFFICIENT_BUFFER
) {
806 heap_free(run
->glyphs
);
807 heap_free(glyph_props
);
809 max_count
= run
->glyphcount
;
811 run
->glyphs
= heap_alloc(max_count
*sizeof(UINT16
));
812 glyph_props
= heap_alloc(max_count
*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES
));
813 if (!run
->glyphs
|| !glyph_props
)
823 heap_free(text_props
);
824 heap_free(glyph_props
);
825 WARN("%s: shaping failed 0x%08x\n", debugstr_run(run
), hr
);
829 run
->run
.glyphIndices
= run
->glyphs
;
830 run
->descr
.clusterMap
= run
->clustermap
;
832 run
->advances
= heap_alloc(run
->glyphcount
*sizeof(FLOAT
));
833 run
->offsets
= heap_alloc(run
->glyphcount
*sizeof(DWRITE_GLYPH_OFFSET
));
834 if (!run
->advances
|| !run
->offsets
)
837 /* now set advances and offsets */
838 if (is_layout_gdi_compatible(layout
))
839 hr
= IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer
, run
->descr
.string
, run
->descr
.clusterMap
,
840 text_props
, run
->descr
.stringLength
, run
->run
.glyphIndices
, glyph_props
, run
->glyphcount
,
841 run
->run
.fontFace
, run
->run
.fontEmSize
, layout
->ppdip
, &layout
->transform
,
842 layout
->measuringmode
== DWRITE_MEASURING_MODE_GDI_NATURAL
, run
->run
.isSideways
,
843 run
->run
.bidiLevel
& 1, &run
->sa
, run
->descr
.localeName
, NULL
, NULL
, 0, run
->advances
, run
->offsets
);
845 hr
= IDWriteTextAnalyzer_GetGlyphPlacements(analyzer
, run
->descr
.string
, run
->descr
.clusterMap
, text_props
,
846 run
->descr
.stringLength
, run
->run
.glyphIndices
, glyph_props
, run
->glyphcount
, run
->run
.fontFace
,
847 run
->run
.fontEmSize
, run
->run
.isSideways
, run
->run
.bidiLevel
& 1, &run
->sa
, run
->descr
.localeName
,
848 NULL
, NULL
, 0, run
->advances
, run
->offsets
);
850 heap_free(text_props
);
851 heap_free(glyph_props
);
853 WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_run(run
), hr
);
855 run
->run
.glyphAdvances
= run
->advances
;
856 run
->run
.glyphOffsets
= run
->offsets
;
858 /* Special treatment of control script, shaping code adds normal glyphs for it,
859 with non-zero advances, and layout code exposes those as zero width clusters,
860 so we have to do it manually. */
861 if (run
->sa
.script
== Script_Common
)
862 run
->run
.glyphCount
= 0;
864 run
->run
.glyphCount
= run
->glyphcount
;
866 /* baseline derived from font metrics */
867 if (is_layout_gdi_compatible(layout
)) {
868 hr
= IDWriteFontFace_GetGdiCompatibleMetrics(run
->run
.fontFace
,
874 WARN("failed to get compat metrics, 0x%08x\n", hr
);
877 IDWriteFontFace_GetMetrics(run
->run
.fontFace
, &fontmetrics
);
879 r
->baseline
= get_scaled_font_metric(fontmetrics
.ascent
, run
->run
.fontEmSize
, &fontmetrics
);
880 r
->height
= get_scaled_font_metric(fontmetrics
.ascent
+ fontmetrics
.descent
, run
->run
.fontEmSize
, &fontmetrics
);
882 layout_set_cluster_metrics(layout
, r
, &cluster
);
887 heap_free(text_props
);
888 heap_free(glyph_props
);
889 heap_free(run
->clustermap
);
890 heap_free(run
->glyphs
);
891 heap_free(run
->advances
);
892 heap_free(run
->offsets
);
893 run
->advances
= NULL
;
895 run
->clustermap
= run
->glyphs
= NULL
;
901 layout
->cluster_count
= cluster
;
903 layout
->clustermetrics
[cluster
-1].canWrapLineAfter
= TRUE
;
906 IDWriteTextAnalyzer_Release(analyzer
);
910 static HRESULT
layout_compute(struct dwrite_textlayout
*layout
)
914 if (!(layout
->recompute
& RECOMPUTE_NOMINAL_RUNS
))
917 /* nominal breakpoints are evaluated only once, because string never changes */
918 if (!layout
->nominal_breakpoints
) {
919 IDWriteTextAnalyzer
*analyzer
;
922 layout
->nominal_breakpoints
= heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT
)*layout
->len
);
923 if (!layout
->nominal_breakpoints
)
924 return E_OUTOFMEMORY
;
926 hr
= get_textanalyzer(&analyzer
);
930 hr
= IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer
, &layout
->IDWriteTextAnalysisSource_iface
,
931 0, layout
->len
, &layout
->IDWriteTextAnalysisSink_iface
);
932 IDWriteTextAnalyzer_Release(analyzer
);
934 if (layout
->actual_breakpoints
) {
935 heap_free(layout
->actual_breakpoints
);
936 layout
->actual_breakpoints
= NULL
;
939 hr
= layout_compute_runs(layout
);
941 if (TRACE_ON(dwrite
)) {
942 struct layout_run
*cur
;
944 LIST_FOR_EACH_ENTRY(cur
, &layout
->runs
, struct layout_run
, entry
) {
945 if (cur
->kind
== LAYOUT_RUN_INLINE
)
946 TRACE("run inline object %p, len %u\n", cur
->u
.object
.object
, cur
->u
.object
.length
);
948 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur
->u
.regular
.descr
.textPosition
, cur
->u
.regular
.descr
.textPosition
+
949 cur
->u
.regular
.descr
.stringLength
-1, cur
->u
.regular
.descr
.stringLength
, cur
->u
.regular
.run
.bidiLevel
);
953 layout
->recompute
&= ~RECOMPUTE_NOMINAL_RUNS
;
957 static inline FLOAT
get_cluster_range_width(struct dwrite_textlayout
*layout
, UINT32 start
, UINT32 end
)
960 for (; start
< end
; start
++)
961 width
+= layout
->clustermetrics
[start
].width
;
965 static struct layout_range_header
*get_layout_range_header_by_pos(struct list
*ranges
, UINT32 pos
)
967 struct layout_range_header
*cur
;
969 LIST_FOR_EACH_ENTRY(cur
, ranges
, struct layout_range_header
, entry
) {
970 DWRITE_TEXT_RANGE
*r
= &cur
->range
;
971 if (r
->startPosition
<= pos
&& pos
< r
->startPosition
+ r
->length
)
978 static inline IUnknown
*layout_get_effect_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
980 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->effects
, pos
);
981 return ((struct layout_range_iface
*)h
)->iface
;
984 static inline BOOL
layout_is_erun_rtl(const struct layout_effective_run
*erun
)
986 return erun
->run
->u
.regular
.run
.bidiLevel
& 1;
989 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
990 'cluster_count' indicates how many clusters to add, including first one. */
991 static HRESULT
layout_add_effective_run(struct dwrite_textlayout
*layout
, const struct layout_run
*r
, UINT32 first_cluster
,
992 UINT32 cluster_count
, UINT32 line
, FLOAT origin_x
, BOOL strikethrough
)
994 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
995 UINT32 i
, start
, length
, last_cluster
;
996 struct layout_effective_run
*run
;
998 if (r
->kind
== LAYOUT_RUN_INLINE
) {
999 struct layout_effective_inline
*inlineobject
;
1001 inlineobject
= heap_alloc(sizeof(*inlineobject
));
1003 return E_OUTOFMEMORY
;
1005 inlineobject
->object
= r
->u
.object
.object
;
1006 inlineobject
->width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1007 inlineobject
->origin_x
= is_rtl
? origin_x
- inlineobject
->width
: origin_x
;
1008 inlineobject
->origin_y
= 0.0f
; /* set after line is built */
1009 inlineobject
->align_dx
= 0.0f
;
1011 /* It's not clear how these two are set, possibly directionality
1012 is derived from surrounding text (replaced text could have
1013 different ranges which differ in reading direction). */
1014 inlineobject
->is_sideways
= FALSE
;
1015 inlineobject
->is_rtl
= FALSE
;
1016 inlineobject
->line
= line
;
1018 /* effect assigned from start position and on is used for inline objects */
1019 inlineobject
->effect
= layout_get_effect_from_pos(layout
, layout
->clusters
[first_cluster
].position
);
1021 list_add_tail(&layout
->inlineobjects
, &inlineobject
->entry
);
1025 run
= heap_alloc(sizeof(*run
));
1027 return E_OUTOFMEMORY
;
1029 /* No need to iterate for that, use simple fact that:
1030 <last cluster position> = first cluster position> + <sum of cluster lengths not including last one> */
1031 last_cluster
= first_cluster
+ cluster_count
- 1;
1032 length
= layout
->clusters
[last_cluster
].position
- layout
->clusters
[first_cluster
].position
+
1033 layout
->clustermetrics
[last_cluster
].length
;
1035 run
->clustermap
= heap_alloc(sizeof(UINT16
)*length
);
1036 if (!run
->clustermap
) {
1038 return E_OUTOFMEMORY
;
1042 run
->start
= start
= layout
->clusters
[first_cluster
].position
;
1043 run
->length
= length
;
1044 run
->width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1046 /* Check if run direction matches paragraph direction, if it doesn't adjust by
1048 if (layout_is_erun_rtl(run
) ^ is_rtl
)
1049 run
->origin_x
= is_rtl
? origin_x
- run
->width
: origin_x
+ run
->width
;
1051 run
->origin_x
= origin_x
;
1053 run
->origin_y
= 0.0f
; /* set after line is built */
1054 run
->align_dx
= 0.0f
;
1057 if (r
->u
.regular
.run
.glyphCount
) {
1058 /* trim from the left */
1059 run
->glyphcount
= r
->u
.regular
.run
.glyphCount
- r
->u
.regular
.clustermap
[start
];
1060 /* trim from the right */
1061 if (start
+ length
< r
->u
.regular
.descr
.stringLength
- 1)
1062 run
->glyphcount
-= r
->u
.regular
.run
.glyphCount
- r
->u
.regular
.clustermap
[start
+ length
];
1065 run
->glyphcount
= 0;
1067 /* cluster map needs to be shifted */
1068 for (i
= 0; i
< length
; i
++)
1069 run
->clustermap
[i
] = r
->u
.regular
.clustermap
[start
+ i
] - r
->u
.regular
.clustermap
[start
];
1071 list_add_tail(&layout
->eruns
, &run
->entry
);
1073 /* Strikethrough style is guaranteed to be consistent within effective run,
1074 it's width equals to run width, thikness and offset are derived from
1075 font metrics, rest of the values are from layout or run itself */
1076 if (strikethrough
) {
1077 DWRITE_FONT_METRICS metrics
= { 0 };
1078 struct layout_strikethrough
*s
;
1080 s
= heap_alloc(sizeof(*s
));
1082 return E_OUTOFMEMORY
;
1084 if (is_layout_gdi_compatible(layout
)) {
1085 HRESULT hr
= IDWriteFontFace_GetGdiCompatibleMetrics(
1086 r
->u
.regular
.run
.fontFace
,
1087 r
->u
.regular
.run
.fontEmSize
,
1092 WARN("failed to get font metrics, 0x%08x\n", hr
);
1095 IDWriteFontFace_GetMetrics(r
->u
.regular
.run
.fontFace
, &metrics
);
1097 s
->s
.width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1098 s
->s
.thickness
= metrics
.strikethroughThickness
;
1099 s
->s
.offset
= metrics
.strikethroughPosition
;
1100 s
->s
.readingDirection
= layout
->format
.readingdir
;
1101 s
->s
.flowDirection
= layout
->format
.flow
;
1102 s
->s
.localeName
= r
->u
.regular
.descr
.localeName
;
1103 s
->s
.measuringMode
= layout
->measuringmode
;
1106 list_add_tail(&layout
->strikethrough
, &s
->entry
);
1112 static HRESULT
layout_set_line_metrics(struct dwrite_textlayout
*layout
, DWRITE_LINE_METRICS
*metrics
, UINT32
*line
)
1114 if (!layout
->line_alloc
) {
1115 layout
->line_alloc
= 5;
1116 layout
->lines
= heap_alloc(layout
->line_alloc
*sizeof(*layout
->lines
));
1118 return E_OUTOFMEMORY
;
1121 if (layout
->metrics
.lineCount
== layout
->line_alloc
) {
1122 DWRITE_LINE_METRICS
*l
= heap_realloc(layout
->lines
, layout
->line_alloc
*2*sizeof(*layout
->lines
));
1124 return E_OUTOFMEMORY
;
1126 layout
->line_alloc
*= 2;
1129 layout
->lines
[*line
] = *metrics
;
1130 layout
->metrics
.lineCount
+= 1;
1135 static inline BOOL
layout_get_strikethrough_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
1137 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->strike_ranges
, pos
);
1138 return ((struct layout_range_bool
*)h
)->value
;
1141 static inline struct layout_effective_run
*layout_get_next_erun(struct dwrite_textlayout
*layout
,
1142 const struct layout_effective_run
*cur
)
1147 e
= list_head(&layout
->eruns
);
1149 e
= list_next(&layout
->eruns
, &cur
->entry
);
1152 return LIST_ENTRY(e
, struct layout_effective_run
, entry
);
1155 static inline struct layout_effective_inline
*layout_get_next_inline_run(struct dwrite_textlayout
*layout
,
1156 const struct layout_effective_inline
*cur
)
1161 e
= list_head(&layout
->inlineobjects
);
1163 e
= list_next(&layout
->inlineobjects
, &cur
->entry
);
1166 return LIST_ENTRY(e
, struct layout_effective_inline
, entry
);
1169 static FLOAT
layout_get_line_width(struct dwrite_textlayout
*layout
,
1170 struct layout_effective_run
*erun
, struct layout_effective_inline
*inrun
, UINT32 line
)
1174 while (erun
&& erun
->line
== line
) {
1175 width
+= erun
->width
;
1176 erun
= layout_get_next_erun(layout
, erun
);
1181 while (inrun
&& inrun
->line
== line
) {
1182 width
+= inrun
->width
;
1183 inrun
= layout_get_next_inline_run(layout
, inrun
);
1191 static inline BOOL
should_skip_transform(const DWRITE_MATRIX
*m
, FLOAT
*det
)
1193 *det
= m
->m11
* m
->m22
- m
->m12
* m
->m21
;
1194 /* on certain conditions we can skip transform */
1195 return (!memcmp(m
, &identity
, sizeof(*m
)) || fabsf(*det
) <= 1e-10f
);
1198 static inline void layout_apply_snapping(struct dwrite_vec
*vec
, BOOL skiptransform
, FLOAT ppdip
,
1199 const DWRITE_MATRIX
*m
, FLOAT det
)
1201 if (!skiptransform
) {
1204 /* apply transform */
1208 vec2
[0] = m
->m11
* vec
->x
+ m
->m21
* vec
->y
+ m
->dx
;
1209 vec2
[1] = m
->m12
* vec
->x
+ m
->m22
* vec
->y
+ m
->dy
;
1212 vec2
[0] = floorf(vec2
[0] + 0.5f
);
1213 vec2
[1] = floorf(vec2
[1] + 0.5f
);
1215 /* apply inverted transform, we don't care about X component at this point */
1216 vec
->x
= (m
->m22
* vec2
[0] - m
->m21
* vec2
[1] + m
->m21
* m
->dy
- m
->m22
* m
->dx
) / det
;
1219 vec
->y
= (-m
->m12
* vec2
[0] + m
->m11
* vec2
[1] - (m
->m11
* m
->dy
- m
->m12
* m
->dx
)) / det
;
1223 vec
->x
= floorf(vec
->x
* ppdip
+ 0.5f
) / ppdip
;
1224 vec
->y
= floorf(vec
->y
* ppdip
+ 0.5f
) / ppdip
;
1228 static void layout_apply_leading_alignment(struct dwrite_textlayout
*layout
)
1230 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1231 struct layout_effective_inline
*inrun
;
1232 struct layout_effective_run
*erun
;
1234 erun
= layout_get_next_erun(layout
, NULL
);
1235 inrun
= layout_get_next_inline_run(layout
, NULL
);
1238 erun
->align_dx
= 0.0f
;
1239 erun
= layout_get_next_erun(layout
, erun
);
1243 inrun
->align_dx
= 0.0f
;
1244 inrun
= layout_get_next_inline_run(layout
, inrun
);
1247 layout
->metrics
.left
= is_rtl
? layout
->metrics
.layoutWidth
- layout
->metrics
.width
: 0.0f
;
1250 static void layout_apply_trailing_alignment(struct dwrite_textlayout
*layout
)
1252 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1253 struct layout_effective_inline
*inrun
;
1254 struct layout_effective_run
*erun
;
1257 erun
= layout_get_next_erun(layout
, NULL
);
1258 inrun
= layout_get_next_inline_run(layout
, NULL
);
1260 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1261 FLOAT width
= layout_get_line_width(layout
, erun
, inrun
, line
);
1262 FLOAT shift
= layout
->metrics
.layoutWidth
- width
;
1267 while (erun
&& erun
->line
== line
) {
1268 erun
->align_dx
= shift
;
1269 erun
= layout_get_next_erun(layout
, erun
);
1272 while (inrun
&& inrun
->line
== line
) {
1273 inrun
->align_dx
= shift
;
1274 inrun
= layout_get_next_inline_run(layout
, inrun
);
1278 layout
->metrics
.left
= is_rtl
? 0.0f
: layout
->metrics
.layoutWidth
- layout
->metrics
.width
;
1281 static inline FLOAT
layout_get_centered_shift(struct dwrite_textlayout
*layout
, BOOL skiptransform
,
1282 FLOAT width
, FLOAT det
)
1284 if (is_layout_gdi_compatible(layout
)) {
1285 struct dwrite_vec vec
= { layout
->metrics
.layoutWidth
- width
, 0.0f
};
1286 layout_apply_snapping(&vec
, skiptransform
, layout
->ppdip
, &layout
->transform
, det
);
1287 return floorf(vec
.x
/ 2.0f
);
1290 return (layout
->metrics
.layoutWidth
- width
) / 2.0f
;
1293 static void layout_apply_centered_alignment(struct dwrite_textlayout
*layout
)
1295 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1296 struct layout_effective_inline
*inrun
;
1297 struct layout_effective_run
*erun
;
1302 erun
= layout_get_next_erun(layout
, NULL
);
1303 inrun
= layout_get_next_inline_run(layout
, NULL
);
1305 skiptransform
= should_skip_transform(&layout
->transform
, &det
);
1307 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1308 FLOAT width
= layout_get_line_width(layout
, erun
, inrun
, line
);
1309 FLOAT shift
= layout_get_centered_shift(layout
, skiptransform
, width
, det
);
1314 while (erun
&& erun
->line
== line
) {
1315 erun
->align_dx
= shift
;
1316 erun
= layout_get_next_erun(layout
, erun
);
1319 while (inrun
&& inrun
->line
== line
) {
1320 inrun
->align_dx
= shift
;
1321 inrun
= layout_get_next_inline_run(layout
, inrun
);
1325 layout
->metrics
.left
= (layout
->metrics
.layoutWidth
- layout
->metrics
.width
) / 2.0f
;
1328 static void layout_apply_text_alignment(struct dwrite_textlayout
*layout
)
1330 switch (layout
->format
.textalignment
)
1332 case DWRITE_TEXT_ALIGNMENT_LEADING
:
1333 layout_apply_leading_alignment(layout
);
1335 case DWRITE_TEXT_ALIGNMENT_TRAILING
:
1336 layout_apply_trailing_alignment(layout
);
1338 case DWRITE_TEXT_ALIGNMENT_CENTER
:
1339 layout_apply_centered_alignment(layout
);
1341 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED
:
1342 FIXME("alignment %d not implemented\n", layout
->format
.textalignment
);
1349 static void layout_apply_par_alignment(struct dwrite_textlayout
*layout
)
1351 struct layout_effective_inline
*inrun
;
1352 struct layout_effective_run
*erun
;
1353 FLOAT origin_y
= 0.0f
;
1356 /* alignment mode defines origin, after that all run origins are updated
1359 switch (layout
->format
.paralign
)
1361 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR
:
1364 case DWRITE_PARAGRAPH_ALIGNMENT_FAR
:
1365 origin_y
= layout
->metrics
.layoutHeight
- layout
->metrics
.height
;
1367 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER
:
1368 origin_y
= (layout
->metrics
.layoutHeight
- layout
->metrics
.height
) / 2.0f
;
1374 layout
->metrics
.top
= origin_y
;
1376 erun
= layout_get_next_erun(layout
, NULL
);
1377 inrun
= layout_get_next_inline_run(layout
, NULL
);
1378 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1379 origin_y
+= layout
->lines
[line
].baseline
;
1381 while (erun
&& erun
->line
== line
) {
1382 erun
->origin_y
= origin_y
;
1383 erun
= layout_get_next_erun(layout
, erun
);
1386 while (inrun
&& inrun
->line
== line
) {
1387 inrun
->origin_y
= origin_y
;
1388 inrun
= layout_get_next_inline_run(layout
, inrun
);
1393 static HRESULT
layout_compute_effective_runs(struct dwrite_textlayout
*layout
)
1395 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1396 struct layout_effective_inline
*inrun
;
1397 struct layout_effective_run
*erun
;
1398 const struct layout_run
*run
;
1399 DWRITE_LINE_METRICS metrics
;
1400 FLOAT width
, origin_x
, origin_y
;
1401 UINT32 i
, start
, line
, textpos
;
1405 if (!(layout
->recompute
& RECOMPUTE_EFFECTIVE_RUNS
))
1408 hr
= layout_compute(layout
);
1412 layout
->metrics
.lineCount
= 0;
1413 origin_x
= is_rtl
? layout
->metrics
.layoutWidth
: 0.0f
;
1415 run
= layout
->clusters
[0].run
;
1416 memset(&metrics
, 0, sizeof(metrics
));
1417 s
[0] = s
[1] = layout_get_strikethrough_from_pos(layout
, 0);
1419 for (i
= 0, start
= 0, textpos
= 0, width
= 0.0f
; i
< layout
->cluster_count
; i
++) {
1422 s
[1] = layout_get_strikethrough_from_pos(layout
, textpos
);
1424 /* switched to next nominal run, at this point all previous pending clusters are already
1425 checked for layout line overflow, so new effective run will fit in current line */
1426 if (run
!= layout
->clusters
[i
].run
|| s
[0] != s
[1]) {
1427 hr
= layout_add_effective_run(layout
, run
, start
, i
- start
, line
, origin_x
, s
[0]);
1430 origin_x
+= is_rtl
? -get_cluster_range_width(layout
, start
, i
) :
1431 get_cluster_range_width(layout
, start
, i
);
1432 run
= layout
->clusters
[i
].run
;
1436 overflow
= layout
->clustermetrics
[i
].canWrapLineAfter
&&
1437 (width
+ layout
->clustermetrics
[i
].width
> layout
->metrics
.layoutWidth
);
1438 /* check if we got new */
1440 layout
->clustermetrics
[i
].isNewline
|| /* always wrap on new line */
1441 i
== layout
->cluster_count
- 1) /* end of the text */ {
1443 UINT32 strlength
, last_cluster
, index
;
1444 FLOAT descent
, trailingspacewidth
;
1447 width
+= layout
->clustermetrics
[i
].width
;
1448 metrics
.length
+= layout
->clustermetrics
[i
].length
;
1452 last_cluster
= i
? i
- 1 : i
;
1455 hr
= layout_add_effective_run(layout
, run
, start
, last_cluster
- start
+ 1, line
, origin_x
, s
[0]);
1458 /* we don't need to update origin for next run as we're going to wrap */
1461 /* take a look at clusters we got for this line in reverse order to set
1462 trailing properties for current line */
1463 strlength
= metrics
.length
;
1464 index
= last_cluster
;
1465 trailingspacewidth
= 0.0f
;
1467 DWRITE_CLUSTER_METRICS
*cluster
= &layout
->clustermetrics
[index
];
1469 if (!cluster
->isNewline
&& !cluster
->isWhitespace
)
1472 if (cluster
->isNewline
) {
1473 metrics
.trailingWhitespaceLength
+= cluster
->length
;
1474 metrics
.newlineLength
+= cluster
->length
;
1477 if (cluster
->isWhitespace
) {
1478 metrics
.trailingWhitespaceLength
+= cluster
->length
;
1479 trailingspacewidth
+= cluster
->width
;
1482 strlength
-= cluster
->length
;
1486 /* look for max baseline and descent for this line */
1487 strlength
= metrics
.length
;
1488 index
= last_cluster
;
1489 metrics
.baseline
= 0.0f
;
1492 DWRITE_CLUSTER_METRICS
*cluster
= &layout
->clustermetrics
[index
];
1493 const struct layout_run
*cur
= layout
->clusters
[index
].run
;
1494 FLOAT cur_descent
= cur
->height
- cur
->baseline
;
1496 if (cur
->baseline
> metrics
.baseline
)
1497 metrics
.baseline
= cur
->baseline
;
1499 if (cur_descent
> descent
)
1500 descent
= cur_descent
;
1502 strlength
-= cluster
->length
;
1505 metrics
.height
= descent
+ metrics
.baseline
;
1507 if (width
> layout
->metrics
.widthIncludingTrailingWhitespace
)
1508 layout
->metrics
.widthIncludingTrailingWhitespace
= width
;
1509 if (width
- trailingspacewidth
> layout
->metrics
.width
)
1510 layout
->metrics
.width
= width
- trailingspacewidth
;
1512 metrics
.isTrimmed
= width
> layout
->metrics
.layoutWidth
;
1513 hr
= layout_set_line_metrics(layout
, &metrics
, &line
);
1517 width
= layout
->clustermetrics
[i
].width
;
1518 memset(&metrics
, 0, sizeof(metrics
));
1519 origin_x
= is_rtl
? layout
->metrics
.layoutWidth
: 0.0f
;
1523 metrics
.length
+= layout
->clustermetrics
[i
].length
;
1524 width
+= layout
->clustermetrics
[i
].width
;
1528 textpos
+= layout
->clustermetrics
[i
].length
;
1531 layout
->metrics
.left
= is_rtl
? layout
->metrics
.layoutWidth
- layout
->metrics
.width
: 0;
1532 layout
->metrics
.top
= 0.0f
;
1533 layout
->metrics
.maxBidiReorderingDepth
= 1; /* FIXME */
1534 layout
->metrics
.height
= 0.0f
;
1536 /* Now all line info is here, update effective runs positions in flow direction */
1537 erun
= layout_get_next_erun(layout
, NULL
);
1538 inrun
= layout_get_next_inline_run(layout
, NULL
);
1541 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1543 origin_y
+= layout
->lines
[line
].baseline
;
1545 /* For all runs on this line */
1546 while (erun
&& erun
->line
== line
) {
1547 erun
->origin_y
= origin_y
;
1548 erun
= layout_get_next_erun(layout
, erun
);
1551 /* Same for inline runs */
1552 while (inrun
&& inrun
->line
== line
) {
1553 inrun
->origin_y
= origin_y
;
1554 inrun
= layout_get_next_inline_run(layout
, inrun
);
1557 layout
->metrics
.height
+= layout
->lines
[line
].height
;
1560 /* initial alignment is always leading */
1561 if (layout
->format
.textalignment
!= DWRITE_TEXT_ALIGNMENT_LEADING
)
1562 layout_apply_text_alignment(layout
);
1564 /* initial paragraph alignment is always near */
1565 if (layout
->format
.paralign
!= DWRITE_PARAGRAPH_ALIGNMENT_NEAR
)
1566 layout_apply_par_alignment(layout
);
1568 layout
->metrics
.heightIncludingTrailingWhitespace
= layout
->metrics
.height
; /* FIXME: not true for vertical text */
1570 layout
->recompute
&= ~RECOMPUTE_EFFECTIVE_RUNS
;
1574 static BOOL
is_same_layout_attrvalue(struct layout_range_header
const *h
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
1576 struct layout_range_spacing
const *range_spacing
= (struct layout_range_spacing
*)h
;
1577 struct layout_range_iface
const *range_iface
= (struct layout_range_iface
*)h
;
1578 struct layout_range_bool
const *range_bool
= (struct layout_range_bool
*)h
;
1579 struct layout_range
const *range
= (struct layout_range
*)h
;
1582 case LAYOUT_RANGE_ATTR_WEIGHT
:
1583 return range
->weight
== value
->u
.weight
;
1584 case LAYOUT_RANGE_ATTR_STYLE
:
1585 return range
->style
== value
->u
.style
;
1586 case LAYOUT_RANGE_ATTR_STRETCH
:
1587 return range
->stretch
== value
->u
.stretch
;
1588 case LAYOUT_RANGE_ATTR_FONTSIZE
:
1589 return range
->fontsize
== value
->u
.fontsize
;
1590 case LAYOUT_RANGE_ATTR_INLINE
:
1591 return range
->object
== value
->u
.object
;
1592 case LAYOUT_RANGE_ATTR_EFFECT
:
1593 return range_iface
->iface
== value
->u
.effect
;
1594 case LAYOUT_RANGE_ATTR_UNDERLINE
:
1595 return range
->underline
== value
->u
.underline
;
1596 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
1597 return range_bool
->value
== value
->u
.strikethrough
;
1598 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
1599 return range
->pair_kerning
== value
->u
.pair_kerning
;
1600 case LAYOUT_RANGE_ATTR_FONTCOLL
:
1601 return range
->collection
== value
->u
.collection
;
1602 case LAYOUT_RANGE_ATTR_LOCALE
:
1603 return strcmpiW(range
->locale
, value
->u
.locale
) == 0;
1604 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
1605 return strcmpW(range
->fontfamily
, value
->u
.fontfamily
) == 0;
1606 case LAYOUT_RANGE_ATTR_SPACING
:
1607 return range_spacing
->leading
== value
->u
.spacing
[0] &&
1608 range_spacing
->trailing
== value
->u
.spacing
[1] &&
1609 range_spacing
->min_advance
== value
->u
.spacing
[2];
1610 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
1611 return range_iface
->iface
== (IUnknown
*)value
->u
.typography
;
1619 static inline BOOL
is_same_layout_attributes(struct layout_range_header
const *hleft
, struct layout_range_header
const *hright
)
1621 switch (hleft
->kind
)
1623 case LAYOUT_RANGE_REGULAR
:
1625 struct layout_range
const *left
= (struct layout_range
const*)hleft
;
1626 struct layout_range
const *right
= (struct layout_range
const*)hright
;
1627 return left
->weight
== right
->weight
&&
1628 left
->style
== right
->style
&&
1629 left
->stretch
== right
->stretch
&&
1630 left
->fontsize
== right
->fontsize
&&
1631 left
->object
== right
->object
&&
1632 left
->underline
== right
->underline
&&
1633 left
->pair_kerning
== right
->pair_kerning
&&
1634 left
->collection
== right
->collection
&&
1635 !strcmpiW(left
->locale
, right
->locale
) &&
1636 !strcmpW(left
->fontfamily
, right
->fontfamily
);
1638 case LAYOUT_RANGE_STRIKETHROUGH
:
1640 struct layout_range_bool
const *left
= (struct layout_range_bool
const*)hleft
;
1641 struct layout_range_bool
const *right
= (struct layout_range_bool
const*)hright
;
1642 return left
->value
== right
->value
;
1644 case LAYOUT_RANGE_EFFECT
:
1645 case LAYOUT_RANGE_TYPOGRAPHY
:
1647 struct layout_range_iface
const *left
= (struct layout_range_iface
const*)hleft
;
1648 struct layout_range_iface
const *right
= (struct layout_range_iface
const*)hright
;
1649 return left
->iface
== right
->iface
;
1651 case LAYOUT_RANGE_SPACING
:
1653 struct layout_range_spacing
const *left
= (struct layout_range_spacing
const*)hleft
;
1654 struct layout_range_spacing
const *right
= (struct layout_range_spacing
const*)hright
;
1655 return left
->leading
== right
->leading
&&
1656 left
->trailing
== right
->trailing
&&
1657 left
->min_advance
== right
->min_advance
;
1660 FIXME("unknown range kind %d\n", hleft
->kind
);
1665 static inline BOOL
is_same_text_range(const DWRITE_TEXT_RANGE
*left
, const DWRITE_TEXT_RANGE
*right
)
1667 return left
->startPosition
== right
->startPosition
&& left
->length
== right
->length
;
1670 /* Allocates range and inits it with default values from text format. */
1671 static struct layout_range_header
*alloc_layout_range(struct dwrite_textlayout
*layout
, const DWRITE_TEXT_RANGE
*r
,
1672 enum layout_range_kind kind
)
1674 struct layout_range_header
*h
;
1678 case LAYOUT_RANGE_REGULAR
:
1680 struct layout_range
*range
;
1682 range
= heap_alloc(sizeof(*range
));
1683 if (!range
) return NULL
;
1685 range
->weight
= layout
->format
.weight
;
1686 range
->style
= layout
->format
.style
;
1687 range
->stretch
= layout
->format
.stretch
;
1688 range
->fontsize
= layout
->format
.fontsize
;
1689 range
->object
= NULL
;
1690 range
->underline
= FALSE
;
1691 range
->pair_kerning
= FALSE
;
1693 range
->fontfamily
= heap_strdupW(layout
->format
.family_name
);
1694 if (!range
->fontfamily
) {
1699 range
->collection
= layout
->format
.collection
;
1700 if (range
->collection
)
1701 IDWriteFontCollection_AddRef(range
->collection
);
1702 strcpyW(range
->locale
, layout
->format
.locale
);
1707 case LAYOUT_RANGE_STRIKETHROUGH
:
1709 struct layout_range_bool
*range
;
1711 range
= heap_alloc(sizeof(*range
));
1712 if (!range
) return NULL
;
1714 range
->value
= FALSE
;
1718 case LAYOUT_RANGE_EFFECT
:
1719 case LAYOUT_RANGE_TYPOGRAPHY
:
1721 struct layout_range_iface
*range
;
1723 range
= heap_alloc(sizeof(*range
));
1724 if (!range
) return NULL
;
1726 range
->iface
= NULL
;
1730 case LAYOUT_RANGE_SPACING
:
1732 struct layout_range_spacing
*range
;
1734 range
= heap_alloc(sizeof(*range
));
1735 if (!range
) return NULL
;
1737 range
->leading
= 0.0f
;
1738 range
->trailing
= 0.0f
;
1739 range
->min_advance
= 0.0f
;
1744 FIXME("unknown range kind %d\n", kind
);
1753 static struct layout_range_header
*alloc_layout_range_from(struct layout_range_header
*h
, const DWRITE_TEXT_RANGE
*r
)
1755 struct layout_range_header
*ret
;
1759 case LAYOUT_RANGE_REGULAR
:
1761 struct layout_range
*from
= (struct layout_range
*)h
;
1763 struct layout_range
*range
= heap_alloc(sizeof(*range
));
1764 if (!range
) return NULL
;
1767 range
->fontfamily
= heap_strdupW(from
->fontfamily
);
1768 if (!range
->fontfamily
) {
1773 /* update refcounts */
1775 IDWriteInlineObject_AddRef(range
->object
);
1776 if (range
->collection
)
1777 IDWriteFontCollection_AddRef(range
->collection
);
1781 case LAYOUT_RANGE_STRIKETHROUGH
:
1783 struct layout_range_bool
*strike
= heap_alloc(sizeof(*strike
));
1784 if (!strike
) return NULL
;
1786 *strike
= *(struct layout_range_bool
*)h
;
1790 case LAYOUT_RANGE_EFFECT
:
1791 case LAYOUT_RANGE_TYPOGRAPHY
:
1793 struct layout_range_iface
*effect
= heap_alloc(sizeof(*effect
));
1794 if (!effect
) return NULL
;
1796 *effect
= *(struct layout_range_iface
*)h
;
1798 IUnknown_AddRef(effect
->iface
);
1802 case LAYOUT_RANGE_SPACING
:
1804 struct layout_range_spacing
*spacing
= heap_alloc(sizeof(*spacing
));
1805 if (!spacing
) return NULL
;
1807 *spacing
= *(struct layout_range_spacing
*)h
;
1812 FIXME("unknown range kind %d\n", h
->kind
);
1820 static void free_layout_range(struct layout_range_header
*h
)
1827 case LAYOUT_RANGE_REGULAR
:
1829 struct layout_range
*range
= (struct layout_range
*)h
;
1832 IDWriteInlineObject_Release(range
->object
);
1833 if (range
->collection
)
1834 IDWriteFontCollection_Release(range
->collection
);
1835 heap_free(range
->fontfamily
);
1838 case LAYOUT_RANGE_EFFECT
:
1839 case LAYOUT_RANGE_TYPOGRAPHY
:
1841 struct layout_range_iface
*range
= (struct layout_range_iface
*)h
;
1843 IUnknown_Release(range
->iface
);
1853 static void free_layout_ranges_list(struct dwrite_textlayout
*layout
)
1855 struct layout_range_header
*cur
, *cur2
;
1857 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->ranges
, struct layout_range_header
, entry
) {
1858 list_remove(&cur
->entry
);
1859 free_layout_range(cur
);
1862 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->strike_ranges
, struct layout_range_header
, entry
) {
1863 list_remove(&cur
->entry
);
1864 free_layout_range(cur
);
1867 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->effects
, struct layout_range_header
, entry
) {
1868 list_remove(&cur
->entry
);
1869 free_layout_range(cur
);
1872 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->spacing
, struct layout_range_header
, entry
) {
1873 list_remove(&cur
->entry
);
1874 free_layout_range(cur
);
1877 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->typographies
, struct layout_range_header
, entry
) {
1878 list_remove(&cur
->entry
);
1879 free_layout_range(cur
);
1883 static struct layout_range_header
*find_outer_range(struct list
*ranges
, const DWRITE_TEXT_RANGE
*range
)
1885 struct layout_range_header
*cur
;
1887 LIST_FOR_EACH_ENTRY(cur
, ranges
, struct layout_range_header
, entry
) {
1889 if (cur
->range
.startPosition
> range
->startPosition
)
1892 if ((cur
->range
.startPosition
+ cur
->range
.length
< range
->startPosition
+ range
->length
) &&
1893 (range
->startPosition
< cur
->range
.startPosition
+ cur
->range
.length
))
1895 if (cur
->range
.startPosition
+ cur
->range
.length
>= range
->startPosition
+ range
->length
)
1902 static struct layout_range
*get_layout_range_by_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
1904 struct layout_range
*cur
;
1906 LIST_FOR_EACH_ENTRY(cur
, &layout
->ranges
, struct layout_range
, h
.entry
) {
1907 DWRITE_TEXT_RANGE
*r
= &cur
->h
.range
;
1908 if (r
->startPosition
<= pos
&& pos
< r
->startPosition
+ r
->length
)
1915 static inline BOOL
set_layout_range_iface_attr(IUnknown
**dest
, IUnknown
*value
)
1917 if (*dest
== value
) return FALSE
;
1920 IUnknown_Release(*dest
);
1923 IUnknown_AddRef(*dest
);
1928 static BOOL
set_layout_range_attrval(struct layout_range_header
*h
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
1930 struct layout_range_spacing
*dest_spacing
= (struct layout_range_spacing
*)h
;
1931 struct layout_range_iface
*dest_iface
= (struct layout_range_iface
*)h
;
1932 struct layout_range_bool
*dest_bool
= (struct layout_range_bool
*)h
;
1933 struct layout_range
*dest
= (struct layout_range
*)h
;
1935 BOOL changed
= FALSE
;
1938 case LAYOUT_RANGE_ATTR_WEIGHT
:
1939 changed
= dest
->weight
!= value
->u
.weight
;
1940 dest
->weight
= value
->u
.weight
;
1942 case LAYOUT_RANGE_ATTR_STYLE
:
1943 changed
= dest
->style
!= value
->u
.style
;
1944 dest
->style
= value
->u
.style
;
1946 case LAYOUT_RANGE_ATTR_STRETCH
:
1947 changed
= dest
->stretch
!= value
->u
.stretch
;
1948 dest
->stretch
= value
->u
.stretch
;
1950 case LAYOUT_RANGE_ATTR_FONTSIZE
:
1951 changed
= dest
->fontsize
!= value
->u
.fontsize
;
1952 dest
->fontsize
= value
->u
.fontsize
;
1954 case LAYOUT_RANGE_ATTR_INLINE
:
1955 changed
= set_layout_range_iface_attr((IUnknown
**)&dest
->object
, (IUnknown
*)value
->u
.object
);
1957 case LAYOUT_RANGE_ATTR_EFFECT
:
1958 changed
= set_layout_range_iface_attr((IUnknown
**)&dest_iface
->iface
, (IUnknown
*)value
->u
.effect
);
1960 case LAYOUT_RANGE_ATTR_UNDERLINE
:
1961 changed
= dest
->underline
!= value
->u
.underline
;
1962 dest
->underline
= value
->u
.underline
;
1964 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
1965 changed
= dest_bool
->value
!= value
->u
.strikethrough
;
1966 dest_bool
->value
= value
->u
.strikethrough
;
1968 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
1969 changed
= dest
->pair_kerning
!= value
->u
.pair_kerning
;
1970 dest
->pair_kerning
= value
->u
.pair_kerning
;
1972 case LAYOUT_RANGE_ATTR_FONTCOLL
:
1973 changed
= set_layout_range_iface_attr((IUnknown
**)&dest
->collection
, (IUnknown
*)value
->u
.collection
);
1975 case LAYOUT_RANGE_ATTR_LOCALE
:
1976 changed
= strcmpiW(dest
->locale
, value
->u
.locale
) != 0;
1978 strcpyW(dest
->locale
, value
->u
.locale
);
1980 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
1981 changed
= strcmpW(dest
->fontfamily
, value
->u
.fontfamily
) != 0;
1983 heap_free(dest
->fontfamily
);
1984 dest
->fontfamily
= heap_strdupW(value
->u
.fontfamily
);
1987 case LAYOUT_RANGE_ATTR_SPACING
:
1988 changed
= dest_spacing
->leading
!= value
->u
.spacing
[0] ||
1989 dest_spacing
->trailing
!= value
->u
.spacing
[1] ||
1990 dest_spacing
->min_advance
!= value
->u
.spacing
[2];
1991 dest_spacing
->leading
= value
->u
.spacing
[0];
1992 dest_spacing
->trailing
= value
->u
.spacing
[1];
1993 dest_spacing
->min_advance
= value
->u
.spacing
[2];
1995 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
1996 changed
= set_layout_range_iface_attr((IUnknown
**)&dest_iface
->iface
, (IUnknown
*)value
->u
.typography
);
2005 static inline BOOL
is_in_layout_range(const DWRITE_TEXT_RANGE
*outer
, const DWRITE_TEXT_RANGE
*inner
)
2007 return (inner
->startPosition
>= outer
->startPosition
) &&
2008 (inner
->startPosition
+ inner
->length
<= outer
->startPosition
+ outer
->length
);
2011 static inline HRESULT
return_range(const struct layout_range_header
*h
, DWRITE_TEXT_RANGE
*r
)
2013 if (r
) *r
= h
->range
;
2017 /* Set attribute value for given range, does all needed splitting/merging of existing ranges. */
2018 static HRESULT
set_layout_range_attr(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
2020 struct layout_range_header
*cur
, *right
, *left
, *outer
;
2021 BOOL changed
= FALSE
;
2022 struct list
*ranges
;
2023 DWRITE_TEXT_RANGE r
;
2025 /* ignore zero length ranges */
2026 if (value
->range
.length
== 0)
2029 /* select from ranges lists */
2032 case LAYOUT_RANGE_ATTR_WEIGHT
:
2033 case LAYOUT_RANGE_ATTR_STYLE
:
2034 case LAYOUT_RANGE_ATTR_STRETCH
:
2035 case LAYOUT_RANGE_ATTR_FONTSIZE
:
2036 case LAYOUT_RANGE_ATTR_INLINE
:
2037 case LAYOUT_RANGE_ATTR_UNDERLINE
:
2038 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
2039 case LAYOUT_RANGE_ATTR_FONTCOLL
:
2040 case LAYOUT_RANGE_ATTR_LOCALE
:
2041 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2042 ranges
= &layout
->ranges
;
2044 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
2045 ranges
= &layout
->strike_ranges
;
2047 case LAYOUT_RANGE_ATTR_EFFECT
:
2048 ranges
= &layout
->effects
;
2050 case LAYOUT_RANGE_ATTR_SPACING
:
2051 ranges
= &layout
->spacing
;
2053 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
2054 ranges
= &layout
->typographies
;
2057 FIXME("unknown attr kind %d\n", attr
);
2061 /* If new range is completely within existing range, split existing range in two */
2062 if ((outer
= find_outer_range(ranges
, &value
->range
))) {
2064 /* no need to add same range */
2065 if (is_same_layout_attrvalue(outer
, attr
, value
))
2068 /* for matching range bounds just replace data */
2069 if (is_same_text_range(&outer
->range
, &value
->range
)) {
2070 changed
= set_layout_range_attrval(outer
, attr
, value
);
2074 /* add new range to the left */
2075 if (value
->range
.startPosition
== outer
->range
.startPosition
) {
2076 left
= alloc_layout_range_from(outer
, &value
->range
);
2077 if (!left
) return E_OUTOFMEMORY
;
2079 changed
= set_layout_range_attrval(left
, attr
, value
);
2080 list_add_before(&outer
->entry
, &left
->entry
);
2081 outer
->range
.startPosition
+= value
->range
.length
;
2082 outer
->range
.length
-= value
->range
.length
;
2086 /* add new range to the right */
2087 if (value
->range
.startPosition
+ value
->range
.length
== outer
->range
.startPosition
+ outer
->range
.length
) {
2088 right
= alloc_layout_range_from(outer
, &value
->range
);
2089 if (!right
) return E_OUTOFMEMORY
;
2091 changed
= set_layout_range_attrval(right
, attr
, value
);
2092 list_add_after(&outer
->entry
, &right
->entry
);
2093 outer
->range
.length
-= value
->range
.length
;
2097 r
.startPosition
= value
->range
.startPosition
+ value
->range
.length
;
2098 r
.length
= outer
->range
.length
+ outer
->range
.startPosition
- r
.startPosition
;
2101 right
= alloc_layout_range_from(outer
, &r
);
2102 /* new range in the middle */
2103 cur
= alloc_layout_range_from(outer
, &value
->range
);
2104 if (!right
|| !cur
) {
2105 free_layout_range(right
);
2106 free_layout_range(cur
);
2107 return E_OUTOFMEMORY
;
2110 /* reuse container range as a left part */
2111 outer
->range
.length
= value
->range
.startPosition
- outer
->range
.startPosition
;
2114 set_layout_range_attrval(cur
, attr
, value
);
2116 list_add_after(&outer
->entry
, &cur
->entry
);
2117 list_add_after(&cur
->entry
, &right
->entry
);
2122 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2123 Update all of them. */
2124 left
= get_layout_range_header_by_pos(ranges
, value
->range
.startPosition
);
2125 if (left
->range
.startPosition
== value
->range
.startPosition
)
2126 changed
= set_layout_range_attrval(left
, attr
, value
);
2127 else /* need to split */ {
2128 r
.startPosition
= value
->range
.startPosition
;
2129 r
.length
= left
->range
.length
- value
->range
.startPosition
+ left
->range
.startPosition
;
2130 left
->range
.length
-= r
.length
;
2131 cur
= alloc_layout_range_from(left
, &r
);
2132 changed
= set_layout_range_attrval(cur
, attr
, value
);
2133 list_add_after(&left
->entry
, &cur
->entry
);
2135 cur
= LIST_ENTRY(list_next(ranges
, &left
->entry
), struct layout_range_header
, entry
);
2137 /* for all existing ranges covered by new one update value */
2138 while (cur
&& is_in_layout_range(&value
->range
, &cur
->range
)) {
2139 changed
|= set_layout_range_attrval(cur
, attr
, value
);
2140 cur
= LIST_ENTRY(list_next(ranges
, &cur
->entry
), struct layout_range_header
, entry
);
2143 /* it's possible rightmost range intersects */
2144 if (cur
&& (cur
->range
.startPosition
< value
->range
.startPosition
+ value
->range
.length
)) {
2145 r
.startPosition
= cur
->range
.startPosition
;
2146 r
.length
= value
->range
.startPosition
+ value
->range
.length
- cur
->range
.startPosition
;
2147 left
= alloc_layout_range_from(cur
, &r
);
2148 changed
|= set_layout_range_attrval(left
, attr
, value
);
2149 cur
->range
.startPosition
+= left
->range
.length
;
2150 cur
->range
.length
-= left
->range
.length
;
2151 list_add_before(&cur
->entry
, &left
->entry
);
2156 struct list
*next
, *i
;
2158 layout
->recompute
= RECOMPUTE_EVERYTHING
;
2159 i
= list_head(ranges
);
2160 while ((next
= list_next(ranges
, i
))) {
2161 struct layout_range_header
*next_range
= LIST_ENTRY(next
, struct layout_range_header
, entry
);
2163 cur
= LIST_ENTRY(i
, struct layout_range_header
, entry
);
2164 if (is_same_layout_attributes(cur
, next_range
)) {
2165 /* remove similar range */
2166 cur
->range
.length
+= next_range
->range
.length
;
2168 free_layout_range(next_range
);
2171 i
= list_next(ranges
, i
);
2178 static inline const WCHAR
*get_string_attribute_ptr(struct layout_range
*range
, enum layout_range_attr_kind kind
)
2183 case LAYOUT_RANGE_ATTR_LOCALE
:
2184 str
= range
->locale
;
2186 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2187 str
= range
->fontfamily
;
2196 static HRESULT
get_string_attribute_length(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind kind
, UINT32 position
,
2197 UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
2199 struct layout_range
*range
;
2202 range
= get_layout_range_by_pos(layout
, position
);
2208 str
= get_string_attribute_ptr(range
, kind
);
2209 *length
= strlenW(str
);
2210 return return_range(&range
->h
, r
);
2213 static HRESULT
get_string_attribute_value(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind kind
, UINT32 position
,
2214 WCHAR
*ret
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
2216 struct layout_range
*range
;
2220 return E_INVALIDARG
;
2223 range
= get_layout_range_by_pos(layout
, position
);
2225 return E_INVALIDARG
;
2227 str
= get_string_attribute_ptr(range
, kind
);
2228 if (length
< strlenW(str
) + 1)
2229 return E_NOT_SUFFICIENT_BUFFER
;
2232 return return_range(&range
->h
, r
);
2235 static HRESULT WINAPI
dwritetextlayout_QueryInterface(IDWriteTextLayout2
*iface
, REFIID riid
, void **obj
)
2237 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2239 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
2243 if (IsEqualIID(riid
, &IID_IDWriteTextLayout2
) ||
2244 IsEqualIID(riid
, &IID_IDWriteTextLayout1
) ||
2245 IsEqualIID(riid
, &IID_IDWriteTextLayout
) ||
2246 IsEqualIID(riid
, &IID_IUnknown
))
2250 else if (IsEqualIID(riid
, &IID_IDWriteTextFormat1
) ||
2251 IsEqualIID(riid
, &IID_IDWriteTextFormat
))
2252 *obj
= &This
->IDWriteTextFormat1_iface
;
2255 IDWriteTextLayout2_AddRef(iface
);
2259 return E_NOINTERFACE
;
2262 static ULONG WINAPI
dwritetextlayout_AddRef(IDWriteTextLayout2
*iface
)
2264 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2265 ULONG ref
= InterlockedIncrement(&This
->ref
);
2266 TRACE("(%p)->(%d)\n", This
, ref
);
2270 static ULONG WINAPI
dwritetextlayout_Release(IDWriteTextLayout2
*iface
)
2272 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2273 ULONG ref
= InterlockedDecrement(&This
->ref
);
2275 TRACE("(%p)->(%d)\n", This
, ref
);
2278 free_layout_ranges_list(This
);
2279 free_layout_eruns(This
);
2280 free_layout_runs(This
);
2281 release_format_data(&This
->format
);
2282 heap_free(This
->nominal_breakpoints
);
2283 heap_free(This
->actual_breakpoints
);
2284 heap_free(This
->clustermetrics
);
2285 heap_free(This
->clusters
);
2286 heap_free(This
->lines
);
2287 heap_free(This
->str
);
2294 static HRESULT WINAPI
dwritetextlayout_SetTextAlignment(IDWriteTextLayout2
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
2296 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2297 return IDWriteTextFormat1_SetTextAlignment(&This
->IDWriteTextFormat1_iface
, alignment
);
2300 static HRESULT WINAPI
dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout2
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
2302 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2303 return IDWriteTextFormat1_SetParagraphAlignment(&This
->IDWriteTextFormat1_iface
, alignment
);
2306 static HRESULT WINAPI
dwritetextlayout_SetWordWrapping(IDWriteTextLayout2
*iface
, DWRITE_WORD_WRAPPING wrapping
)
2308 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2309 return IDWriteTextFormat1_SetWordWrapping(&This
->IDWriteTextFormat1_iface
, wrapping
);
2312 static HRESULT WINAPI
dwritetextlayout_SetReadingDirection(IDWriteTextLayout2
*iface
, DWRITE_READING_DIRECTION direction
)
2314 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2315 return IDWriteTextFormat1_SetReadingDirection(&This
->IDWriteTextFormat1_iface
, direction
);
2318 static HRESULT WINAPI
dwritetextlayout_SetFlowDirection(IDWriteTextLayout2
*iface
, DWRITE_FLOW_DIRECTION direction
)
2320 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2321 TRACE("(%p)->(%d)\n", This
, direction
);
2322 return IDWriteTextFormat1_SetFlowDirection(&This
->IDWriteTextFormat1_iface
, direction
);
2325 static HRESULT WINAPI
dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout2
*iface
, FLOAT tabstop
)
2327 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2328 TRACE("(%p)->(%.2f)\n", This
, tabstop
);
2329 return IDWriteTextFormat1_SetIncrementalTabStop(&This
->IDWriteTextFormat1_iface
, tabstop
);
2332 static HRESULT WINAPI
dwritetextlayout_SetTrimming(IDWriteTextLayout2
*iface
, DWRITE_TRIMMING
const *trimming
,
2333 IDWriteInlineObject
*trimming_sign
)
2335 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2336 TRACE("(%p)->(%p %p)\n", This
, trimming
, trimming_sign
);
2337 return IDWriteTextFormat1_SetTrimming(&This
->IDWriteTextFormat1_iface
, trimming
, trimming_sign
);
2340 static HRESULT WINAPI
dwritetextlayout_SetLineSpacing(IDWriteTextLayout2
*iface
, DWRITE_LINE_SPACING_METHOD spacing
,
2341 FLOAT line_spacing
, FLOAT baseline
)
2343 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2344 TRACE("(%p)->(%d %.2f %.2f)\n", This
, spacing
, line_spacing
, baseline
);
2345 return IDWriteTextFormat1_SetLineSpacing(&This
->IDWriteTextFormat1_iface
, spacing
, line_spacing
, baseline
);
2348 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextlayout_GetTextAlignment(IDWriteTextLayout2
*iface
)
2350 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2351 return IDWriteTextFormat1_GetTextAlignment(&This
->IDWriteTextFormat1_iface
);
2354 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout2
*iface
)
2356 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2357 return IDWriteTextFormat1_GetParagraphAlignment(&This
->IDWriteTextFormat1_iface
);
2360 static DWRITE_WORD_WRAPPING WINAPI
dwritetextlayout_GetWordWrapping(IDWriteTextLayout2
*iface
)
2362 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2363 return IDWriteTextFormat1_GetWordWrapping(&This
->IDWriteTextFormat1_iface
);
2366 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_GetReadingDirection(IDWriteTextLayout2
*iface
)
2368 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2369 return IDWriteTextFormat1_GetReadingDirection(&This
->IDWriteTextFormat1_iface
);
2372 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextlayout_GetFlowDirection(IDWriteTextLayout2
*iface
)
2374 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2375 return IDWriteTextFormat1_GetFlowDirection(&This
->IDWriteTextFormat1_iface
);
2378 static FLOAT WINAPI
dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout2
*iface
)
2380 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2381 return IDWriteTextFormat1_GetIncrementalTabStop(&This
->IDWriteTextFormat1_iface
);
2384 static HRESULT WINAPI
dwritetextlayout_GetTrimming(IDWriteTextLayout2
*iface
, DWRITE_TRIMMING
*options
,
2385 IDWriteInlineObject
**trimming_sign
)
2387 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2388 return IDWriteTextFormat1_GetTrimming(&This
->IDWriteTextFormat1_iface
, options
, trimming_sign
);
2391 static HRESULT WINAPI
dwritetextlayout_GetLineSpacing(IDWriteTextLayout2
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
2392 FLOAT
*spacing
, FLOAT
*baseline
)
2394 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2395 return IDWriteTextFormat1_GetLineSpacing(&This
->IDWriteTextFormat1_iface
, method
, spacing
, baseline
);
2398 static HRESULT WINAPI
dwritetextlayout_GetFontCollection(IDWriteTextLayout2
*iface
, IDWriteFontCollection
**collection
)
2400 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2401 return IDWriteTextFormat1_GetFontCollection(&This
->IDWriteTextFormat1_iface
, collection
);
2404 static UINT32 WINAPI
dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout2
*iface
)
2406 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2407 return IDWriteTextFormat1_GetFontFamilyNameLength(&This
->IDWriteTextFormat1_iface
);
2410 static HRESULT WINAPI
dwritetextlayout_GetFontFamilyName(IDWriteTextLayout2
*iface
, WCHAR
*name
, UINT32 size
)
2412 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2413 return IDWriteTextFormat1_GetFontFamilyName(&This
->IDWriteTextFormat1_iface
, name
, size
);
2416 static DWRITE_FONT_WEIGHT WINAPI
dwritetextlayout_GetFontWeight(IDWriteTextLayout2
*iface
)
2418 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2419 return IDWriteTextFormat1_GetFontWeight(&This
->IDWriteTextFormat1_iface
);
2422 static DWRITE_FONT_STYLE WINAPI
dwritetextlayout_GetFontStyle(IDWriteTextLayout2
*iface
)
2424 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2425 return IDWriteTextFormat1_GetFontStyle(&This
->IDWriteTextFormat1_iface
);
2428 static DWRITE_FONT_STRETCH WINAPI
dwritetextlayout_GetFontStretch(IDWriteTextLayout2
*iface
)
2430 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2431 return IDWriteTextFormat1_GetFontStretch(&This
->IDWriteTextFormat1_iface
);
2434 static FLOAT WINAPI
dwritetextlayout_GetFontSize(IDWriteTextLayout2
*iface
)
2436 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2437 return IDWriteTextFormat1_GetFontSize(&This
->IDWriteTextFormat1_iface
);
2440 static UINT32 WINAPI
dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout2
*iface
)
2442 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2443 return IDWriteTextFormat1_GetLocaleNameLength(&This
->IDWriteTextFormat1_iface
);
2446 static HRESULT WINAPI
dwritetextlayout_GetLocaleName(IDWriteTextLayout2
*iface
, WCHAR
*name
, UINT32 size
)
2448 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2449 return IDWriteTextFormat1_GetLocaleName(&This
->IDWriteTextFormat1_iface
, name
, size
);
2452 static HRESULT WINAPI
dwritetextlayout_SetMaxWidth(IDWriteTextLayout2
*iface
, FLOAT maxWidth
)
2454 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2456 TRACE("(%p)->(%.2f)\n", This
, maxWidth
);
2458 if (maxWidth
< 0.0f
)
2459 return E_INVALIDARG
;
2461 This
->metrics
.layoutWidth
= maxWidth
;
2465 static HRESULT WINAPI
dwritetextlayout_SetMaxHeight(IDWriteTextLayout2
*iface
, FLOAT maxHeight
)
2467 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2469 TRACE("(%p)->(%.2f)\n", This
, maxHeight
);
2471 if (maxHeight
< 0.0f
)
2472 return E_INVALIDARG
;
2474 This
->metrics
.layoutHeight
= maxHeight
;
2478 static HRESULT WINAPI
dwritetextlayout_SetFontCollection(IDWriteTextLayout2
*iface
, IDWriteFontCollection
* collection
, DWRITE_TEXT_RANGE range
)
2480 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2481 struct layout_range_attr_value value
;
2483 TRACE("(%p)->(%p %s)\n", This
, collection
, debugstr_range(&range
));
2485 value
.range
= range
;
2486 value
.u
.collection
= collection
;
2487 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTCOLL
, &value
);
2490 static HRESULT WINAPI
dwritetextlayout_SetFontFamilyName(IDWriteTextLayout2
*iface
, WCHAR
const *name
, DWRITE_TEXT_RANGE range
)
2492 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2493 struct layout_range_attr_value value
;
2495 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(name
), debugstr_range(&range
));
2498 return E_INVALIDARG
;
2500 value
.range
= range
;
2501 value
.u
.fontfamily
= name
;
2502 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, &value
);
2505 static HRESULT WINAPI
dwritetextlayout_SetFontWeight(IDWriteTextLayout2
*iface
, DWRITE_FONT_WEIGHT weight
, DWRITE_TEXT_RANGE range
)
2507 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2508 struct layout_range_attr_value value
;
2510 TRACE("(%p)->(%d %s)\n", This
, weight
, debugstr_range(&range
));
2512 value
.range
= range
;
2513 value
.u
.weight
= weight
;
2514 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_WEIGHT
, &value
);
2517 static HRESULT WINAPI
dwritetextlayout_SetFontStyle(IDWriteTextLayout2
*iface
, DWRITE_FONT_STYLE style
, DWRITE_TEXT_RANGE range
)
2519 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2520 struct layout_range_attr_value value
;
2522 TRACE("(%p)->(%d %s)\n", This
, style
, debugstr_range(&range
));
2524 if ((UINT32
)style
> DWRITE_FONT_STYLE_ITALIC
)
2525 return E_INVALIDARG
;
2527 value
.range
= range
;
2528 value
.u
.style
= style
;
2529 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STYLE
, &value
);
2532 static HRESULT WINAPI
dwritetextlayout_SetFontStretch(IDWriteTextLayout2
*iface
, DWRITE_FONT_STRETCH stretch
, DWRITE_TEXT_RANGE range
)
2534 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2535 struct layout_range_attr_value value
;
2537 TRACE("(%p)->(%d %s)\n", This
, stretch
, debugstr_range(&range
));
2539 if (stretch
== DWRITE_FONT_STRETCH_UNDEFINED
|| (UINT32
)stretch
> DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
2540 return E_INVALIDARG
;
2542 value
.range
= range
;
2543 value
.u
.stretch
= stretch
;
2544 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STRETCH
, &value
);
2547 static HRESULT WINAPI
dwritetextlayout_SetFontSize(IDWriteTextLayout2
*iface
, FLOAT size
, DWRITE_TEXT_RANGE range
)
2549 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2550 struct layout_range_attr_value value
;
2552 TRACE("(%p)->(%.2f %s)\n", This
, size
, debugstr_range(&range
));
2555 return E_INVALIDARG
;
2557 value
.range
= range
;
2558 value
.u
.fontsize
= size
;
2559 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTSIZE
, &value
);
2562 static HRESULT WINAPI
dwritetextlayout_SetUnderline(IDWriteTextLayout2
*iface
, BOOL underline
, DWRITE_TEXT_RANGE range
)
2564 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2565 struct layout_range_attr_value value
;
2567 TRACE("(%p)->(%d %s)\n", This
, underline
, debugstr_range(&range
));
2569 value
.range
= range
;
2570 value
.u
.underline
= underline
;
2571 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_UNDERLINE
, &value
);
2574 static HRESULT WINAPI
dwritetextlayout_SetStrikethrough(IDWriteTextLayout2
*iface
, BOOL strikethrough
, DWRITE_TEXT_RANGE range
)
2576 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2577 struct layout_range_attr_value value
;
2579 TRACE("(%p)->(%d %s)\n", This
, strikethrough
, debugstr_range(&range
));
2581 value
.range
= range
;
2582 value
.u
.strikethrough
= strikethrough
;
2583 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STRIKETHROUGH
, &value
);
2586 static HRESULT WINAPI
dwritetextlayout_SetDrawingEffect(IDWriteTextLayout2
*iface
, IUnknown
* effect
, DWRITE_TEXT_RANGE range
)
2588 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2589 struct layout_range_attr_value value
;
2591 TRACE("(%p)->(%p %s)\n", This
, effect
, debugstr_range(&range
));
2593 value
.range
= range
;
2594 value
.u
.effect
= effect
;
2595 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_EFFECT
, &value
);
2598 static HRESULT WINAPI
dwritetextlayout_SetInlineObject(IDWriteTextLayout2
*iface
, IDWriteInlineObject
*object
, DWRITE_TEXT_RANGE range
)
2600 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2601 struct layout_range_attr_value value
;
2603 TRACE("(%p)->(%p %s)\n", This
, object
, debugstr_range(&range
));
2605 value
.range
= range
;
2606 value
.u
.object
= object
;
2607 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_INLINE
, &value
);
2610 static HRESULT WINAPI
dwritetextlayout_SetTypography(IDWriteTextLayout2
*iface
, IDWriteTypography
* typography
, DWRITE_TEXT_RANGE range
)
2612 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2613 struct layout_range_attr_value value
;
2615 TRACE("(%p)->(%p %s)\n", This
, typography
, debugstr_range(&range
));
2617 value
.range
= range
;
2618 value
.u
.typography
= typography
;
2619 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_TYPOGRAPHY
, &value
);
2622 static HRESULT WINAPI
dwritetextlayout_SetLocaleName(IDWriteTextLayout2
*iface
, WCHAR
const* locale
, DWRITE_TEXT_RANGE range
)
2624 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2625 struct layout_range_attr_value value
;
2627 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(locale
), debugstr_range(&range
));
2629 if (!locale
|| strlenW(locale
) > LOCALE_NAME_MAX_LENGTH
-1)
2630 return E_INVALIDARG
;
2632 value
.range
= range
;
2633 value
.u
.locale
= locale
;
2634 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_LOCALE
, &value
);
2637 static FLOAT WINAPI
dwritetextlayout_GetMaxWidth(IDWriteTextLayout2
*iface
)
2639 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2640 TRACE("(%p)\n", This
);
2641 return This
->metrics
.layoutWidth
;
2644 static FLOAT WINAPI
dwritetextlayout_GetMaxHeight(IDWriteTextLayout2
*iface
)
2646 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2647 TRACE("(%p)\n", This
);
2648 return This
->metrics
.layoutHeight
;
2651 static HRESULT WINAPI
dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout2
*iface
, UINT32 position
,
2652 IDWriteFontCollection
** collection
, DWRITE_TEXT_RANGE
*r
)
2654 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2655 struct layout_range
*range
;
2657 TRACE("(%p)->(%u %p %p)\n", This
, position
, collection
, r
);
2659 if (position
>= This
->len
)
2662 range
= get_layout_range_by_pos(This
, position
);
2663 *collection
= range
->collection
;
2665 IDWriteFontCollection_AddRef(*collection
);
2667 return return_range(&range
->h
, r
);
2670 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout2
*iface
,
2671 UINT32 position
, UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
2673 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2674 TRACE("(%p)->(%d %p %p)\n", This
, position
, length
, r
);
2675 return get_string_attribute_length(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, length
, r
);
2678 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout2
*iface
,
2679 UINT32 position
, WCHAR
*name
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
2681 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2682 TRACE("(%p)->(%u %p %u %p)\n", This
, position
, name
, length
, r
);
2683 return get_string_attribute_value(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, name
, length
, r
);
2686 static HRESULT WINAPI
dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout2
*iface
,
2687 UINT32 position
, DWRITE_FONT_WEIGHT
*weight
, DWRITE_TEXT_RANGE
*r
)
2689 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2690 struct layout_range
*range
;
2692 TRACE("(%p)->(%u %p %p)\n", This
, position
, weight
, r
);
2694 if (position
>= This
->len
)
2697 range
= get_layout_range_by_pos(This
, position
);
2698 *weight
= range
->weight
;
2700 return return_range(&range
->h
, r
);
2703 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout2
*iface
,
2704 UINT32 position
, DWRITE_FONT_STYLE
*style
, DWRITE_TEXT_RANGE
*r
)
2706 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2707 struct layout_range
*range
;
2709 TRACE("(%p)->(%u %p %p)\n", This
, position
, style
, r
);
2711 range
= get_layout_range_by_pos(This
, position
);
2712 *style
= range
->style
;
2713 return return_range(&range
->h
, r
);
2716 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout2
*iface
,
2717 UINT32 position
, DWRITE_FONT_STRETCH
*stretch
, DWRITE_TEXT_RANGE
*r
)
2719 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2720 struct layout_range
*range
;
2722 TRACE("(%p)->(%u %p %p)\n", This
, position
, stretch
, r
);
2724 range
= get_layout_range_by_pos(This
, position
);
2725 *stretch
= range
->stretch
;
2726 return return_range(&range
->h
, r
);
2729 static HRESULT WINAPI
dwritetextlayout_layout_GetFontSize(IDWriteTextLayout2
*iface
,
2730 UINT32 position
, FLOAT
*size
, DWRITE_TEXT_RANGE
*r
)
2732 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2733 struct layout_range
*range
;
2735 TRACE("(%p)->(%u %p %p)\n", This
, position
, size
, r
);
2737 range
= get_layout_range_by_pos(This
, position
);
2738 *size
= range
->fontsize
;
2739 return return_range(&range
->h
, r
);
2742 static HRESULT WINAPI
dwritetextlayout_GetUnderline(IDWriteTextLayout2
*iface
,
2743 UINT32 position
, BOOL
*underline
, DWRITE_TEXT_RANGE
*r
)
2745 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2746 struct layout_range
*range
;
2748 TRACE("(%p)->(%u %p %p)\n", This
, position
, underline
, r
);
2750 if (position
>= This
->len
)
2753 range
= get_layout_range_by_pos(This
, position
);
2754 *underline
= range
->underline
;
2756 return return_range(&range
->h
, r
);
2759 static HRESULT WINAPI
dwritetextlayout_GetStrikethrough(IDWriteTextLayout2
*iface
,
2760 UINT32 position
, BOOL
*strikethrough
, DWRITE_TEXT_RANGE
*r
)
2762 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2763 struct layout_range_bool
*range
;
2765 TRACE("(%p)->(%u %p %p)\n", This
, position
, strikethrough
, r
);
2767 range
= (struct layout_range_bool
*)get_layout_range_header_by_pos(&This
->strike_ranges
, position
);
2768 *strikethrough
= range
->value
;
2770 return return_range(&range
->h
, r
);
2773 static HRESULT WINAPI
dwritetextlayout_GetDrawingEffect(IDWriteTextLayout2
*iface
,
2774 UINT32 position
, IUnknown
**effect
, DWRITE_TEXT_RANGE
*r
)
2776 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2777 struct layout_range_iface
*range
;
2779 TRACE("(%p)->(%u %p %p)\n", This
, position
, effect
, r
);
2781 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&This
->effects
, position
);
2782 *effect
= range
->iface
;
2784 IUnknown_AddRef(*effect
);
2786 return return_range(&range
->h
, r
);
2789 static HRESULT WINAPI
dwritetextlayout_GetInlineObject(IDWriteTextLayout2
*iface
,
2790 UINT32 position
, IDWriteInlineObject
**object
, DWRITE_TEXT_RANGE
*r
)
2792 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2793 struct layout_range
*range
;
2795 TRACE("(%p)->(%u %p %p)\n", This
, position
, object
, r
);
2797 if (position
>= This
->len
)
2800 range
= get_layout_range_by_pos(This
, position
);
2801 *object
= range
->object
;
2803 IDWriteInlineObject_AddRef(*object
);
2805 return return_range(&range
->h
, r
);
2808 static HRESULT WINAPI
dwritetextlayout_GetTypography(IDWriteTextLayout2
*iface
,
2809 UINT32 position
, IDWriteTypography
** typography
, DWRITE_TEXT_RANGE
*r
)
2811 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2812 struct layout_range_iface
*range
;
2814 TRACE("(%p)->(%u %p %p)\n", This
, position
, typography
, r
);
2816 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&This
->typographies
, position
);
2817 *typography
= (IDWriteTypography
*)range
->iface
;
2819 IDWriteTypography_AddRef(*typography
);
2821 return return_range(&range
->h
, r
);
2824 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout2
*iface
,
2825 UINT32 position
, UINT32
* length
, DWRITE_TEXT_RANGE
*r
)
2827 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2828 TRACE("(%p)->(%u %p %p)\n", This
, position
, length
, r
);
2829 return get_string_attribute_length(This
, LAYOUT_RANGE_ATTR_LOCALE
, position
, length
, r
);
2832 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout2
*iface
,
2833 UINT32 position
, WCHAR
* locale
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
2835 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2836 TRACE("(%p)->(%u %p %u %p)\n", This
, position
, locale
, length
, r
);
2837 return get_string_attribute_value(This
, LAYOUT_RANGE_ATTR_LOCALE
, position
, locale
, length
, r
);
2840 static inline FLOAT
renderer_apply_snapping(FLOAT coord
, BOOL skiptransform
, FLOAT ppdip
, FLOAT det
,
2841 const DWRITE_MATRIX
*m
)
2843 FLOAT vec
[2], vec2
[2];
2845 if (!skiptransform
) {
2846 /* apply transform */
2848 vec
[1] = coord
* ppdip
;
2850 vec2
[0] = m
->m11
* vec
[0] + m
->m21
* vec
[1] + m
->dx
;
2851 vec2
[1] = m
->m12
* vec
[0] + m
->m22
* vec
[1] + m
->dy
;
2854 vec2
[0] = floorf(vec2
[0] + 0.5f
);
2855 vec2
[1] = floorf(vec2
[1] + 0.5f
);
2857 /* apply inverted transform, we don't care about X component at this point */
2858 vec
[1] = (-m
->m12
* vec2
[0] + m
->m11
* vec2
[1] - (m
->m11
* m
->dy
- m
->m12
* m
->dx
)) / det
;
2862 vec
[1] = floorf(coord
* ppdip
+ 0.5f
) / ppdip
;
2867 static HRESULT WINAPI
dwritetextlayout_Draw(IDWriteTextLayout2
*iface
,
2868 void *context
, IDWriteTextRenderer
* renderer
, FLOAT origin_x
, FLOAT origin_y
)
2870 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2871 BOOL disabled
= FALSE
, skiptransform
= FALSE
;
2872 struct layout_effective_inline
*inlineobject
;
2873 struct layout_effective_run
*run
;
2874 struct layout_strikethrough
*s
;
2875 FLOAT det
= 0.0f
, ppdip
= 0.0f
;
2876 DWRITE_MATRIX m
= { 0 };
2879 TRACE("(%p)->(%p %p %.2f %.2f)\n", This
, context
, renderer
, origin_x
, origin_y
);
2881 hr
= layout_compute_effective_runs(This
);
2885 hr
= IDWriteTextRenderer_IsPixelSnappingDisabled(renderer
, context
, &disabled
);
2890 hr
= IDWriteTextRenderer_GetPixelsPerDip(renderer
, context
, &ppdip
);
2894 hr
= IDWriteTextRenderer_GetCurrentTransform(renderer
, context
, &m
);
2898 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
2899 if (ppdip
<= 0.0f
||
2900 (m
.m11
* m
.m22
!= 0.0f
&& (m
.m12
!= 0.0f
|| m
.m21
!= 0.0f
)) ||
2901 (m
.m12
* m
.m21
!= 0.0f
&& (m
.m11
!= 0.0f
|| m
.m22
!= 0.0f
)))
2904 skiptransform
= should_skip_transform(&m
, &det
);
2907 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
2908 /* 1. Regular runs */
2909 LIST_FOR_EACH_ENTRY(run
, &This
->eruns
, struct layout_effective_run
, entry
) {
2910 const struct regular_layout_run
*regular
= &run
->run
->u
.regular
;
2911 UINT32 start_glyph
= regular
->clustermap
[run
->start
];
2912 DWRITE_GLYPH_RUN_DESCRIPTION descr
;
2913 DWRITE_GLYPH_RUN glyph_run
;
2915 /* Everything but cluster map will be reused from nominal run, as we only need
2916 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
2917 it can't be reused because it has to start with 0 index for each reported run. */
2918 glyph_run
= regular
->run
;
2919 glyph_run
.glyphCount
= run
->glyphcount
;
2921 /* fixup glyph data arrays */
2922 glyph_run
.glyphIndices
+= start_glyph
;
2923 glyph_run
.glyphAdvances
+= start_glyph
;
2924 glyph_run
.glyphOffsets
+= start_glyph
;
2927 descr
= regular
->descr
;
2928 descr
.stringLength
= run
->length
;
2929 descr
.string
+= run
->start
;
2930 descr
.clusterMap
= run
->clustermap
;
2931 descr
.textPosition
+= run
->start
;
2933 /* return value is ignored */
2934 IDWriteTextRenderer_DrawGlyphRun(renderer
,
2936 run
->origin_x
+ run
->align_dx
+ origin_x
,
2937 SNAP_COORD(run
->origin_y
+ origin_y
),
2938 This
->measuringmode
,
2944 /* 2. Inline objects */
2945 LIST_FOR_EACH_ENTRY(inlineobject
, &This
->inlineobjects
, struct layout_effective_inline
, entry
) {
2946 IDWriteTextRenderer_DrawInlineObject(renderer
,
2948 inlineobject
->origin_x
+ inlineobject
->align_dx
+ origin_x
,
2949 SNAP_COORD(inlineobject
->origin_y
+ origin_y
),
2950 inlineobject
->object
,
2951 inlineobject
->is_sideways
,
2952 inlineobject
->is_rtl
,
2953 inlineobject
->effect
);
2956 /* TODO: 3. Underlines */
2958 /* 4. Strikethrough */
2959 LIST_FOR_EACH_ENTRY(s
, &This
->strikethrough
, struct layout_strikethrough
, entry
) {
2960 IDWriteTextRenderer_DrawStrikethrough(renderer
,
2963 SNAP_COORD(s
->run
->origin_y
),
2972 static HRESULT WINAPI
dwritetextlayout_GetLineMetrics(IDWriteTextLayout2
*iface
,
2973 DWRITE_LINE_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
2975 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2978 TRACE("(%p)->(%p %u %p)\n", This
, metrics
, max_count
, count
);
2980 hr
= layout_compute_effective_runs(This
);
2985 memcpy(metrics
, This
->lines
, sizeof(*metrics
)*min(max_count
, This
->metrics
.lineCount
));
2987 *count
= This
->metrics
.lineCount
;
2988 return max_count
>= This
->metrics
.lineCount
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
2991 static HRESULT WINAPI
dwritetextlayout_GetMetrics(IDWriteTextLayout2
*iface
, DWRITE_TEXT_METRICS
*metrics
)
2993 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2994 DWRITE_TEXT_METRICS1 metrics1
;
2997 TRACE("(%p)->(%p)\n", This
, metrics
);
2999 hr
= IDWriteTextLayout2_GetMetrics(iface
, &metrics1
);
3001 memcpy(metrics
, &metrics1
, sizeof(*metrics
));
3006 static HRESULT WINAPI
dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout2
*iface
, DWRITE_OVERHANG_METRICS
*overhangs
)
3008 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3009 FIXME("(%p)->(%p): stub\n", This
, overhangs
);
3013 static HRESULT WINAPI
dwritetextlayout_GetClusterMetrics(IDWriteTextLayout2
*iface
,
3014 DWRITE_CLUSTER_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
3016 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3019 TRACE("(%p)->(%p %u %p)\n", This
, metrics
, max_count
, count
);
3021 hr
= layout_compute(This
);
3026 memcpy(metrics
, This
->clustermetrics
, sizeof(DWRITE_CLUSTER_METRICS
)*min(max_count
, This
->cluster_count
));
3028 *count
= This
->cluster_count
;
3029 return max_count
>= This
->cluster_count
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
3032 /* Only to be used with DetermineMinWidth() to find the longest cluster sequence that we don't want to try
3033 too hard to break. */
3034 static inline BOOL
is_terminal_cluster(struct dwrite_textlayout
*layout
, UINT32 index
)
3036 if (layout
->clustermetrics
[index
].isWhitespace
|| layout
->clustermetrics
[index
].isNewline
||
3037 (index
== layout
->cluster_count
- 1))
3039 /* check next one */
3040 return (index
< layout
->cluster_count
- 1) && layout
->clustermetrics
[index
+1].isWhitespace
;
3043 static HRESULT WINAPI
dwritetextlayout_DetermineMinWidth(IDWriteTextLayout2
*iface
, FLOAT
* min_width
)
3045 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3050 TRACE("(%p)->(%p)\n", This
, min_width
);
3053 return E_INVALIDARG
;
3055 if (!(This
->recompute
& RECOMPUTE_MINIMAL_WIDTH
))
3059 hr
= layout_compute(This
);
3063 for (i
= 0; i
< This
->cluster_count
;) {
3064 if (is_terminal_cluster(This
, i
)) {
3065 width
= This
->clustermetrics
[i
].width
;
3070 while (!is_terminal_cluster(This
, i
)) {
3071 width
+= This
->clustermetrics
[i
].width
;
3074 /* count last one too */
3075 width
+= This
->clustermetrics
[i
].width
;
3078 if (width
> This
->minwidth
)
3079 This
->minwidth
= width
;
3081 This
->recompute
&= ~RECOMPUTE_MINIMAL_WIDTH
;
3084 *min_width
= This
->minwidth
;
3088 static HRESULT WINAPI
dwritetextlayout_HitTestPoint(IDWriteTextLayout2
*iface
,
3089 FLOAT pointX
, FLOAT pointY
, BOOL
* is_trailinghit
, BOOL
* is_inside
, DWRITE_HIT_TEST_METRICS
*metrics
)
3091 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3092 FIXME("(%p)->(%f %f %p %p %p): stub\n", This
, pointX
, pointY
, is_trailinghit
, is_inside
, metrics
);
3096 static HRESULT WINAPI
dwritetextlayout_HitTestTextPosition(IDWriteTextLayout2
*iface
,
3097 UINT32 textPosition
, BOOL is_trailinghit
, FLOAT
* pointX
, FLOAT
* pointY
, DWRITE_HIT_TEST_METRICS
*metrics
)
3099 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3100 FIXME("(%p)->(%u %d %p %p %p): stub\n", This
, textPosition
, is_trailinghit
, pointX
, pointY
, metrics
);
3104 static HRESULT WINAPI
dwritetextlayout_HitTestTextRange(IDWriteTextLayout2
*iface
,
3105 UINT32 textPosition
, UINT32 textLength
, FLOAT originX
, FLOAT originY
,
3106 DWRITE_HIT_TEST_METRICS
*metrics
, UINT32 max_metricscount
, UINT32
* actual_metricscount
)
3108 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3109 FIXME("(%p)->(%u %u %f %f %p %u %p): stub\n", This
, textPosition
, textLength
, originX
, originY
, metrics
,
3110 max_metricscount
, actual_metricscount
);
3114 static HRESULT WINAPI
dwritetextlayout1_SetPairKerning(IDWriteTextLayout2
*iface
, BOOL is_pairkerning_enabled
,
3115 DWRITE_TEXT_RANGE range
)
3117 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3118 struct layout_range_attr_value value
;
3120 TRACE("(%p)->(%d %s)\n", This
, is_pairkerning_enabled
, debugstr_range(&range
));
3122 value
.range
= range
;
3123 value
.u
.pair_kerning
= !!is_pairkerning_enabled
;
3124 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_PAIR_KERNING
, &value
);
3127 static HRESULT WINAPI
dwritetextlayout1_GetPairKerning(IDWriteTextLayout2
*iface
, UINT32 position
, BOOL
*is_pairkerning_enabled
,
3128 DWRITE_TEXT_RANGE
*r
)
3130 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3131 struct layout_range
*range
;
3133 TRACE("(%p)->(%u %p %p)\n", This
, position
, is_pairkerning_enabled
, r
);
3135 if (position
>= This
->len
)
3138 range
= get_layout_range_by_pos(This
, position
);
3139 *is_pairkerning_enabled
= range
->pair_kerning
;
3141 return return_range(&range
->h
, r
);
3144 static HRESULT WINAPI
dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout2
*iface
, FLOAT leading
, FLOAT trailing
,
3145 FLOAT min_advance
, DWRITE_TEXT_RANGE range
)
3147 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3148 struct layout_range_attr_value value
;
3150 TRACE("(%p)->(%.2f %.2f %.2f %s)\n", This
, leading
, trailing
, min_advance
, debugstr_range(&range
));
3152 if (min_advance
< 0.0f
)
3153 return E_INVALIDARG
;
3155 value
.range
= range
;
3156 value
.u
.spacing
[0] = leading
;
3157 value
.u
.spacing
[1] = trailing
;
3158 value
.u
.spacing
[2] = min_advance
;
3159 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_SPACING
, &value
);
3162 static HRESULT WINAPI
dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout2
*iface
, UINT32 position
, FLOAT
*leading
,
3163 FLOAT
*trailing
, FLOAT
*min_advance
, DWRITE_TEXT_RANGE
*r
)
3165 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3166 struct layout_range_spacing
*range
;
3168 TRACE("(%p)->(%u %p %p %p %p)\n", This
, position
, leading
, trailing
, min_advance
, r
);
3170 range
= (struct layout_range_spacing
*)get_layout_range_header_by_pos(&This
->spacing
, position
);
3171 *leading
= range
->leading
;
3172 *trailing
= range
->trailing
;
3173 *min_advance
= range
->min_advance
;
3175 return return_range(&range
->h
, r
);
3178 static HRESULT WINAPI
dwritetextlayout2_GetMetrics(IDWriteTextLayout2
*iface
, DWRITE_TEXT_METRICS1
*metrics
)
3180 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3183 TRACE("(%p)->(%p)\n", This
, metrics
);
3185 hr
= layout_compute_effective_runs(This
);
3189 *metrics
= This
->metrics
;
3193 static HRESULT WINAPI
dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout2
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
3195 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3197 TRACE("(%p)->(%d)\n", This
, orientation
);
3199 if ((UINT32
)orientation
> DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED
)
3200 return E_INVALIDARG
;
3202 This
->format
.vertical_orientation
= orientation
;
3206 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout2
*iface
)
3208 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3209 TRACE("(%p)\n", This
);
3210 return This
->format
.vertical_orientation
;
3213 static HRESULT WINAPI
dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout2
*iface
, BOOL lastline_wrapping_enabled
)
3215 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3216 TRACE("(%p)->(%d)\n", This
, lastline_wrapping_enabled
);
3217 return IDWriteTextFormat1_SetLastLineWrapping(&This
->IDWriteTextFormat1_iface
, lastline_wrapping_enabled
);
3220 static BOOL WINAPI
dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout2
*iface
)
3222 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3223 TRACE("(%p)\n", This
);
3224 return IDWriteTextFormat1_GetLastLineWrapping(&This
->IDWriteTextFormat1_iface
);
3227 static HRESULT WINAPI
dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout2
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
3229 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3230 TRACE("(%p)->(%d)\n", This
, alignment
);
3231 return IDWriteTextFormat1_SetOpticalAlignment(&This
->IDWriteTextFormat1_iface
, alignment
);
3234 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout2
*iface
)
3236 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3237 TRACE("(%p)\n", This
);
3238 return IDWriteTextFormat1_GetOpticalAlignment(&This
->IDWriteTextFormat1_iface
);
3241 static HRESULT WINAPI
dwritetextlayout2_SetFontFallback(IDWriteTextLayout2
*iface
, IDWriteFontFallback
*fallback
)
3243 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3244 TRACE("(%p)->(%p)\n", This
, fallback
);
3245 return set_fontfallback_for_format(&This
->format
, fallback
);
3248 static HRESULT WINAPI
dwritetextlayout2_GetFontFallback(IDWriteTextLayout2
*iface
, IDWriteFontFallback
**fallback
)
3250 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3251 TRACE("(%p)->(%p)\n", This
, fallback
);
3252 return get_fontfallback_from_format(&This
->format
, fallback
);
3255 static const IDWriteTextLayout2Vtbl dwritetextlayoutvtbl
= {
3256 dwritetextlayout_QueryInterface
,
3257 dwritetextlayout_AddRef
,
3258 dwritetextlayout_Release
,
3259 dwritetextlayout_SetTextAlignment
,
3260 dwritetextlayout_SetParagraphAlignment
,
3261 dwritetextlayout_SetWordWrapping
,
3262 dwritetextlayout_SetReadingDirection
,
3263 dwritetextlayout_SetFlowDirection
,
3264 dwritetextlayout_SetIncrementalTabStop
,
3265 dwritetextlayout_SetTrimming
,
3266 dwritetextlayout_SetLineSpacing
,
3267 dwritetextlayout_GetTextAlignment
,
3268 dwritetextlayout_GetParagraphAlignment
,
3269 dwritetextlayout_GetWordWrapping
,
3270 dwritetextlayout_GetReadingDirection
,
3271 dwritetextlayout_GetFlowDirection
,
3272 dwritetextlayout_GetIncrementalTabStop
,
3273 dwritetextlayout_GetTrimming
,
3274 dwritetextlayout_GetLineSpacing
,
3275 dwritetextlayout_GetFontCollection
,
3276 dwritetextlayout_GetFontFamilyNameLength
,
3277 dwritetextlayout_GetFontFamilyName
,
3278 dwritetextlayout_GetFontWeight
,
3279 dwritetextlayout_GetFontStyle
,
3280 dwritetextlayout_GetFontStretch
,
3281 dwritetextlayout_GetFontSize
,
3282 dwritetextlayout_GetLocaleNameLength
,
3283 dwritetextlayout_GetLocaleName
,
3284 dwritetextlayout_SetMaxWidth
,
3285 dwritetextlayout_SetMaxHeight
,
3286 dwritetextlayout_SetFontCollection
,
3287 dwritetextlayout_SetFontFamilyName
,
3288 dwritetextlayout_SetFontWeight
,
3289 dwritetextlayout_SetFontStyle
,
3290 dwritetextlayout_SetFontStretch
,
3291 dwritetextlayout_SetFontSize
,
3292 dwritetextlayout_SetUnderline
,
3293 dwritetextlayout_SetStrikethrough
,
3294 dwritetextlayout_SetDrawingEffect
,
3295 dwritetextlayout_SetInlineObject
,
3296 dwritetextlayout_SetTypography
,
3297 dwritetextlayout_SetLocaleName
,
3298 dwritetextlayout_GetMaxWidth
,
3299 dwritetextlayout_GetMaxHeight
,
3300 dwritetextlayout_layout_GetFontCollection
,
3301 dwritetextlayout_layout_GetFontFamilyNameLength
,
3302 dwritetextlayout_layout_GetFontFamilyName
,
3303 dwritetextlayout_layout_GetFontWeight
,
3304 dwritetextlayout_layout_GetFontStyle
,
3305 dwritetextlayout_layout_GetFontStretch
,
3306 dwritetextlayout_layout_GetFontSize
,
3307 dwritetextlayout_GetUnderline
,
3308 dwritetextlayout_GetStrikethrough
,
3309 dwritetextlayout_GetDrawingEffect
,
3310 dwritetextlayout_GetInlineObject
,
3311 dwritetextlayout_GetTypography
,
3312 dwritetextlayout_layout_GetLocaleNameLength
,
3313 dwritetextlayout_layout_GetLocaleName
,
3314 dwritetextlayout_Draw
,
3315 dwritetextlayout_GetLineMetrics
,
3316 dwritetextlayout_GetMetrics
,
3317 dwritetextlayout_GetOverhangMetrics
,
3318 dwritetextlayout_GetClusterMetrics
,
3319 dwritetextlayout_DetermineMinWidth
,
3320 dwritetextlayout_HitTestPoint
,
3321 dwritetextlayout_HitTestTextPosition
,
3322 dwritetextlayout_HitTestTextRange
,
3323 dwritetextlayout1_SetPairKerning
,
3324 dwritetextlayout1_GetPairKerning
,
3325 dwritetextlayout1_SetCharacterSpacing
,
3326 dwritetextlayout1_GetCharacterSpacing
,
3327 dwritetextlayout2_GetMetrics
,
3328 dwritetextlayout2_SetVerticalGlyphOrientation
,
3329 dwritetextlayout2_GetVerticalGlyphOrientation
,
3330 dwritetextlayout2_SetLastLineWrapping
,
3331 dwritetextlayout2_GetLastLineWrapping
,
3332 dwritetextlayout2_SetOpticalAlignment
,
3333 dwritetextlayout2_GetOpticalAlignment
,
3334 dwritetextlayout2_SetFontFallback
,
3335 dwritetextlayout2_GetFontFallback
3338 static HRESULT WINAPI
dwritetextformat1_layout_QueryInterface(IDWriteTextFormat1
*iface
, REFIID riid
, void **obj
)
3340 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3341 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
3342 return IDWriteTextLayout2_QueryInterface(&This
->IDWriteTextLayout2_iface
, riid
, obj
);
3345 static ULONG WINAPI
dwritetextformat1_layout_AddRef(IDWriteTextFormat1
*iface
)
3347 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3348 return IDWriteTextLayout2_AddRef(&This
->IDWriteTextLayout2_iface
);
3351 static ULONG WINAPI
dwritetextformat1_layout_Release(IDWriteTextFormat1
*iface
)
3353 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3354 return IDWriteTextLayout2_Release(&This
->IDWriteTextLayout2_iface
);
3357 static HRESULT WINAPI
dwritetextformat1_layout_SetTextAlignment(IDWriteTextFormat1
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
3359 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3363 TRACE("(%p)->(%d)\n", This
, alignment
);
3365 hr
= format_set_textalignment(&This
->format
, alignment
, &changed
);
3369 /* if layout is not ready there's nothing to align */
3370 if (changed
&& !(This
->recompute
& RECOMPUTE_EFFECTIVE_RUNS
))
3371 layout_apply_text_alignment(This
);
3376 static HRESULT WINAPI
dwritetextformat1_layout_SetParagraphAlignment(IDWriteTextFormat1
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
3378 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3382 TRACE("(%p)->(%d)\n", This
, alignment
);
3384 hr
= format_set_paralignment(&This
->format
, alignment
, &changed
);
3388 /* if layout is not ready there's nothing to align */
3389 if (changed
&& !(This
->recompute
& RECOMPUTE_EFFECTIVE_RUNS
))
3390 layout_apply_par_alignment(This
);
3395 static HRESULT WINAPI
dwritetextformat1_layout_SetWordWrapping(IDWriteTextFormat1
*iface
, DWRITE_WORD_WRAPPING wrapping
)
3397 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3401 TRACE("(%p)->(%d)\n", This
, wrapping
);
3403 hr
= format_set_wordwrapping(&This
->format
, wrapping
, &changed
);
3408 This
->recompute
|= RECOMPUTE_EFFECTIVE_RUNS
;
3413 static HRESULT WINAPI
dwritetextformat1_layout_SetReadingDirection(IDWriteTextFormat1
*iface
, DWRITE_READING_DIRECTION direction
)
3415 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3419 TRACE("(%p)->(%d)\n", This
, direction
);
3421 hr
= format_set_readingdirection(&This
->format
, direction
, &changed
);
3426 This
->recompute
= RECOMPUTE_EVERYTHING
;
3431 static HRESULT WINAPI
dwritetextformat1_layout_SetFlowDirection(IDWriteTextFormat1
*iface
, DWRITE_FLOW_DIRECTION direction
)
3433 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3434 FIXME("(%p)->(%d): stub\n", This
, direction
);
3438 static HRESULT WINAPI
dwritetextformat1_layout_SetIncrementalTabStop(IDWriteTextFormat1
*iface
, FLOAT tabstop
)
3440 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3441 FIXME("(%p)->(%f): stub\n", This
, tabstop
);
3445 static HRESULT WINAPI
dwritetextformat1_layout_SetTrimming(IDWriteTextFormat1
*iface
, DWRITE_TRIMMING
const *trimming
,
3446 IDWriteInlineObject
*trimming_sign
)
3448 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3449 FIXME("(%p)->(%p %p): stub\n", This
, trimming
, trimming_sign
);
3453 static HRESULT WINAPI
dwritetextformat1_layout_SetLineSpacing(IDWriteTextFormat1
*iface
, DWRITE_LINE_SPACING_METHOD spacing
,
3454 FLOAT line_spacing
, FLOAT baseline
)
3456 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3457 FIXME("(%p)->(%d %f %f): stub\n", This
, spacing
, line_spacing
, baseline
);
3461 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextformat1_layout_GetTextAlignment(IDWriteTextFormat1
*iface
)
3463 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3464 TRACE("(%p)\n", This
);
3465 return This
->format
.textalignment
;
3468 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextformat1_layout_GetParagraphAlignment(IDWriteTextFormat1
*iface
)
3470 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3471 TRACE("(%p)\n", This
);
3472 return This
->format
.paralign
;
3475 static DWRITE_WORD_WRAPPING WINAPI
dwritetextformat1_layout_GetWordWrapping(IDWriteTextFormat1
*iface
)
3477 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3478 TRACE("(%p)\n", This
);
3479 return This
->format
.wrapping
;
3482 static DWRITE_READING_DIRECTION WINAPI
dwritetextformat1_layout_GetReadingDirection(IDWriteTextFormat1
*iface
)
3484 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3485 TRACE("(%p)\n", This
);
3486 return This
->format
.readingdir
;
3489 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextformat1_layout_GetFlowDirection(IDWriteTextFormat1
*iface
)
3491 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3492 TRACE("(%p)\n", This
);
3493 return This
->format
.flow
;
3496 static FLOAT WINAPI
dwritetextformat1_layout_GetIncrementalTabStop(IDWriteTextFormat1
*iface
)
3498 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3499 FIXME("(%p): stub\n", This
);
3503 static HRESULT WINAPI
dwritetextformat1_layout_GetTrimming(IDWriteTextFormat1
*iface
, DWRITE_TRIMMING
*options
,
3504 IDWriteInlineObject
**trimming_sign
)
3506 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3508 TRACE("(%p)->(%p %p)\n", This
, options
, trimming_sign
);
3510 *options
= This
->format
.trimming
;
3511 *trimming_sign
= This
->format
.trimmingsign
;
3513 IDWriteInlineObject_AddRef(*trimming_sign
);
3517 static HRESULT WINAPI
dwritetextformat1_layout_GetLineSpacing(IDWriteTextFormat1
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
3518 FLOAT
*spacing
, FLOAT
*baseline
)
3520 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3522 TRACE("(%p)->(%p %p %p)\n", This
, method
, spacing
, baseline
);
3524 *method
= This
->format
.spacingmethod
;
3525 *spacing
= This
->format
.spacing
;
3526 *baseline
= This
->format
.baseline
;
3530 static HRESULT WINAPI
dwritetextformat1_layout_GetFontCollection(IDWriteTextFormat1
*iface
, IDWriteFontCollection
**collection
)
3532 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3534 TRACE("(%p)->(%p)\n", This
, collection
);
3536 *collection
= This
->format
.collection
;
3538 IDWriteFontCollection_AddRef(*collection
);
3542 static UINT32 WINAPI
dwritetextformat1_layout_GetFontFamilyNameLength(IDWriteTextFormat1
*iface
)
3544 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3545 TRACE("(%p)\n", This
);
3546 return This
->format
.family_len
;
3549 static HRESULT WINAPI
dwritetextformat1_layout_GetFontFamilyName(IDWriteTextFormat1
*iface
, WCHAR
*name
, UINT32 size
)
3551 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3553 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
3555 if (size
<= This
->format
.family_len
) return E_NOT_SUFFICIENT_BUFFER
;
3556 strcpyW(name
, This
->format
.family_name
);
3560 static DWRITE_FONT_WEIGHT WINAPI
dwritetextformat1_layout_GetFontWeight(IDWriteTextFormat1
*iface
)
3562 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3563 TRACE("(%p)\n", This
);
3564 return This
->format
.weight
;
3567 static DWRITE_FONT_STYLE WINAPI
dwritetextformat1_layout_GetFontStyle(IDWriteTextFormat1
*iface
)
3569 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3570 TRACE("(%p)\n", This
);
3571 return This
->format
.style
;
3574 static DWRITE_FONT_STRETCH WINAPI
dwritetextformat1_layout_GetFontStretch(IDWriteTextFormat1
*iface
)
3576 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3577 TRACE("(%p)\n", This
);
3578 return This
->format
.stretch
;
3581 static FLOAT WINAPI
dwritetextformat1_layout_GetFontSize(IDWriteTextFormat1
*iface
)
3583 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3584 TRACE("(%p)\n", This
);
3585 return This
->format
.fontsize
;
3588 static UINT32 WINAPI
dwritetextformat1_layout_GetLocaleNameLength(IDWriteTextFormat1
*iface
)
3590 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3591 TRACE("(%p)\n", This
);
3592 return This
->format
.locale_len
;
3595 static HRESULT WINAPI
dwritetextformat1_layout_GetLocaleName(IDWriteTextFormat1
*iface
, WCHAR
*name
, UINT32 size
)
3597 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3599 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
3601 if (size
<= This
->format
.locale_len
) return E_NOT_SUFFICIENT_BUFFER
;
3602 strcpyW(name
, This
->format
.locale
);
3606 static HRESULT WINAPI
dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat1
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
3608 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3609 FIXME("(%p)->(%d): stub\n", This
, orientation
);
3613 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat1
*iface
)
3615 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3616 FIXME("(%p): stub\n", This
);
3617 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
3620 static HRESULT WINAPI
dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat1
*iface
, BOOL lastline_wrapping_enabled
)
3622 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3624 TRACE("(%p)->(%d)\n", This
, lastline_wrapping_enabled
);
3626 This
->format
.last_line_wrapping
= !!lastline_wrapping_enabled
;
3630 static BOOL WINAPI
dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat1
*iface
)
3632 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3633 TRACE("(%p)\n", This
);
3634 return This
->format
.last_line_wrapping
;
3637 static HRESULT WINAPI
dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat1
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
3639 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3640 TRACE("(%p)->(%d)\n", This
, alignment
);
3641 return format_set_optical_alignment(&This
->format
, alignment
);
3644 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat1
*iface
)
3646 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3647 TRACE("(%p)\n", This
);
3648 return This
->format
.optical_alignment
;
3651 static HRESULT WINAPI
dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat1
*iface
, IDWriteFontFallback
*fallback
)
3653 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3654 TRACE("(%p)->(%p)\n", This
, fallback
);
3655 return IDWriteTextLayout2_SetFontFallback(&This
->IDWriteTextLayout2_iface
, fallback
);
3658 static HRESULT WINAPI
dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat1
*iface
, IDWriteFontFallback
**fallback
)
3660 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3661 TRACE("(%p)->(%p)\n", This
, fallback
);
3662 return IDWriteTextLayout2_GetFontFallback(&This
->IDWriteTextLayout2_iface
, fallback
);
3665 static const IDWriteTextFormat1Vtbl dwritetextformat1_layout_vtbl
= {
3666 dwritetextformat1_layout_QueryInterface
,
3667 dwritetextformat1_layout_AddRef
,
3668 dwritetextformat1_layout_Release
,
3669 dwritetextformat1_layout_SetTextAlignment
,
3670 dwritetextformat1_layout_SetParagraphAlignment
,
3671 dwritetextformat1_layout_SetWordWrapping
,
3672 dwritetextformat1_layout_SetReadingDirection
,
3673 dwritetextformat1_layout_SetFlowDirection
,
3674 dwritetextformat1_layout_SetIncrementalTabStop
,
3675 dwritetextformat1_layout_SetTrimming
,
3676 dwritetextformat1_layout_SetLineSpacing
,
3677 dwritetextformat1_layout_GetTextAlignment
,
3678 dwritetextformat1_layout_GetParagraphAlignment
,
3679 dwritetextformat1_layout_GetWordWrapping
,
3680 dwritetextformat1_layout_GetReadingDirection
,
3681 dwritetextformat1_layout_GetFlowDirection
,
3682 dwritetextformat1_layout_GetIncrementalTabStop
,
3683 dwritetextformat1_layout_GetTrimming
,
3684 dwritetextformat1_layout_GetLineSpacing
,
3685 dwritetextformat1_layout_GetFontCollection
,
3686 dwritetextformat1_layout_GetFontFamilyNameLength
,
3687 dwritetextformat1_layout_GetFontFamilyName
,
3688 dwritetextformat1_layout_GetFontWeight
,
3689 dwritetextformat1_layout_GetFontStyle
,
3690 dwritetextformat1_layout_GetFontStretch
,
3691 dwritetextformat1_layout_GetFontSize
,
3692 dwritetextformat1_layout_GetLocaleNameLength
,
3693 dwritetextformat1_layout_GetLocaleName
,
3694 dwritetextformat1_layout_SetVerticalGlyphOrientation
,
3695 dwritetextformat1_layout_GetVerticalGlyphOrientation
,
3696 dwritetextformat1_layout_SetLastLineWrapping
,
3697 dwritetextformat1_layout_GetLastLineWrapping
,
3698 dwritetextformat1_layout_SetOpticalAlignment
,
3699 dwritetextformat1_layout_GetOpticalAlignment
,
3700 dwritetextformat1_layout_SetFontFallback
,
3701 dwritetextformat1_layout_GetFontFallback
3704 static HRESULT WINAPI
dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink
*iface
,
3705 REFIID riid
, void **obj
)
3707 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSink
) || IsEqualIID(riid
, &IID_IUnknown
)) {
3709 IDWriteTextAnalysisSink_AddRef(iface
);
3714 return E_NOINTERFACE
;
3717 static ULONG WINAPI
dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink
*iface
)
3722 static ULONG WINAPI
dwritetextlayout_sink_Release(IDWriteTextAnalysisSink
*iface
)
3727 static HRESULT WINAPI
dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink
*iface
,
3728 UINT32 position
, UINT32 length
, DWRITE_SCRIPT_ANALYSIS
const* sa
)
3730 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink(iface
);
3731 struct layout_run
*run
;
3733 TRACE("%u %u script=%d\n", position
, length
, sa
->script
);
3735 run
= alloc_layout_run(LAYOUT_RUN_REGULAR
);
3737 return E_OUTOFMEMORY
;
3739 run
->u
.regular
.descr
.string
= &layout
->str
[position
];
3740 run
->u
.regular
.descr
.stringLength
= length
;
3741 run
->u
.regular
.descr
.textPosition
= position
;
3742 run
->u
.regular
.sa
= *sa
;
3743 list_add_tail(&layout
->runs
, &run
->entry
);
3747 static HRESULT WINAPI
dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink
*iface
,
3748 UINT32 position
, UINT32 length
, DWRITE_LINE_BREAKPOINT
const* breakpoints
)
3750 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink(iface
);
3752 if (position
+ length
> layout
->len
)
3755 memcpy(&layout
->nominal_breakpoints
[position
], breakpoints
, length
*sizeof(DWRITE_LINE_BREAKPOINT
));
3759 static HRESULT WINAPI
dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink
*iface
, UINT32 position
,
3760 UINT32 length
, UINT8 explicitLevel
, UINT8 resolvedLevel
)
3762 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink(iface
);
3763 struct layout_run
*cur_run
;
3765 TRACE("%u %u %u %u\n", position
, length
, explicitLevel
, resolvedLevel
);
3767 LIST_FOR_EACH_ENTRY(cur_run
, &layout
->runs
, struct layout_run
, entry
) {
3768 struct regular_layout_run
*cur
= &cur_run
->u
.regular
;
3769 struct layout_run
*run
;
3771 if (cur_run
->kind
== LAYOUT_RUN_INLINE
)
3774 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
3775 if (position
< cur
->descr
.textPosition
|| position
>= cur
->descr
.textPosition
+ cur
->descr
.stringLength
)
3778 /* full hit - just set run level */
3779 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
== length
) {
3780 cur
->run
.bidiLevel
= resolvedLevel
;
3784 /* current run is fully covered, move to next one */
3785 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
< length
) {
3786 cur
->run
.bidiLevel
= resolvedLevel
;
3787 position
+= cur
->descr
.stringLength
;
3788 length
-= cur
->descr
.stringLength
;
3792 /* all fully covered runs are processed at this point, reuse existing run for remaining
3793 reported bidi range and add another run for the rest of original one */
3795 run
= alloc_layout_run(LAYOUT_RUN_REGULAR
);
3797 return E_OUTOFMEMORY
;
3800 run
->u
.regular
.descr
.textPosition
= position
+ length
;
3801 run
->u
.regular
.descr
.stringLength
= cur
->descr
.stringLength
- length
;
3802 run
->u
.regular
.descr
.string
= &layout
->str
[position
+ length
];
3804 /* reduce existing run */
3805 cur
->run
.bidiLevel
= resolvedLevel
;
3806 cur
->descr
.stringLength
= length
;
3808 list_add_after(&cur_run
->entry
, &run
->entry
);
3815 static HRESULT WINAPI
dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink
*iface
,
3816 UINT32 position
, UINT32 length
, IDWriteNumberSubstitution
* substitution
)
3821 static const IDWriteTextAnalysisSinkVtbl dwritetextlayoutsinkvtbl
= {
3822 dwritetextlayout_sink_QueryInterface
,
3823 dwritetextlayout_sink_AddRef
,
3824 dwritetextlayout_sink_Release
,
3825 dwritetextlayout_sink_SetScriptAnalysis
,
3826 dwritetextlayout_sink_SetLineBreakpoints
,
3827 dwritetextlayout_sink_SetBidiLevel
,
3828 dwritetextlayout_sink_SetNumberSubstitution
3831 static HRESULT WINAPI
dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource
*iface
,
3832 REFIID riid
, void **obj
)
3834 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSource
) ||
3835 IsEqualIID(riid
, &IID_IUnknown
))
3838 IDWriteTextAnalysisSource_AddRef(iface
);
3843 return E_NOINTERFACE
;
3846 static ULONG WINAPI
dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource
*iface
)
3851 static ULONG WINAPI
dwritetextlayout_source_Release(IDWriteTextAnalysisSource
*iface
)
3856 static HRESULT WINAPI
dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource
*iface
,
3857 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
3859 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource(iface
);
3861 TRACE("(%p)->(%u %p %p)\n", layout
, position
, text
, text_len
);
3863 if (position
< layout
->len
) {
3864 *text
= &layout
->str
[position
];
3865 *text_len
= layout
->len
- position
;
3875 static HRESULT WINAPI
dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource
*iface
,
3876 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
3878 FIXME("%u %p %p: stub\n", position
, text
, text_len
);
3882 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource
*iface
)
3884 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource(iface
);
3885 return IDWriteTextLayout2_GetReadingDirection(&layout
->IDWriteTextLayout2_iface
);
3888 static HRESULT WINAPI
dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource
*iface
,
3889 UINT32 position
, UINT32
* text_len
, WCHAR
const** locale
)
3891 FIXME("%u %p %p: stub\n", position
, text_len
, locale
);
3895 static HRESULT WINAPI
dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource
*iface
,
3896 UINT32 position
, UINT32
* text_len
, IDWriteNumberSubstitution
**substitution
)
3898 FIXME("%u %p %p: stub\n", position
, text_len
, substitution
);
3902 static const IDWriteTextAnalysisSourceVtbl dwritetextlayoutsourcevtbl
= {
3903 dwritetextlayout_source_QueryInterface
,
3904 dwritetextlayout_source_AddRef
,
3905 dwritetextlayout_source_Release
,
3906 dwritetextlayout_source_GetTextAtPosition
,
3907 dwritetextlayout_source_GetTextBeforePosition
,
3908 dwritetextlayout_source_GetParagraphReadingDirection
,
3909 dwritetextlayout_source_GetLocaleName
,
3910 dwritetextlayout_source_GetNumberSubstitution
3913 static HRESULT
layout_format_from_textformat(struct dwrite_textlayout
*layout
, IDWriteTextFormat
*format
)
3915 struct dwrite_textformat
*textformat
;
3916 IDWriteTextFormat1
*format1
;
3920 if ((textformat
= unsafe_impl_from_IDWriteTextFormat(format
))) {
3921 layout
->format
= textformat
->format
;
3923 layout
->format
.locale
= heap_strdupW(textformat
->format
.locale
);
3924 layout
->format
.family_name
= heap_strdupW(textformat
->format
.family_name
);
3925 if (!layout
->format
.locale
|| !layout
->format
.family_name
)
3927 heap_free(layout
->format
.locale
);
3928 heap_free(layout
->format
.family_name
);
3929 return E_OUTOFMEMORY
;
3932 if (layout
->format
.trimmingsign
)
3933 IDWriteInlineObject_AddRef(layout
->format
.trimmingsign
);
3934 if (layout
->format
.collection
)
3935 IDWriteFontCollection_AddRef(layout
->format
.collection
);
3936 if (layout
->format
.fallback
)
3937 IDWriteFontFallback_AddRef(layout
->format
.fallback
);
3942 layout
->format
.weight
= IDWriteTextFormat_GetFontWeight(format
);
3943 layout
->format
.style
= IDWriteTextFormat_GetFontStyle(format
);
3944 layout
->format
.stretch
= IDWriteTextFormat_GetFontStretch(format
);
3945 layout
->format
.fontsize
= IDWriteTextFormat_GetFontSize(format
);
3946 layout
->format
.textalignment
= IDWriteTextFormat_GetTextAlignment(format
);
3947 layout
->format
.paralign
= IDWriteTextFormat_GetParagraphAlignment(format
);
3948 layout
->format
.wrapping
= IDWriteTextFormat_GetWordWrapping(format
);
3949 layout
->format
.readingdir
= IDWriteTextFormat_GetReadingDirection(format
);
3950 layout
->format
.flow
= IDWriteTextFormat_GetFlowDirection(format
);
3951 layout
->format
.fallback
= NULL
;
3952 hr
= IDWriteTextFormat_GetLineSpacing(format
, &layout
->format
.spacingmethod
,
3953 &layout
->format
.spacing
, &layout
->format
.baseline
);
3957 hr
= IDWriteTextFormat_GetTrimming(format
, &layout
->format
.trimming
, &layout
->format
.trimmingsign
);
3961 /* locale name and length */
3962 len
= IDWriteTextFormat_GetLocaleNameLength(format
);
3963 layout
->format
.locale
= heap_alloc((len
+1)*sizeof(WCHAR
));
3964 if (!layout
->format
.locale
)
3965 return E_OUTOFMEMORY
;
3967 hr
= IDWriteTextFormat_GetLocaleName(format
, layout
->format
.locale
, len
+1);
3970 layout
->format
.locale_len
= len
;
3972 /* font family name and length */
3973 len
= IDWriteTextFormat_GetFontFamilyNameLength(format
);
3974 layout
->format
.family_name
= heap_alloc((len
+1)*sizeof(WCHAR
));
3975 if (!layout
->format
.family_name
)
3976 return E_OUTOFMEMORY
;
3978 hr
= IDWriteTextFormat_GetFontFamilyName(format
, layout
->format
.family_name
, len
+1);
3981 layout
->format
.family_len
= len
;
3983 hr
= IDWriteTextFormat_QueryInterface(format
, &IID_IDWriteTextFormat1
, (void**)&format1
);
3985 layout
->format
.vertical_orientation
= IDWriteTextFormat1_GetVerticalGlyphOrientation(format1
);
3986 layout
->format
.optical_alignment
= IDWriteTextFormat1_GetOpticalAlignment(format1
);
3987 IDWriteTextFormat1_GetFontFallback(format1
, &layout
->format
.fallback
);
3988 IDWriteTextFormat1_Release(format1
);
3991 layout
->format
.vertical_orientation
= DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
3992 layout
->format
.optical_alignment
= DWRITE_OPTICAL_ALIGNMENT_NONE
;
3995 return IDWriteTextFormat_GetFontCollection(format
, &layout
->format
.collection
);
3998 static HRESULT
init_textlayout(const WCHAR
*str
, UINT32 len
, IDWriteTextFormat
*format
, FLOAT maxwidth
, FLOAT maxheight
, struct dwrite_textlayout
*layout
)
4000 struct layout_range_header
*range
, *strike
, *effect
, *spacing
, *typography
;
4001 static const DWRITE_TEXT_RANGE r
= { 0, ~0u };
4004 layout
->IDWriteTextLayout2_iface
.lpVtbl
= &dwritetextlayoutvtbl
;
4005 layout
->IDWriteTextFormat1_iface
.lpVtbl
= &dwritetextformat1_layout_vtbl
;
4006 layout
->IDWriteTextAnalysisSink_iface
.lpVtbl
= &dwritetextlayoutsinkvtbl
;
4007 layout
->IDWriteTextAnalysisSource_iface
.lpVtbl
= &dwritetextlayoutsourcevtbl
;
4010 layout
->recompute
= RECOMPUTE_EVERYTHING
;
4011 layout
->nominal_breakpoints
= NULL
;
4012 layout
->actual_breakpoints
= NULL
;
4013 layout
->cluster_count
= 0;
4014 layout
->clustermetrics
= NULL
;
4015 layout
->clusters
= NULL
;
4016 layout
->lines
= NULL
;
4017 layout
->line_alloc
= 0;
4018 layout
->minwidth
= 0.0f
;
4019 list_init(&layout
->eruns
);
4020 list_init(&layout
->inlineobjects
);
4021 list_init(&layout
->strikethrough
);
4022 list_init(&layout
->runs
);
4023 list_init(&layout
->ranges
);
4024 list_init(&layout
->strike_ranges
);
4025 list_init(&layout
->effects
);
4026 list_init(&layout
->spacing
);
4027 list_init(&layout
->typographies
);
4028 memset(&layout
->format
, 0, sizeof(layout
->format
));
4029 memset(&layout
->metrics
, 0, sizeof(layout
->metrics
));
4030 layout
->metrics
.layoutWidth
= maxwidth
;
4031 layout
->metrics
.layoutHeight
= maxheight
;
4032 layout
->measuringmode
= DWRITE_MEASURING_MODE_NATURAL
;
4034 layout
->ppdip
= 0.0f
;
4035 memset(&layout
->transform
, 0, sizeof(layout
->transform
));
4037 layout
->str
= heap_strdupnW(str
, len
);
4038 if (len
&& !layout
->str
) {
4043 hr
= layout_format_from_textformat(layout
, format
);
4047 range
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_REGULAR
);
4048 strike
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_STRIKETHROUGH
);
4049 effect
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_EFFECT
);
4050 spacing
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_SPACING
);
4051 typography
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_TYPOGRAPHY
);
4052 if (!range
|| !strike
|| !effect
|| !spacing
|| !typography
) {
4053 free_layout_range(range
);
4054 free_layout_range(strike
);
4055 free_layout_range(effect
);
4056 free_layout_range(spacing
);
4057 free_layout_range(typography
);
4062 list_add_head(&layout
->ranges
, &range
->entry
);
4063 list_add_head(&layout
->strike_ranges
, &strike
->entry
);
4064 list_add_head(&layout
->effects
, &effect
->entry
);
4065 list_add_head(&layout
->spacing
, &spacing
->entry
);
4066 list_add_head(&layout
->typographies
, &typography
->entry
);
4070 IDWriteTextLayout2_Release(&layout
->IDWriteTextLayout2_iface
);
4074 HRESULT
create_textlayout(const WCHAR
*str
, UINT32 len
, IDWriteTextFormat
*format
, FLOAT maxwidth
, FLOAT maxheight
, IDWriteTextLayout
**ret
)
4076 struct dwrite_textlayout
*layout
;
4081 layout
= heap_alloc(sizeof(struct dwrite_textlayout
));
4082 if (!layout
) return E_OUTOFMEMORY
;
4084 hr
= init_textlayout(str
, len
, format
, maxwidth
, maxheight
, layout
);
4086 *ret
= (IDWriteTextLayout
*)&layout
->IDWriteTextLayout2_iface
;
4091 HRESULT
create_gdicompat_textlayout(const WCHAR
*str
, UINT32 len
, IDWriteTextFormat
*format
, FLOAT maxwidth
, FLOAT maxheight
,
4092 FLOAT ppdip
, const DWRITE_MATRIX
*transform
, BOOL use_gdi_natural
, IDWriteTextLayout
**ret
)
4094 struct dwrite_textlayout
*layout
;
4099 layout
= heap_alloc(sizeof(struct dwrite_textlayout
));
4100 if (!layout
) return E_OUTOFMEMORY
;
4102 hr
= init_textlayout(str
, len
, format
, maxwidth
, maxheight
, layout
);
4104 layout
->measuringmode
= use_gdi_natural
? DWRITE_MEASURING_MODE_GDI_NATURAL
: DWRITE_MEASURING_MODE_GDI_CLASSIC
;
4106 /* set gdi-specific properties */
4107 layout
->ppdip
= ppdip
;
4108 layout
->transform
= transform
? *transform
: identity
;
4110 *ret
= (IDWriteTextLayout
*)&layout
->IDWriteTextLayout2_iface
;
4116 static HRESULT WINAPI
dwritetrimmingsign_QueryInterface(IDWriteInlineObject
*iface
, REFIID riid
, void **obj
)
4118 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
4120 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
4122 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDWriteInlineObject
)) {
4124 IDWriteInlineObject_AddRef(iface
);
4129 return E_NOINTERFACE
;
4132 static ULONG WINAPI
dwritetrimmingsign_AddRef(IDWriteInlineObject
*iface
)
4134 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
4135 ULONG ref
= InterlockedIncrement(&This
->ref
);
4136 TRACE("(%p)->(%d)\n", This
, ref
);
4140 static ULONG WINAPI
dwritetrimmingsign_Release(IDWriteInlineObject
*iface
)
4142 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
4143 ULONG ref
= InterlockedDecrement(&This
->ref
);
4145 TRACE("(%p)->(%d)\n", This
, ref
);
4148 IDWriteTextLayout_Release(This
->layout
);
4155 static HRESULT WINAPI
dwritetrimmingsign_Draw(IDWriteInlineObject
*iface
, void *context
, IDWriteTextRenderer
*renderer
,
4156 FLOAT originX
, FLOAT originY
, BOOL is_sideways
, BOOL is_rtl
, IUnknown
*effect
)
4158 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
4159 DWRITE_TEXT_RANGE range
= { 0, ~0u };
4161 TRACE("(%p)->(%p %p %.2f %.2f %d %d %p)\n", This
, context
, renderer
, originX
, originY
, is_sideways
, is_rtl
, effect
);
4163 IDWriteTextLayout_SetDrawingEffect(This
->layout
, effect
, range
);
4164 return IDWriteTextLayout_Draw(This
->layout
, context
, renderer
, originX
, originY
);
4167 static HRESULT WINAPI
dwritetrimmingsign_GetMetrics(IDWriteInlineObject
*iface
, DWRITE_INLINE_OBJECT_METRICS
*ret
)
4169 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
4170 DWRITE_TEXT_METRICS metrics
;
4173 TRACE("(%p)->(%p)\n", This
, ret
);
4175 hr
= IDWriteTextLayout_GetMetrics(This
->layout
, &metrics
);
4177 memset(ret
, 0, sizeof(*ret
));
4181 ret
->width
= metrics
.width
;
4183 ret
->baseline
= 0.0f
;
4184 ret
->supportsSideways
= FALSE
;
4188 static HRESULT WINAPI
dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject
*iface
, DWRITE_OVERHANG_METRICS
*overhangs
)
4190 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
4191 FIXME("(%p)->(%p): stub\n", This
, overhangs
);
4195 static HRESULT WINAPI
dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject
*iface
, DWRITE_BREAK_CONDITION
*before
,
4196 DWRITE_BREAK_CONDITION
*after
)
4198 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
4200 TRACE("(%p)->(%p %p)\n", This
, before
, after
);
4202 *before
= *after
= DWRITE_BREAK_CONDITION_NEUTRAL
;
4206 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl
= {
4207 dwritetrimmingsign_QueryInterface
,
4208 dwritetrimmingsign_AddRef
,
4209 dwritetrimmingsign_Release
,
4210 dwritetrimmingsign_Draw
,
4211 dwritetrimmingsign_GetMetrics
,
4212 dwritetrimmingsign_GetOverhangMetrics
,
4213 dwritetrimmingsign_GetBreakConditions
4216 static inline BOOL
is_reading_direction_horz(DWRITE_READING_DIRECTION direction
)
4218 return (direction
== DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
) ||
4219 (direction
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
);
4222 static inline BOOL
is_reading_direction_vert(DWRITE_READING_DIRECTION direction
)
4224 return (direction
== DWRITE_READING_DIRECTION_TOP_TO_BOTTOM
) ||
4225 (direction
== DWRITE_READING_DIRECTION_BOTTOM_TO_TOP
);
4228 static inline BOOL
is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction
)
4230 return (direction
== DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT
) ||
4231 (direction
== DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT
);
4234 static inline BOOL
is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction
)
4236 return (direction
== DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM
) ||
4237 (direction
== DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP
);
4240 HRESULT
create_trimmingsign(IDWriteFactory2
*factory
, IDWriteTextFormat
*format
, IDWriteInlineObject
**sign
)
4242 static const WCHAR ellipsisW
= 0x2026;
4243 struct dwrite_trimmingsign
*This
;
4244 DWRITE_READING_DIRECTION reading
;
4245 DWRITE_FLOW_DIRECTION flow
;
4250 /* Validate reading/flow direction here, layout creation won't complain about
4251 invalid combinations. */
4252 reading
= IDWriteTextFormat_GetReadingDirection(format
);
4253 flow
= IDWriteTextFormat_GetFlowDirection(format
);
4255 if ((is_reading_direction_horz(reading
) && is_flow_direction_horz(flow
)) ||
4256 (is_reading_direction_vert(reading
) && is_flow_direction_vert(flow
)))
4257 return DWRITE_E_FLOWDIRECTIONCONFLICTS
;
4259 This
= heap_alloc(sizeof(*This
));
4261 return E_OUTOFMEMORY
;
4263 This
->IDWriteInlineObject_iface
.lpVtbl
= &dwritetrimmingsignvtbl
;
4266 hr
= IDWriteFactory2_CreateTextLayout(factory
, &ellipsisW
, 1, format
, 0.0f
, 0.0f
, &This
->layout
);
4272 IDWriteTextLayout_SetWordWrapping(This
->layout
, DWRITE_WORD_WRAPPING_NO_WRAP
);
4273 *sign
= &This
->IDWriteInlineObject_iface
;
4278 static HRESULT WINAPI
dwritetextformat_QueryInterface(IDWriteTextFormat1
*iface
, REFIID riid
, void **obj
)
4280 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4282 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
4284 if (IsEqualIID(riid
, &IID_IDWriteTextFormat1
) ||
4285 IsEqualIID(riid
, &IID_IDWriteTextFormat
) ||
4286 IsEqualIID(riid
, &IID_IUnknown
))
4289 IDWriteTextFormat1_AddRef(iface
);
4295 return E_NOINTERFACE
;
4298 static ULONG WINAPI
dwritetextformat_AddRef(IDWriteTextFormat1
*iface
)
4300 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4301 ULONG ref
= InterlockedIncrement(&This
->ref
);
4302 TRACE("(%p)->(%d)\n", This
, ref
);
4306 static ULONG WINAPI
dwritetextformat_Release(IDWriteTextFormat1
*iface
)
4308 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4309 ULONG ref
= InterlockedDecrement(&This
->ref
);
4311 TRACE("(%p)->(%d)\n", This
, ref
);
4315 release_format_data(&This
->format
);
4322 static HRESULT WINAPI
dwritetextformat_SetTextAlignment(IDWriteTextFormat1
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
4324 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4325 TRACE("(%p)->(%d)\n", This
, alignment
);
4326 return format_set_textalignment(&This
->format
, alignment
, NULL
);
4329 static HRESULT WINAPI
dwritetextformat_SetParagraphAlignment(IDWriteTextFormat1
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
4331 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4332 TRACE("(%p)->(%d)\n", This
, alignment
);
4333 return format_set_paralignment(&This
->format
, alignment
, NULL
);
4336 static HRESULT WINAPI
dwritetextformat_SetWordWrapping(IDWriteTextFormat1
*iface
, DWRITE_WORD_WRAPPING wrapping
)
4338 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4339 TRACE("(%p)->(%d)\n", This
, wrapping
);
4340 return format_set_wordwrapping(&This
->format
, wrapping
, NULL
);
4343 static HRESULT WINAPI
dwritetextformat_SetReadingDirection(IDWriteTextFormat1
*iface
, DWRITE_READING_DIRECTION direction
)
4345 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4346 TRACE("(%p)->(%d)\n", This
, direction
);
4347 return format_set_readingdirection(&This
->format
, direction
, NULL
);
4350 static HRESULT WINAPI
dwritetextformat_SetFlowDirection(IDWriteTextFormat1
*iface
, DWRITE_FLOW_DIRECTION direction
)
4352 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4354 TRACE("(%p)->(%d)\n", This
, direction
);
4356 if ((UINT32
)direction
> DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT
)
4357 return E_INVALIDARG
;
4359 This
->format
.flow
= direction
;
4363 static HRESULT WINAPI
dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat1
*iface
, FLOAT tabstop
)
4365 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4366 FIXME("(%p)->(%f): stub\n", This
, tabstop
);
4370 static HRESULT WINAPI
dwritetextformat_SetTrimming(IDWriteTextFormat1
*iface
, DWRITE_TRIMMING
const *trimming
,
4371 IDWriteInlineObject
*trimming_sign
)
4373 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4374 TRACE("(%p)->(%p %p)\n", This
, trimming
, trimming_sign
);
4376 This
->format
.trimming
= *trimming
;
4377 if (This
->format
.trimmingsign
)
4378 IDWriteInlineObject_Release(This
->format
.trimmingsign
);
4379 This
->format
.trimmingsign
= trimming_sign
;
4380 if (This
->format
.trimmingsign
)
4381 IDWriteInlineObject_AddRef(This
->format
.trimmingsign
);
4385 static HRESULT WINAPI
dwritetextformat_SetLineSpacing(IDWriteTextFormat1
*iface
, DWRITE_LINE_SPACING_METHOD method
,
4386 FLOAT spacing
, FLOAT baseline
)
4388 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4390 TRACE("(%p)->(%d %f %f)\n", This
, method
, spacing
, baseline
);
4392 if (spacing
< 0.0f
|| (UINT32
)method
> DWRITE_LINE_SPACING_METHOD_UNIFORM
)
4393 return E_INVALIDARG
;
4395 This
->format
.spacingmethod
= method
;
4396 This
->format
.spacing
= spacing
;
4397 This
->format
.baseline
= baseline
;
4401 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextformat_GetTextAlignment(IDWriteTextFormat1
*iface
)
4403 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4404 TRACE("(%p)\n", This
);
4405 return This
->format
.textalignment
;
4408 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextformat_GetParagraphAlignment(IDWriteTextFormat1
*iface
)
4410 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4411 TRACE("(%p)\n", This
);
4412 return This
->format
.paralign
;
4415 static DWRITE_WORD_WRAPPING WINAPI
dwritetextformat_GetWordWrapping(IDWriteTextFormat1
*iface
)
4417 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4418 TRACE("(%p)\n", This
);
4419 return This
->format
.wrapping
;
4422 static DWRITE_READING_DIRECTION WINAPI
dwritetextformat_GetReadingDirection(IDWriteTextFormat1
*iface
)
4424 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4425 TRACE("(%p)\n", This
);
4426 return This
->format
.readingdir
;
4429 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextformat_GetFlowDirection(IDWriteTextFormat1
*iface
)
4431 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4432 TRACE("(%p)\n", This
);
4433 return This
->format
.flow
;
4436 static FLOAT WINAPI
dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat1
*iface
)
4438 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4439 FIXME("(%p): stub\n", This
);
4443 static HRESULT WINAPI
dwritetextformat_GetTrimming(IDWriteTextFormat1
*iface
, DWRITE_TRIMMING
*options
,
4444 IDWriteInlineObject
**trimming_sign
)
4446 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4447 TRACE("(%p)->(%p %p)\n", This
, options
, trimming_sign
);
4449 *options
= This
->format
.trimming
;
4450 if ((*trimming_sign
= This
->format
.trimmingsign
))
4451 IDWriteInlineObject_AddRef(*trimming_sign
);
4456 static HRESULT WINAPI
dwritetextformat_GetLineSpacing(IDWriteTextFormat1
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
4457 FLOAT
*spacing
, FLOAT
*baseline
)
4459 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4460 TRACE("(%p)->(%p %p %p)\n", This
, method
, spacing
, baseline
);
4462 *method
= This
->format
.spacingmethod
;
4463 *spacing
= This
->format
.spacing
;
4464 *baseline
= This
->format
.baseline
;
4468 static HRESULT WINAPI
dwritetextformat_GetFontCollection(IDWriteTextFormat1
*iface
, IDWriteFontCollection
**collection
)
4470 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4472 TRACE("(%p)->(%p)\n", This
, collection
);
4474 *collection
= This
->format
.collection
;
4475 IDWriteFontCollection_AddRef(*collection
);
4480 static UINT32 WINAPI
dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat1
*iface
)
4482 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4483 TRACE("(%p)\n", This
);
4484 return This
->format
.family_len
;
4487 static HRESULT WINAPI
dwritetextformat_GetFontFamilyName(IDWriteTextFormat1
*iface
, WCHAR
*name
, UINT32 size
)
4489 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4491 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
4493 if (size
<= This
->format
.family_len
) return E_NOT_SUFFICIENT_BUFFER
;
4494 strcpyW(name
, This
->format
.family_name
);
4498 static DWRITE_FONT_WEIGHT WINAPI
dwritetextformat_GetFontWeight(IDWriteTextFormat1
*iface
)
4500 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4501 TRACE("(%p)\n", This
);
4502 return This
->format
.weight
;
4505 static DWRITE_FONT_STYLE WINAPI
dwritetextformat_GetFontStyle(IDWriteTextFormat1
*iface
)
4507 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4508 TRACE("(%p)\n", This
);
4509 return This
->format
.style
;
4512 static DWRITE_FONT_STRETCH WINAPI
dwritetextformat_GetFontStretch(IDWriteTextFormat1
*iface
)
4514 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4515 TRACE("(%p)\n", This
);
4516 return This
->format
.stretch
;
4519 static FLOAT WINAPI
dwritetextformat_GetFontSize(IDWriteTextFormat1
*iface
)
4521 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4522 TRACE("(%p)\n", This
);
4523 return This
->format
.fontsize
;
4526 static UINT32 WINAPI
dwritetextformat_GetLocaleNameLength(IDWriteTextFormat1
*iface
)
4528 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4529 TRACE("(%p)\n", This
);
4530 return This
->format
.locale_len
;
4533 static HRESULT WINAPI
dwritetextformat_GetLocaleName(IDWriteTextFormat1
*iface
, WCHAR
*name
, UINT32 size
)
4535 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4537 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
4539 if (size
<= This
->format
.locale_len
) return E_NOT_SUFFICIENT_BUFFER
;
4540 strcpyW(name
, This
->format
.locale
);
4544 static HRESULT WINAPI
dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat1
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
4546 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4548 TRACE("(%p)->(%d)\n", This
, orientation
);
4550 if ((UINT32
)orientation
> DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED
)
4551 return E_INVALIDARG
;
4553 This
->format
.vertical_orientation
= orientation
;
4557 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat1
*iface
)
4559 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4560 TRACE("(%p)\n", This
);
4561 return This
->format
.vertical_orientation
;
4564 static HRESULT WINAPI
dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat1
*iface
, BOOL lastline_wrapping_enabled
)
4566 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4568 TRACE("(%p)->(%d)\n", This
, lastline_wrapping_enabled
);
4570 This
->format
.last_line_wrapping
= !!lastline_wrapping_enabled
;
4574 static BOOL WINAPI
dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat1
*iface
)
4576 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4577 TRACE("(%p)\n", This
);
4578 return This
->format
.last_line_wrapping
;
4581 static HRESULT WINAPI
dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat1
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
4583 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4584 TRACE("(%p)->(%d)\n", This
, alignment
);
4585 return format_set_optical_alignment(&This
->format
, alignment
);
4588 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat1
*iface
)
4590 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4591 TRACE("(%p)\n", This
);
4592 return This
->format
.optical_alignment
;
4595 static HRESULT WINAPI
dwritetextformat1_SetFontFallback(IDWriteTextFormat1
*iface
, IDWriteFontFallback
*fallback
)
4597 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4598 TRACE("(%p)->(%p)\n", This
, fallback
);
4599 return set_fontfallback_for_format(&This
->format
, fallback
);
4602 static HRESULT WINAPI
dwritetextformat1_GetFontFallback(IDWriteTextFormat1
*iface
, IDWriteFontFallback
**fallback
)
4604 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4605 TRACE("(%p)->(%p)\n", This
, fallback
);
4606 return get_fontfallback_from_format(&This
->format
, fallback
);
4609 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl
= {
4610 dwritetextformat_QueryInterface
,
4611 dwritetextformat_AddRef
,
4612 dwritetextformat_Release
,
4613 dwritetextformat_SetTextAlignment
,
4614 dwritetextformat_SetParagraphAlignment
,
4615 dwritetextformat_SetWordWrapping
,
4616 dwritetextformat_SetReadingDirection
,
4617 dwritetextformat_SetFlowDirection
,
4618 dwritetextformat_SetIncrementalTabStop
,
4619 dwritetextformat_SetTrimming
,
4620 dwritetextformat_SetLineSpacing
,
4621 dwritetextformat_GetTextAlignment
,
4622 dwritetextformat_GetParagraphAlignment
,
4623 dwritetextformat_GetWordWrapping
,
4624 dwritetextformat_GetReadingDirection
,
4625 dwritetextformat_GetFlowDirection
,
4626 dwritetextformat_GetIncrementalTabStop
,
4627 dwritetextformat_GetTrimming
,
4628 dwritetextformat_GetLineSpacing
,
4629 dwritetextformat_GetFontCollection
,
4630 dwritetextformat_GetFontFamilyNameLength
,
4631 dwritetextformat_GetFontFamilyName
,
4632 dwritetextformat_GetFontWeight
,
4633 dwritetextformat_GetFontStyle
,
4634 dwritetextformat_GetFontStretch
,
4635 dwritetextformat_GetFontSize
,
4636 dwritetextformat_GetLocaleNameLength
,
4637 dwritetextformat_GetLocaleName
,
4638 dwritetextformat1_SetVerticalGlyphOrientation
,
4639 dwritetextformat1_GetVerticalGlyphOrientation
,
4640 dwritetextformat1_SetLastLineWrapping
,
4641 dwritetextformat1_GetLastLineWrapping
,
4642 dwritetextformat1_SetOpticalAlignment
,
4643 dwritetextformat1_GetOpticalAlignment
,
4644 dwritetextformat1_SetFontFallback
,
4645 dwritetextformat1_GetFontFallback
4648 static struct dwrite_textformat
*unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat
*iface
)
4650 return (iface
->lpVtbl
== (IDWriteTextFormatVtbl
*)&dwritetextformatvtbl
) ?
4651 CONTAINING_RECORD(iface
, struct dwrite_textformat
, IDWriteTextFormat1_iface
) : NULL
;
4654 HRESULT
create_textformat(const WCHAR
*family_name
, IDWriteFontCollection
*collection
, DWRITE_FONT_WEIGHT weight
, DWRITE_FONT_STYLE style
,
4655 DWRITE_FONT_STRETCH stretch
, FLOAT size
, const WCHAR
*locale
, IDWriteTextFormat
**format
)
4657 struct dwrite_textformat
*This
;
4661 This
= heap_alloc(sizeof(struct dwrite_textformat
));
4662 if (!This
) return E_OUTOFMEMORY
;
4664 This
->IDWriteTextFormat1_iface
.lpVtbl
= &dwritetextformatvtbl
;
4666 This
->format
.family_name
= heap_strdupW(family_name
);
4667 This
->format
.family_len
= strlenW(family_name
);
4668 This
->format
.locale
= heap_strdupW(locale
);
4669 This
->format
.locale_len
= strlenW(locale
);
4670 /* force locale name to lower case, layout will inherit this modified value */
4671 strlwrW(This
->format
.locale
);
4672 This
->format
.weight
= weight
;
4673 This
->format
.style
= style
;
4674 This
->format
.fontsize
= size
;
4675 This
->format
.stretch
= stretch
;
4676 This
->format
.textalignment
= DWRITE_TEXT_ALIGNMENT_LEADING
;
4677 This
->format
.optical_alignment
= DWRITE_OPTICAL_ALIGNMENT_NONE
;
4678 This
->format
.paralign
= DWRITE_PARAGRAPH_ALIGNMENT_NEAR
;
4679 This
->format
.wrapping
= DWRITE_WORD_WRAPPING_WRAP
;
4680 This
->format
.last_line_wrapping
= TRUE
;
4681 This
->format
.readingdir
= DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
;
4682 This
->format
.flow
= DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM
;
4683 This
->format
.spacingmethod
= DWRITE_LINE_SPACING_METHOD_DEFAULT
;
4684 This
->format
.vertical_orientation
= DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
4685 This
->format
.spacing
= 0.0f
;
4686 This
->format
.baseline
= 0.0f
;
4687 This
->format
.trimming
.granularity
= DWRITE_TRIMMING_GRANULARITY_NONE
;
4688 This
->format
.trimming
.delimiter
= 0;
4689 This
->format
.trimming
.delimiterCount
= 0;
4690 This
->format
.trimmingsign
= NULL
;
4691 This
->format
.collection
= collection
;
4692 This
->format
.fallback
= NULL
;
4693 IDWriteFontCollection_AddRef(collection
);
4695 *format
= (IDWriteTextFormat
*)&This
->IDWriteTextFormat1_iface
;
4700 static HRESULT WINAPI
dwritetypography_QueryInterface(IDWriteTypography
*iface
, REFIID riid
, void **obj
)
4702 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
4704 TRACE("(%p)->(%s %p)\n", typography
, debugstr_guid(riid
), obj
);
4706 if (IsEqualIID(riid
, &IID_IDWriteTypography
) || IsEqualIID(riid
, &IID_IUnknown
)) {
4708 IDWriteTypography_AddRef(iface
);
4714 return E_NOINTERFACE
;
4717 static ULONG WINAPI
dwritetypography_AddRef(IDWriteTypography
*iface
)
4719 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
4720 ULONG ref
= InterlockedIncrement(&typography
->ref
);
4721 TRACE("(%p)->(%d)\n", typography
, ref
);
4725 static ULONG WINAPI
dwritetypography_Release(IDWriteTypography
*iface
)
4727 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
4728 ULONG ref
= InterlockedDecrement(&typography
->ref
);
4730 TRACE("(%p)->(%d)\n", typography
, ref
);
4733 heap_free(typography
->features
);
4734 heap_free(typography
);
4740 static HRESULT WINAPI
dwritetypography_AddFontFeature(IDWriteTypography
*iface
, DWRITE_FONT_FEATURE feature
)
4742 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
4744 TRACE("(%p)->(%x %u)\n", typography
, feature
.nameTag
, feature
.parameter
);
4746 if (typography
->count
== typography
->allocated
) {
4747 DWRITE_FONT_FEATURE
*ptr
= heap_realloc(typography
->features
, 2*typography
->allocated
*sizeof(DWRITE_FONT_FEATURE
));
4749 return E_OUTOFMEMORY
;
4751 typography
->features
= ptr
;
4752 typography
->allocated
*= 2;
4755 typography
->features
[typography
->count
++] = feature
;
4759 static UINT32 WINAPI
dwritetypography_GetFontFeatureCount(IDWriteTypography
*iface
)
4761 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
4762 TRACE("(%p)\n", typography
);
4763 return typography
->count
;
4766 static HRESULT WINAPI
dwritetypography_GetFontFeature(IDWriteTypography
*iface
, UINT32 index
, DWRITE_FONT_FEATURE
*feature
)
4768 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
4770 TRACE("(%p)->(%u %p)\n", typography
, index
, feature
);
4772 if (index
>= typography
->count
)
4773 return E_INVALIDARG
;
4775 *feature
= typography
->features
[index
];
4779 static const IDWriteTypographyVtbl dwritetypographyvtbl
= {
4780 dwritetypography_QueryInterface
,
4781 dwritetypography_AddRef
,
4782 dwritetypography_Release
,
4783 dwritetypography_AddFontFeature
,
4784 dwritetypography_GetFontFeatureCount
,
4785 dwritetypography_GetFontFeature
4788 HRESULT
create_typography(IDWriteTypography
**ret
)
4790 struct dwrite_typography
*typography
;
4794 typography
= heap_alloc(sizeof(*typography
));
4796 return E_OUTOFMEMORY
;
4798 typography
->IDWriteTypography_iface
.lpVtbl
= &dwritetypographyvtbl
;
4799 typography
->ref
= 1;
4800 typography
->allocated
= 2;
4801 typography
->count
= 0;
4803 typography
->features
= heap_alloc(typography
->allocated
*sizeof(DWRITE_FONT_FEATURE
));
4804 if (!typography
->features
) {
4805 heap_free(typography
);
4806 return E_OUTOFMEMORY
;
4809 *ret
= &typography
->IDWriteTypography_iface
;