2 * Text format and layout
4 * Copyright 2012, 2014-2015 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
28 #include "dwrite_private.h"
30 #include "wine/list.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(dwrite
);
34 struct dwrite_textformat_data
{
40 DWRITE_FONT_WEIGHT weight
;
41 DWRITE_FONT_STYLE style
;
42 DWRITE_FONT_STRETCH stretch
;
44 DWRITE_PARAGRAPH_ALIGNMENT paralign
;
45 DWRITE_READING_DIRECTION readingdir
;
46 DWRITE_WORD_WRAPPING wrapping
;
47 DWRITE_TEXT_ALIGNMENT textalignment
;
48 DWRITE_FLOW_DIRECTION flow
;
49 DWRITE_LINE_SPACING_METHOD spacingmethod
;
50 DWRITE_VERTICAL_GLYPH_ORIENTATION vertical_orientation
;
56 DWRITE_TRIMMING trimming
;
57 IDWriteInlineObject
*trimmingsign
;
59 IDWriteFontCollection
*collection
;
60 IDWriteFontFallback
*fallback
;
63 enum layout_range_attr_kind
{
64 LAYOUT_RANGE_ATTR_WEIGHT
,
65 LAYOUT_RANGE_ATTR_STYLE
,
66 LAYOUT_RANGE_ATTR_STRETCH
,
67 LAYOUT_RANGE_ATTR_FONTSIZE
,
68 LAYOUT_RANGE_ATTR_EFFECT
,
69 LAYOUT_RANGE_ATTR_INLINE
,
70 LAYOUT_RANGE_ATTR_UNDERLINE
,
71 LAYOUT_RANGE_ATTR_STRIKETHROUGH
,
72 LAYOUT_RANGE_ATTR_PAIR_KERNING
,
73 LAYOUT_RANGE_ATTR_FONTCOLL
,
74 LAYOUT_RANGE_ATTR_LOCALE
,
75 LAYOUT_RANGE_ATTR_FONTFAMILY
78 struct layout_range_attr_value
{
79 DWRITE_TEXT_RANGE range
;
81 DWRITE_FONT_WEIGHT weight
;
82 DWRITE_FONT_STYLE style
;
83 DWRITE_FONT_STRETCH stretch
;
85 IDWriteInlineObject
*object
;
90 IDWriteFontCollection
*collection
;
92 const WCHAR
*fontfamily
;
96 enum layout_range_kind
{
98 LAYOUT_RANGE_STRIKETHROUGH
101 struct layout_range_header
{
103 enum layout_range_kind kind
;
104 DWRITE_TEXT_RANGE range
;
107 struct layout_range
{
108 struct layout_range_header h
;
109 DWRITE_FONT_WEIGHT weight
;
110 DWRITE_FONT_STYLE style
;
112 DWRITE_FONT_STRETCH stretch
;
113 IDWriteInlineObject
*object
;
117 IDWriteFontCollection
*collection
;
118 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
122 struct layout_range_bool
{
123 struct layout_range_header h
;
127 enum layout_run_kind
{
132 struct inline_object_run
{
133 IDWriteInlineObject
*object
;
137 struct regular_layout_run
{
138 DWRITE_GLYPH_RUN_DESCRIPTION descr
;
139 DWRITE_GLYPH_RUN run
;
140 DWRITE_SCRIPT_ANALYSIS sa
;
144 DWRITE_GLYPH_OFFSET
*offsets
;
145 /* this is actual glyph count after shaping, it's not necessary the same as reported to Draw() */
151 enum layout_run_kind kind
;
153 struct inline_object_run object
;
154 struct regular_layout_run regular
;
159 struct layout_effective_run
{
161 const struct layout_run
*run
; /* nominal run this one is based on */
162 UINT32 start
; /* relative text position, 0 means first text position of a nominal run */
163 UINT32 length
; /* length in codepoints that this run covers */
164 UINT32 glyphcount
; /* total glyph count in this run */
165 FLOAT origin_x
; /* baseline X position */
166 FLOAT origin_y
; /* baseline Y position */
167 UINT16
*clustermap
; /* effective clustermap, allocated separately, is not reused from nominal map */
170 struct layout_effective_inline
{
172 IDWriteInlineObject
*object
;
179 struct layout_strikethrough
{
181 const struct layout_effective_run
*run
;
182 DWRITE_STRIKETHROUGH s
;
185 struct layout_cluster
{
186 const struct layout_run
*run
; /* link to nominal run this cluster belongs to */
187 UINT32 position
; /* relative to run, first cluster has 0 position */
190 enum layout_recompute_mask
{
191 RECOMPUTE_NOMINAL_RUNS
= 1 << 0,
192 RECOMPUTE_MINIMAL_WIDTH
= 1 << 1,
193 RECOMPUTE_EFFECTIVE_RUNS
= 1 << 2,
194 RECOMPUTE_EVERYTHING
= 0xffff
197 struct dwrite_textlayout
{
198 IDWriteTextLayout2 IDWriteTextLayout2_iface
;
199 IDWriteTextFormat1 IDWriteTextFormat1_iface
;
200 IDWriteTextAnalysisSink IDWriteTextAnalysisSink_iface
;
201 IDWriteTextAnalysisSource IDWriteTextAnalysisSource_iface
;
206 struct dwrite_textformat_data format
;
209 struct list strike_ranges
;
212 /* lists ready to use by Draw() */
214 struct list inlineobjects
;
215 struct list strikethrough
;
218 DWRITE_LINE_BREAKPOINT
*nominal_breakpoints
;
219 DWRITE_LINE_BREAKPOINT
*actual_breakpoints
;
221 struct layout_cluster
*clusters
;
222 DWRITE_CLUSTER_METRICS
*clustermetrics
;
223 UINT32 cluster_count
;
226 DWRITE_LINE_METRICS
*lines
;
230 /* gdi-compatible layout specifics */
232 FLOAT pixels_per_dip
;
233 BOOL use_gdi_natural
;
234 DWRITE_MATRIX transform
;
237 struct dwrite_textformat
{
238 IDWriteTextFormat1 IDWriteTextFormat1_iface
;
240 struct dwrite_textformat_data format
;
243 struct dwrite_trimmingsign
{
244 IDWriteInlineObject IDWriteInlineObject_iface
;
248 struct dwrite_typography
{
249 IDWriteTypography IDWriteTypography_iface
;
252 DWRITE_FONT_FEATURE
*features
;
257 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl
;
259 static void release_format_data(struct dwrite_textformat_data
*data
)
261 if (data
->collection
) IDWriteFontCollection_Release(data
->collection
);
262 if (data
->fallback
) IDWriteFontFallback_Release(data
->fallback
);
263 if (data
->trimmingsign
) IDWriteInlineObject_Release(data
->trimmingsign
);
264 heap_free(data
->family_name
);
265 heap_free(data
->locale
);
268 static inline struct dwrite_textlayout
*impl_from_IDWriteTextLayout2(IDWriteTextLayout2
*iface
)
270 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextLayout2_iface
);
273 static inline struct dwrite_textlayout
*impl_layout_form_IDWriteTextFormat1(IDWriteTextFormat1
*iface
)
275 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextFormat1_iface
);
278 static inline struct dwrite_textlayout
*impl_from_IDWriteTextAnalysisSink(IDWriteTextAnalysisSink
*iface
)
280 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextAnalysisSink_iface
);
283 static inline struct dwrite_textlayout
*impl_from_IDWriteTextAnalysisSource(IDWriteTextAnalysisSource
*iface
)
285 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextAnalysisSource_iface
);
288 static inline struct dwrite_textformat
*impl_from_IDWriteTextFormat1(IDWriteTextFormat1
*iface
)
290 return CONTAINING_RECORD(iface
, struct dwrite_textformat
, IDWriteTextFormat1_iface
);
293 static inline struct dwrite_trimmingsign
*impl_from_IDWriteInlineObject(IDWriteInlineObject
*iface
)
295 return CONTAINING_RECORD(iface
, struct dwrite_trimmingsign
, IDWriteInlineObject_iface
);
298 static inline struct dwrite_typography
*impl_from_IDWriteTypography(IDWriteTypography
*iface
)
300 return CONTAINING_RECORD(iface
, struct dwrite_typography
, IDWriteTypography_iface
);
303 static inline const char *debugstr_run(const struct regular_layout_run
*run
)
305 return wine_dbg_sprintf("[%u,%u)", run
->descr
.textPosition
, run
->descr
.textPosition
+
306 run
->descr
.stringLength
);
309 static HRESULT
get_fontfallback_from_format(const struct dwrite_textformat_data
*format
, IDWriteFontFallback
**fallback
)
311 *fallback
= format
->fallback
;
313 IDWriteFontFallback_AddRef(*fallback
);
317 static HRESULT
set_fontfallback_for_format(struct dwrite_textformat_data
*format
, IDWriteFontFallback
*fallback
)
319 if (format
->fallback
)
320 IDWriteFontFallback_Release(format
->fallback
);
321 format
->fallback
= fallback
;
323 IDWriteFontFallback_AddRef(fallback
);
327 static struct layout_run
*alloc_layout_run(enum layout_run_kind kind
)
329 struct layout_run
*ret
;
331 ret
= heap_alloc(sizeof(*ret
));
332 if (!ret
) return NULL
;
334 memset(ret
, 0, sizeof(*ret
));
336 if (kind
== LAYOUT_RUN_REGULAR
) {
337 ret
->u
.regular
.sa
.script
= Script_Unknown
;
338 ret
->u
.regular
.sa
.shapes
= DWRITE_SCRIPT_SHAPES_DEFAULT
;
344 static void free_layout_runs(struct dwrite_textlayout
*layout
)
346 struct layout_run
*cur
, *cur2
;
347 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->runs
, struct layout_run
, entry
) {
348 list_remove(&cur
->entry
);
349 if (cur
->kind
== LAYOUT_RUN_REGULAR
) {
350 if (cur
->u
.regular
.run
.fontFace
)
351 IDWriteFontFace_Release(cur
->u
.regular
.run
.fontFace
);
352 heap_free(cur
->u
.regular
.glyphs
);
353 heap_free(cur
->u
.regular
.clustermap
);
354 heap_free(cur
->u
.regular
.advances
);
355 heap_free(cur
->u
.regular
.offsets
);
361 static void free_layout_eruns(struct dwrite_textlayout
*layout
)
363 struct layout_effective_inline
*in
, *in2
;
364 struct layout_effective_run
*cur
, *cur2
;
365 struct layout_strikethrough
*s
, *s2
;
367 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->eruns
, struct layout_effective_run
, entry
) {
368 list_remove(&cur
->entry
);
369 heap_free(cur
->clustermap
);
373 LIST_FOR_EACH_ENTRY_SAFE(in
, in2
, &layout
->inlineobjects
, struct layout_effective_inline
, entry
) {
374 list_remove(&in
->entry
);
378 LIST_FOR_EACH_ENTRY_SAFE(s
, s2
, &layout
->strikethrough
, struct layout_strikethrough
, entry
) {
379 list_remove(&s
->entry
);
384 /* Used to resolve break condition by forcing stronger condition over weaker. */
385 static inline DWRITE_BREAK_CONDITION
override_break_condition(DWRITE_BREAK_CONDITION existingbreak
, DWRITE_BREAK_CONDITION newbreak
)
387 switch (existingbreak
) {
388 case DWRITE_BREAK_CONDITION_NEUTRAL
:
390 case DWRITE_BREAK_CONDITION_CAN_BREAK
:
391 return newbreak
== DWRITE_BREAK_CONDITION_NEUTRAL
? existingbreak
: newbreak
;
392 /* let's keep stronger conditions as is */
393 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
:
394 case DWRITE_BREAK_CONDITION_MUST_BREAK
:
397 ERR("unknown break condition %d\n", existingbreak
);
400 return existingbreak
;
403 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
404 static HRESULT
layout_update_breakpoints_range(struct dwrite_textlayout
*layout
, const struct layout_range
*cur
)
406 DWRITE_BREAK_CONDITION before
, after
;
410 /* ignore returned conditions if failed */
411 hr
= IDWriteInlineObject_GetBreakConditions(cur
->object
, &before
, &after
);
413 after
= before
= DWRITE_BREAK_CONDITION_NEUTRAL
;
415 if (!layout
->actual_breakpoints
) {
416 layout
->actual_breakpoints
= heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT
)*layout
->len
);
417 if (!layout
->actual_breakpoints
)
418 return E_OUTOFMEMORY
;
419 memcpy(layout
->actual_breakpoints
, layout
->nominal_breakpoints
, sizeof(DWRITE_LINE_BREAKPOINT
)*layout
->len
);
422 for (i
= cur
->h
.range
.startPosition
; i
< cur
->h
.range
.length
+ cur
->h
.range
.startPosition
; i
++) {
423 /* for first codepoint check if there's anything before it and update accordingly */
424 if (i
== cur
->h
.range
.startPosition
) {
426 layout
->actual_breakpoints
[i
].breakConditionBefore
= layout
->actual_breakpoints
[i
-1].breakConditionAfter
=
427 override_break_condition(layout
->actual_breakpoints
[i
-1].breakConditionAfter
, before
);
429 layout
->actual_breakpoints
[i
].breakConditionBefore
= before
;
430 layout
->actual_breakpoints
[i
].breakConditionAfter
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
432 /* similar check for last codepoint */
433 else if (i
== cur
->h
.range
.startPosition
+ cur
->h
.range
.length
- 1) {
434 if (i
== layout
->len
- 1)
435 layout
->actual_breakpoints
[i
].breakConditionAfter
= after
;
437 layout
->actual_breakpoints
[i
].breakConditionAfter
= layout
->actual_breakpoints
[i
+1].breakConditionBefore
=
438 override_break_condition(layout
->actual_breakpoints
[i
+1].breakConditionBefore
, after
);
439 layout
->actual_breakpoints
[i
].breakConditionBefore
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
441 /* for all positions within a range disable breaks */
443 layout
->actual_breakpoints
[i
].breakConditionBefore
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
444 layout
->actual_breakpoints
[i
].breakConditionAfter
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
447 layout
->actual_breakpoints
[i
].isWhitespace
= FALSE
;
448 layout
->actual_breakpoints
[i
].isSoftHyphen
= FALSE
;
454 static struct layout_range
*get_layout_range_by_pos(struct dwrite_textlayout
*layout
, UINT32 pos
);
456 static inline DWRITE_LINE_BREAKPOINT
get_effective_breakpoint(const struct dwrite_textlayout
*layout
, UINT32 pos
)
458 if (layout
->actual_breakpoints
)
459 return layout
->actual_breakpoints
[pos
];
460 return layout
->nominal_breakpoints
[pos
];
463 static inline void init_cluster_metrics(const struct dwrite_textlayout
*layout
, const struct regular_layout_run
*run
,
464 UINT16 start_glyph
, UINT16 stop_glyph
, UINT32 stop_position
, DWRITE_CLUSTER_METRICS
*metrics
)
466 UINT8 breakcondition
;
470 metrics
->width
= 0.0;
472 /* For clusters on control chars we report zero glyphs, and we need zero cluster
473 width as well; advances are already computed at this point and are not necessary zero. */
474 if (run
->run
.glyphCount
) {
475 for (j
= start_glyph
; j
< stop_glyph
; j
++)
476 metrics
->width
+= run
->run
.glyphAdvances
[j
];
480 position
= stop_position
;
481 if (stop_glyph
== run
->glyphcount
)
482 breakcondition
= get_effective_breakpoint(layout
, stop_position
).breakConditionAfter
;
484 breakcondition
= get_effective_breakpoint(layout
, stop_position
).breakConditionBefore
;
485 if (stop_position
) position
= stop_position
- 1;
488 metrics
->canWrapLineAfter
= breakcondition
== DWRITE_BREAK_CONDITION_CAN_BREAK
||
489 breakcondition
== DWRITE_BREAK_CONDITION_MUST_BREAK
;
490 if (metrics
->length
== 1) {
493 GetStringTypeW(CT_CTYPE1
, &layout
->str
[position
], 1, &type
);
494 metrics
->isWhitespace
= type
== C1_SPACE
;
495 metrics
->isNewline
= FALSE
/* FIXME */;
496 metrics
->isSoftHyphen
= layout
->str
[position
] == 0x00ad /* Unicode Soft Hyphen */;
499 metrics
->isWhitespace
= FALSE
;
500 metrics
->isNewline
= FALSE
;
501 metrics
->isSoftHyphen
= FALSE
;
503 metrics
->isRightToLeft
= run
->run
.bidiLevel
& 1;
504 metrics
->padding
= 0;
509 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
510 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
511 Note that there's no need to reallocate anything at this point as we allocate one cluster per
515 static void layout_set_cluster_metrics(struct dwrite_textlayout
*layout
, const struct layout_run
*r
, UINT32
*cluster
)
517 DWRITE_CLUSTER_METRICS
*metrics
= &layout
->clustermetrics
[*cluster
];
518 struct layout_cluster
*c
= &layout
->clusters
[*cluster
];
519 const struct regular_layout_run
*run
= &r
->u
.regular
;
522 for (i
= 0; i
< run
->descr
.stringLength
; i
++) {
523 BOOL end
= i
== run
->descr
.stringLength
- 1;
525 if (run
->descr
.clusterMap
[start
] != run
->descr
.clusterMap
[i
]) {
526 init_cluster_metrics(layout
, run
, run
->descr
.clusterMap
[start
], run
->descr
.clusterMap
[i
], i
, metrics
);
527 metrics
->length
= i
- start
;
538 init_cluster_metrics(layout
, run
, run
->descr
.clusterMap
[start
], run
->glyphcount
, i
, metrics
);
539 metrics
->length
= i
- start
+ 1;
549 /* This helper should be used to get effective range length, in other words it returns number of text
550 positions from range starting point to the end of the range, limited by layout text length */
551 static inline UINT32
get_clipped_range_length(const struct dwrite_textlayout
*layout
, const struct layout_range
*range
)
553 if (range
->h
.range
.startPosition
+ range
->h
.range
.length
<= layout
->len
)
554 return range
->h
.range
.length
;
555 return layout
->len
- range
->h
.range
.startPosition
;
558 static HRESULT
layout_compute_runs(struct dwrite_textlayout
*layout
)
560 IDWriteTextAnalyzer
*analyzer
;
561 struct layout_range
*range
;
562 struct layout_run
*r
;
566 free_layout_eruns(layout
);
567 free_layout_runs(layout
);
569 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
570 if (!layout
->clustermetrics
) {
571 layout
->clustermetrics
= heap_alloc(layout
->len
*sizeof(*layout
->clustermetrics
));
572 layout
->clusters
= heap_alloc(layout
->len
*sizeof(*layout
->clusters
));
573 if (!layout
->clustermetrics
|| !layout
->clusters
) {
574 heap_free(layout
->clustermetrics
);
575 heap_free(layout
->clusters
);
576 return E_OUTOFMEMORY
;
579 layout
->cluster_count
= 0;
581 hr
= get_textanalyzer(&analyzer
);
585 LIST_FOR_EACH_ENTRY(range
, &layout
->ranges
, struct layout_range
, h
.entry
) {
586 /* we don't care about ranges that don't contain any text */
587 if (range
->h
.range
.startPosition
>= layout
->len
)
590 /* inline objects override actual text in a range */
592 hr
= layout_update_breakpoints_range(layout
, range
);
596 r
= alloc_layout_run(LAYOUT_RUN_INLINE
);
598 return E_OUTOFMEMORY
;
600 r
->u
.object
.object
= range
->object
;
601 r
->u
.object
.length
= get_clipped_range_length(layout
, range
);
602 r
->effect
= range
->effect
;
603 list_add_tail(&layout
->runs
, &r
->entry
);
607 /* initial splitting by script */
608 hr
= IDWriteTextAnalyzer_AnalyzeScript(analyzer
, &layout
->IDWriteTextAnalysisSource_iface
,
609 range
->h
.range
.startPosition
, get_clipped_range_length(layout
, range
), &layout
->IDWriteTextAnalysisSink_iface
);
613 /* this splits it further */
614 hr
= IDWriteTextAnalyzer_AnalyzeBidi(analyzer
, &layout
->IDWriteTextAnalysisSource_iface
,
615 range
->h
.range
.startPosition
, get_clipped_range_length(layout
, range
), &layout
->IDWriteTextAnalysisSink_iface
);
621 LIST_FOR_EACH_ENTRY(r
, &layout
->runs
, struct layout_run
, entry
) {
622 DWRITE_SHAPING_GLYPH_PROPERTIES
*glyph_props
= NULL
;
623 DWRITE_SHAPING_TEXT_PROPERTIES
*text_props
= NULL
;
624 struct regular_layout_run
*run
= &r
->u
.regular
;
625 IDWriteFontFamily
*family
;
626 UINT32 index
, max_count
;
630 /* we need to do very little in case of inline objects */
631 if (r
->kind
== LAYOUT_RUN_INLINE
) {
632 DWRITE_CLUSTER_METRICS
*metrics
= &layout
->clustermetrics
[cluster
];
633 struct layout_cluster
*c
= &layout
->clusters
[cluster
];
634 DWRITE_INLINE_OBJECT_METRICS inlinemetrics
;
636 metrics
->width
= 0.0;
637 metrics
->length
= r
->u
.object
.length
;
638 metrics
->canWrapLineAfter
= FALSE
;
639 metrics
->isWhitespace
= FALSE
;
640 metrics
->isNewline
= FALSE
;
641 metrics
->isSoftHyphen
= FALSE
;
642 metrics
->isRightToLeft
= FALSE
;
643 metrics
->padding
= 0;
645 c
->position
= 0; /* there's always one cluster per inline object, so 0 is valid value */
648 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
649 hr
= IDWriteInlineObject_GetMetrics(r
->u
.object
.object
, &inlinemetrics
);
651 memset(&inlinemetrics
, 0, sizeof(inlinemetrics
));
654 metrics
->width
= inlinemetrics
.width
;
656 /* FIXME: use resolved breakpoints in this case too */
661 range
= get_layout_range_by_pos(layout
, run
->descr
.textPosition
);
662 r
->effect
= range
->effect
;
664 hr
= IDWriteFontCollection_FindFamilyName(range
->collection
, range
->fontfamily
, &index
, &exists
);
665 if (FAILED(hr
) || !exists
) {
666 WARN("%s: family %s not found in collection %p\n", debugstr_run(run
), debugstr_w(range
->fontfamily
), range
->collection
);
670 hr
= IDWriteFontCollection_GetFontFamily(range
->collection
, index
, &family
);
674 hr
= IDWriteFontFamily_GetFirstMatchingFont(family
, range
->weight
, range
->stretch
, range
->style
, &font
);
675 IDWriteFontFamily_Release(family
);
677 WARN("%s: failed to get a matching font\n", debugstr_run(run
));
681 hr
= IDWriteFont_CreateFontFace(font
, &run
->run
.fontFace
);
682 IDWriteFont_Release(font
);
686 run
->run
.fontEmSize
= range
->fontsize
;
687 run
->descr
.localeName
= range
->locale
;
688 run
->clustermap
= heap_alloc(run
->descr
.stringLength
*sizeof(UINT16
));
690 max_count
= 3*run
->descr
.stringLength
/2 + 16;
691 run
->glyphs
= heap_alloc(max_count
*sizeof(UINT16
));
692 if (!run
->clustermap
|| !run
->glyphs
)
695 text_props
= heap_alloc(run
->descr
.stringLength
*sizeof(DWRITE_SHAPING_TEXT_PROPERTIES
));
696 glyph_props
= heap_alloc(max_count
*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES
));
697 if (!text_props
|| !glyph_props
)
701 hr
= IDWriteTextAnalyzer_GetGlyphs(analyzer
, run
->descr
.string
, run
->descr
.stringLength
,
702 run
->run
.fontFace
, run
->run
.isSideways
, run
->run
.bidiLevel
& 1, &run
->sa
, run
->descr
.localeName
,
703 NULL
/* FIXME */, NULL
, NULL
, 0, max_count
, run
->clustermap
, text_props
, run
->glyphs
, glyph_props
,
705 if (hr
== E_NOT_SUFFICIENT_BUFFER
) {
706 heap_free(run
->glyphs
);
707 heap_free(glyph_props
);
709 max_count
= run
->glyphcount
;
711 run
->glyphs
= heap_alloc(max_count
*sizeof(UINT16
));
712 glyph_props
= heap_alloc(max_count
*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES
));
713 if (!run
->glyphs
|| !glyph_props
)
723 heap_free(text_props
);
724 heap_free(glyph_props
);
725 WARN("%s: shaping failed 0x%08x\n", debugstr_run(run
), hr
);
729 run
->run
.glyphIndices
= run
->glyphs
;
730 run
->descr
.clusterMap
= run
->clustermap
;
732 run
->advances
= heap_alloc(run
->glyphcount
*sizeof(FLOAT
));
733 run
->offsets
= heap_alloc(run
->glyphcount
*sizeof(DWRITE_GLYPH_OFFSET
));
734 if (!run
->advances
|| !run
->offsets
)
737 /* now set advances and offsets */
738 if (layout
->gdicompatible
)
739 hr
= IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer
, run
->descr
.string
, run
->descr
.clusterMap
,
740 text_props
, run
->descr
.stringLength
, run
->run
.glyphIndices
, glyph_props
, run
->glyphcount
,
741 run
->run
.fontFace
, run
->run
.fontEmSize
, layout
->pixels_per_dip
, &layout
->transform
, layout
->use_gdi_natural
,
742 run
->run
.isSideways
, run
->run
.bidiLevel
& 1, &run
->sa
, run
->descr
.localeName
, NULL
, NULL
, 0,
743 run
->advances
, run
->offsets
);
745 hr
= IDWriteTextAnalyzer_GetGlyphPlacements(analyzer
, run
->descr
.string
, run
->descr
.clusterMap
, text_props
,
746 run
->descr
.stringLength
, run
->run
.glyphIndices
, glyph_props
, run
->glyphcount
, run
->run
.fontFace
,
747 run
->run
.fontEmSize
, run
->run
.isSideways
, run
->run
.bidiLevel
& 1, &run
->sa
, run
->descr
.localeName
,
748 NULL
, NULL
, 0, run
->advances
, run
->offsets
);
750 heap_free(text_props
);
751 heap_free(glyph_props
);
753 WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_run(run
), hr
);
755 run
->run
.glyphAdvances
= run
->advances
;
756 run
->run
.glyphOffsets
= run
->offsets
;
758 /* Special treatment of control script, shaping code adds normal glyphs for it,
759 with non-zero advances, and layout code exposes those as zero width clusters,
760 so we have to do it manually. */
761 if (run
->sa
.script
== Script_Common
)
762 run
->run
.glyphCount
= 0;
764 run
->run
.glyphCount
= run
->glyphcount
;
765 layout_set_cluster_metrics(layout
, r
, &cluster
);
770 heap_free(text_props
);
771 heap_free(glyph_props
);
772 heap_free(run
->clustermap
);
773 heap_free(run
->glyphs
);
774 heap_free(run
->advances
);
775 heap_free(run
->offsets
);
776 run
->advances
= NULL
;
778 run
->clustermap
= run
->glyphs
= NULL
;
784 layout
->cluster_count
= cluster
;
786 IDWriteTextAnalyzer_Release(analyzer
);
790 static HRESULT
layout_compute(struct dwrite_textlayout
*layout
)
794 if (!(layout
->recompute
& RECOMPUTE_NOMINAL_RUNS
))
797 /* nominal breakpoints are evaluated only once, because string never changes */
798 if (!layout
->nominal_breakpoints
) {
799 IDWriteTextAnalyzer
*analyzer
;
802 layout
->nominal_breakpoints
= heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT
)*layout
->len
);
803 if (!layout
->nominal_breakpoints
)
804 return E_OUTOFMEMORY
;
806 hr
= get_textanalyzer(&analyzer
);
810 hr
= IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer
, &layout
->IDWriteTextAnalysisSource_iface
,
811 0, layout
->len
, &layout
->IDWriteTextAnalysisSink_iface
);
812 IDWriteTextAnalyzer_Release(analyzer
);
814 if (layout
->actual_breakpoints
) {
815 heap_free(layout
->actual_breakpoints
);
816 layout
->actual_breakpoints
= NULL
;
819 hr
= layout_compute_runs(layout
);
821 if (TRACE_ON(dwrite
)) {
822 struct layout_run
*cur
;
824 LIST_FOR_EACH_ENTRY(cur
, &layout
->runs
, struct layout_run
, entry
) {
825 if (cur
->kind
== LAYOUT_RUN_INLINE
)
826 TRACE("run inline object %p, len %u\n", cur
->u
.object
.object
, cur
->u
.object
.length
);
828 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur
->u
.regular
.descr
.textPosition
, cur
->u
.regular
.descr
.textPosition
+
829 cur
->u
.regular
.descr
.stringLength
-1, cur
->u
.regular
.descr
.stringLength
, cur
->u
.regular
.run
.bidiLevel
);
833 layout
->recompute
&= ~RECOMPUTE_NOMINAL_RUNS
;
837 static inline FLOAT
get_cluster_range_width(struct dwrite_textlayout
*layout
, UINT32 start
, UINT32 end
)
840 for (; start
< end
; start
++)
841 width
+= layout
->clustermetrics
[start
].width
;
845 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
846 'cluster_count' indicates how many clusters to add, including first one. */
847 static HRESULT
layout_add_effective_run(struct dwrite_textlayout
*layout
, const struct layout_run
*r
, UINT32 first_cluster
,
848 UINT32 cluster_count
, FLOAT origin_x
, BOOL strikethrough
)
850 UINT32 i
, start
, length
, last_cluster
;
851 struct layout_effective_run
*run
;
853 if (r
->kind
== LAYOUT_RUN_INLINE
) {
854 struct layout_effective_inline
*inlineobject
;
856 inlineobject
= heap_alloc(sizeof(*inlineobject
));
858 return E_OUTOFMEMORY
;
860 inlineobject
->object
= r
->u
.object
.object
;
861 inlineobject
->origin_x
= origin_x
;
862 inlineobject
->origin_y
= 0.0; /* FIXME */
863 /* It's not clear how these two are set, possibly directionality
864 is derived from surrounding text (replaced text could have
865 different ranges which differ in reading direction). */
866 inlineobject
->is_sideways
= FALSE
;
867 inlineobject
->is_rtl
= FALSE
;
868 list_add_tail(&layout
->inlineobjects
, &inlineobject
->entry
);
872 run
= heap_alloc(sizeof(*run
));
874 return E_OUTOFMEMORY
;
876 /* No need to iterate for that, use simple fact that:
877 <last cluster position> = first cluster position> + <sum of cluster lengths not including last one> */
878 last_cluster
= first_cluster
+ cluster_count
- 1;
879 length
= layout
->clusters
[last_cluster
].position
- layout
->clusters
[first_cluster
].position
+
880 layout
->clustermetrics
[last_cluster
].length
;
882 run
->clustermap
= heap_alloc(sizeof(UINT16
)*length
);
883 if (!run
->clustermap
) {
885 return E_OUTOFMEMORY
;
889 run
->start
= start
= layout
->clusters
[first_cluster
].position
;
890 run
->length
= length
;
891 run
->origin_x
= origin_x
;
892 run
->origin_y
= 0.0; /* FIXME: set after line is built */
894 if (r
->u
.regular
.run
.glyphCount
) {
895 /* trim from the left */
896 run
->glyphcount
= r
->u
.regular
.run
.glyphCount
- r
->u
.regular
.clustermap
[start
];
897 /* trim from the right */
898 if (length
< r
->u
.regular
.descr
.stringLength
)
899 run
->glyphcount
-= r
->u
.regular
.clustermap
[start
+ length
];
904 /* cluster map needs to be shifted */
905 for (i
= 0; i
< length
; i
++)
906 run
->clustermap
[i
] = r
->u
.regular
.clustermap
[start
] - start
;
908 list_add_tail(&layout
->eruns
, &run
->entry
);
910 /* Strikethrough style is guaranteed to be consistent within effective run,
911 it's width equals to run width, thikness and offset are derived from
912 font metrics, rest of the values are from layout or run itself */
914 DWRITE_FONT_METRICS metrics
= { 0 };
915 struct layout_strikethrough
*s
;
917 s
= heap_alloc(sizeof(*s
));
919 return E_OUTOFMEMORY
;
921 if (layout
->gdicompatible
) {
922 HRESULT hr
= IDWriteFontFace_GetGdiCompatibleMetrics(
923 r
->u
.regular
.run
.fontFace
,
924 r
->u
.regular
.run
.fontEmSize
,
925 layout
->pixels_per_dip
,
929 WARN("failed to get font metrics, 0x%08x\n", hr
);
932 IDWriteFontFace_GetMetrics(r
->u
.regular
.run
.fontFace
, &metrics
);
934 s
->s
.width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
935 s
->s
.thickness
= metrics
.strikethroughThickness
;
936 s
->s
.offset
= metrics
.strikethroughPosition
;
937 s
->s
.readingDirection
= layout
->format
.readingdir
;
938 s
->s
.flowDirection
= layout
->format
.flow
;
939 s
->s
.localeName
= r
->u
.regular
.descr
.localeName
;
940 s
->s
.measuringMode
= DWRITE_MEASURING_MODE_NATURAL
; /* FIXME */
943 list_add_tail(&layout
->strikethrough
, &s
->entry
);
949 static HRESULT
layout_set_line_metrics(struct dwrite_textlayout
*layout
, DWRITE_LINE_METRICS
*metrics
, UINT32
*line
)
951 if (!layout
->line_alloc
) {
952 layout
->line_alloc
= 5;
953 layout
->lines
= heap_alloc(layout
->line_alloc
*sizeof(*layout
->lines
));
955 return E_OUTOFMEMORY
;
958 if (layout
->line_count
== layout
->line_alloc
) {
959 DWRITE_LINE_METRICS
*l
= heap_realloc(layout
->lines
, layout
->line_alloc
*2*sizeof(*layout
->lines
));
961 return E_OUTOFMEMORY
;
963 layout
->line_alloc
*= 2;
966 layout
->lines
[*line
] = *metrics
;
971 static struct layout_range_header
*get_layout_range_header_by_pos(struct list
*ranges
, UINT32 pos
)
973 struct layout_range_header
*cur
;
975 LIST_FOR_EACH_ENTRY(cur
, ranges
, struct layout_range_header
, entry
) {
976 DWRITE_TEXT_RANGE
*r
= &cur
->range
;
977 if (r
->startPosition
<= pos
&& pos
< r
->startPosition
+ r
->length
)
984 static inline BOOL
layout_get_strikethrough_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
986 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->strike_ranges
, pos
);
987 return ((struct layout_range_bool
*)h
)->value
;
990 static HRESULT
layout_compute_effective_runs(struct dwrite_textlayout
*layout
)
992 DWRITE_LINE_METRICS metrics
;
993 const struct layout_run
*run
;
994 FLOAT width
, origin_x
;
995 UINT32 i
, start
, line
, textpos
;
999 if (!(layout
->recompute
& RECOMPUTE_EFFECTIVE_RUNS
))
1002 hr
= layout_compute(layout
);
1006 layout
->line_count
= 0;
1009 run
= layout
->clusters
[0].run
;
1010 memset(&metrics
, 0, sizeof(metrics
));
1011 s
[0] = s
[1] = layout_get_strikethrough_from_pos(layout
, 0);
1013 for (i
= 0, start
= 0, textpos
= 0, width
= 0.0; i
< layout
->cluster_count
; i
++) {
1014 BOOL can_wrap_after
= layout
->clustermetrics
[i
].canWrapLineAfter
;
1016 s
[1] = layout_get_strikethrough_from_pos(layout
, textpos
);
1018 /* switched to next nominal run, at this point all previous pending clusters are already
1019 checked for layout line overflow, so new effective run will fit in current line */
1020 if (run
!= layout
->clusters
[i
].run
|| s
[0] != s
[1]) {
1021 hr
= layout_add_effective_run(layout
, run
, start
, i
- start
, origin_x
, s
[0]);
1024 origin_x
+= get_cluster_range_width(layout
, start
, i
);
1025 run
= layout
->clusters
[i
].run
;
1029 /* check if we got new line */
1030 if (((can_wrap_after
&& (width
+ layout
->clustermetrics
[i
].width
> layout
->maxwidth
)) ||
1031 layout
->clustermetrics
[i
].isNewline
|| /* always wrap on new line */
1032 i
== layout
->cluster_count
- 1)) /* end of the text */ {
1034 UINT32 strlength
= metrics
.length
, index
= i
;
1037 hr
= layout_add_effective_run(layout
, run
, start
, i
- start
+ 1, origin_x
, s
[0]);
1040 /* we don't need to update origin for next run as we're going to wrap */
1043 /* take a look at clusters we got for this line in reverse order to set
1044 trailing properties for current line */
1046 DWRITE_CLUSTER_METRICS
*cluster
= &layout
->clustermetrics
[index
];
1048 if (!cluster
->isNewline
&& !cluster
->isWhitespace
)
1051 if (cluster
->isNewline
) {
1052 metrics
.trailingWhitespaceLength
+= cluster
->length
;
1053 metrics
.newlineLength
+= cluster
->length
;
1056 if (cluster
->isWhitespace
)
1057 metrics
.trailingWhitespaceLength
+= cluster
->length
;
1059 strlength
-= cluster
->length
;
1063 metrics
.height
= 0.0; /* FIXME */
1064 metrics
.baseline
= 0.0; /* FIXME */
1065 metrics
.isTrimmed
= width
> layout
->maxwidth
;
1066 hr
= layout_set_line_metrics(layout
, &metrics
, &line
);
1070 width
= layout
->clustermetrics
[i
].width
;
1071 memset(&metrics
, 0, sizeof(metrics
));
1076 metrics
.length
+= layout
->clustermetrics
[i
].length
;
1077 width
+= layout
->clustermetrics
[i
].width
;
1081 textpos
+= layout
->clustermetrics
[i
].length
;
1084 layout
->line_count
= line
;
1085 layout
->recompute
&= ~RECOMPUTE_EFFECTIVE_RUNS
;
1089 static BOOL
is_same_layout_attrvalue(struct layout_range_header
const *h
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
1091 struct layout_range_bool
const *range_bool
= (struct layout_range_bool
*)h
;
1092 struct layout_range
const *range
= (struct layout_range
*)h
;
1095 case LAYOUT_RANGE_ATTR_WEIGHT
:
1096 return range
->weight
== value
->u
.weight
;
1097 case LAYOUT_RANGE_ATTR_STYLE
:
1098 return range
->style
== value
->u
.style
;
1099 case LAYOUT_RANGE_ATTR_STRETCH
:
1100 return range
->stretch
== value
->u
.stretch
;
1101 case LAYOUT_RANGE_ATTR_FONTSIZE
:
1102 return range
->fontsize
== value
->u
.fontsize
;
1103 case LAYOUT_RANGE_ATTR_INLINE
:
1104 return range
->object
== value
->u
.object
;
1105 case LAYOUT_RANGE_ATTR_EFFECT
:
1106 return range
->effect
== value
->u
.effect
;
1107 case LAYOUT_RANGE_ATTR_UNDERLINE
:
1108 return range
->underline
== value
->u
.underline
;
1109 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
1110 return range_bool
->value
== value
->u
.strikethrough
;
1111 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
1112 return range
->pair_kerning
== value
->u
.pair_kerning
;
1113 case LAYOUT_RANGE_ATTR_FONTCOLL
:
1114 return range
->collection
== value
->u
.collection
;
1115 case LAYOUT_RANGE_ATTR_LOCALE
:
1116 return strcmpW(range
->locale
, value
->u
.locale
) == 0;
1117 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
1118 return strcmpW(range
->fontfamily
, value
->u
.fontfamily
) == 0;
1126 static inline BOOL
is_same_layout_attributes(struct layout_range_header
const *hleft
, struct layout_range_header
const *hright
)
1128 switch (hleft
->kind
)
1130 case LAYOUT_RANGE_REGULAR
:
1132 struct layout_range
const *left
= (struct layout_range
const*)hleft
;
1133 struct layout_range
const *right
= (struct layout_range
const*)hright
;
1134 return left
->weight
== right
->weight
&&
1135 left
->style
== right
->style
&&
1136 left
->stretch
== right
->stretch
&&
1137 left
->fontsize
== right
->fontsize
&&
1138 left
->object
== right
->object
&&
1139 left
->effect
== right
->effect
&&
1140 left
->underline
== right
->underline
&&
1141 left
->pair_kerning
== right
->pair_kerning
&&
1142 left
->collection
== right
->collection
&&
1143 !strcmpW(left
->locale
, right
->locale
) &&
1144 !strcmpW(left
->fontfamily
, right
->fontfamily
);
1146 case LAYOUT_RANGE_STRIKETHROUGH
:
1148 struct layout_range_bool
const *left
= (struct layout_range_bool
const*)hleft
;
1149 struct layout_range_bool
const *right
= (struct layout_range_bool
const*)hright
;
1150 return left
->value
== right
->value
;
1153 FIXME("unknown range kind %d\n", hleft
->kind
);
1158 static inline BOOL
is_same_text_range(const DWRITE_TEXT_RANGE
*left
, const DWRITE_TEXT_RANGE
*right
)
1160 return left
->startPosition
== right
->startPosition
&& left
->length
== right
->length
;
1163 /* Allocates range and inits it with default values from text format. */
1164 static struct layout_range_header
*alloc_layout_range(struct dwrite_textlayout
*layout
, const DWRITE_TEXT_RANGE
*r
,
1165 enum layout_range_kind kind
)
1167 struct layout_range_header
*h
;
1171 case LAYOUT_RANGE_REGULAR
:
1173 struct layout_range
*range
;
1175 range
= heap_alloc(sizeof(*range
));
1176 if (!range
) return NULL
;
1178 range
->weight
= layout
->format
.weight
;
1179 range
->style
= layout
->format
.style
;
1180 range
->stretch
= layout
->format
.stretch
;
1181 range
->fontsize
= layout
->format
.fontsize
;
1182 range
->object
= NULL
;
1183 range
->effect
= NULL
;
1184 range
->underline
= FALSE
;
1185 range
->pair_kerning
= FALSE
;
1187 range
->fontfamily
= heap_strdupW(layout
->format
.family_name
);
1188 if (!range
->fontfamily
) {
1193 range
->collection
= layout
->format
.collection
;
1194 if (range
->collection
)
1195 IDWriteFontCollection_AddRef(range
->collection
);
1196 strcpyW(range
->locale
, layout
->format
.locale
);
1201 case LAYOUT_RANGE_STRIKETHROUGH
:
1203 struct layout_range_bool
*range
;
1205 range
= heap_alloc(sizeof(*range
));
1206 if (!range
) return NULL
;
1208 range
->value
= FALSE
;
1213 FIXME("unknown range kind %d\n", kind
);
1222 static struct layout_range_header
*alloc_layout_range_from(struct layout_range_header
*h
, const DWRITE_TEXT_RANGE
*r
)
1224 struct layout_range_header
*ret
;
1228 case LAYOUT_RANGE_REGULAR
:
1230 struct layout_range
*from
= (struct layout_range
*)h
;
1232 struct layout_range
*range
= heap_alloc(sizeof(*range
));
1233 if (!range
) return NULL
;
1236 range
->fontfamily
= heap_strdupW(from
->fontfamily
);
1237 if (!range
->fontfamily
) {
1242 /* update refcounts */
1244 IDWriteInlineObject_AddRef(range
->object
);
1246 IUnknown_AddRef(range
->effect
);
1247 if (range
->collection
)
1248 IDWriteFontCollection_AddRef(range
->collection
);
1252 case LAYOUT_RANGE_STRIKETHROUGH
:
1254 struct layout_range_bool
*strike
= heap_alloc(sizeof(*strike
));
1255 if (!strike
) return NULL
;
1257 *strike
= *(struct layout_range_bool
*)h
;
1262 FIXME("unknown range kind %d\n", h
->kind
);
1270 static void free_layout_range(struct layout_range_header
*h
)
1275 if (h
->kind
== LAYOUT_RANGE_REGULAR
) {
1276 struct layout_range
*range
= (struct layout_range
*)h
;
1279 IDWriteInlineObject_Release(range
->object
);
1281 IUnknown_Release(range
->effect
);
1282 if (range
->collection
)
1283 IDWriteFontCollection_Release(range
->collection
);
1284 heap_free(range
->fontfamily
);
1290 static void free_layout_ranges_list(struct dwrite_textlayout
*layout
)
1292 struct layout_range_header
*cur
, *cur2
;
1294 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->ranges
, struct layout_range_header
, entry
) {
1295 list_remove(&cur
->entry
);
1296 free_layout_range(cur
);
1299 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->strike_ranges
, struct layout_range_header
, entry
) {
1300 list_remove(&cur
->entry
);
1301 free_layout_range(cur
);
1305 static struct layout_range_header
*find_outer_range(struct list
*ranges
, const DWRITE_TEXT_RANGE
*range
)
1307 struct layout_range_header
*cur
;
1309 LIST_FOR_EACH_ENTRY(cur
, ranges
, struct layout_range_header
, entry
) {
1311 if (cur
->range
.startPosition
> range
->startPosition
)
1314 if ((cur
->range
.startPosition
+ cur
->range
.length
< range
->startPosition
+ range
->length
) &&
1315 (range
->startPosition
< cur
->range
.startPosition
+ cur
->range
.length
))
1317 if (cur
->range
.startPosition
+ cur
->range
.length
>= range
->startPosition
+ range
->length
)
1324 static struct layout_range
*get_layout_range_by_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
1326 struct layout_range
*cur
;
1328 LIST_FOR_EACH_ENTRY(cur
, &layout
->ranges
, struct layout_range
, h
.entry
) {
1329 DWRITE_TEXT_RANGE
*r
= &cur
->h
.range
;
1330 if (r
->startPosition
<= pos
&& pos
< r
->startPosition
+ r
->length
)
1337 static inline BOOL
set_layout_range_iface_attr(IUnknown
**dest
, IUnknown
*value
)
1339 if (*dest
== value
) return FALSE
;
1342 IUnknown_Release(*dest
);
1345 IUnknown_AddRef(*dest
);
1350 static BOOL
set_layout_range_attrval(struct layout_range_header
*h
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
1352 struct layout_range_bool
*dest_bool
= (struct layout_range_bool
*)h
;
1353 struct layout_range
*dest
= (struct layout_range
*)h
;
1355 BOOL changed
= FALSE
;
1358 case LAYOUT_RANGE_ATTR_WEIGHT
:
1359 changed
= dest
->weight
!= value
->u
.weight
;
1360 dest
->weight
= value
->u
.weight
;
1362 case LAYOUT_RANGE_ATTR_STYLE
:
1363 changed
= dest
->style
!= value
->u
.style
;
1364 dest
->style
= value
->u
.style
;
1366 case LAYOUT_RANGE_ATTR_STRETCH
:
1367 changed
= dest
->stretch
!= value
->u
.stretch
;
1368 dest
->stretch
= value
->u
.stretch
;
1370 case LAYOUT_RANGE_ATTR_FONTSIZE
:
1371 changed
= dest
->fontsize
!= value
->u
.fontsize
;
1372 dest
->fontsize
= value
->u
.fontsize
;
1374 case LAYOUT_RANGE_ATTR_INLINE
:
1375 changed
= set_layout_range_iface_attr((IUnknown
**)&dest
->object
, (IUnknown
*)value
->u
.object
);
1377 case LAYOUT_RANGE_ATTR_EFFECT
:
1378 changed
= set_layout_range_iface_attr((IUnknown
**)&dest
->effect
, (IUnknown
*)value
->u
.effect
);
1380 case LAYOUT_RANGE_ATTR_UNDERLINE
:
1381 changed
= dest
->underline
!= value
->u
.underline
;
1382 dest
->underline
= value
->u
.underline
;
1384 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
1385 changed
= dest_bool
->value
!= value
->u
.strikethrough
;
1386 dest_bool
->value
= value
->u
.strikethrough
;
1388 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
1389 changed
= dest
->pair_kerning
!= value
->u
.pair_kerning
;
1390 dest
->pair_kerning
= value
->u
.pair_kerning
;
1392 case LAYOUT_RANGE_ATTR_FONTCOLL
:
1393 changed
= set_layout_range_iface_attr((IUnknown
**)&dest
->collection
, (IUnknown
*)value
->u
.collection
);
1395 case LAYOUT_RANGE_ATTR_LOCALE
:
1396 changed
= strcmpW(dest
->locale
, value
->u
.locale
) != 0;
1398 strcpyW(dest
->locale
, value
->u
.locale
);
1400 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
1401 changed
= strcmpW(dest
->fontfamily
, value
->u
.fontfamily
) != 0;
1403 heap_free(dest
->fontfamily
);
1404 dest
->fontfamily
= heap_strdupW(value
->u
.fontfamily
);
1414 static inline BOOL
is_in_layout_range(const DWRITE_TEXT_RANGE
*outer
, const DWRITE_TEXT_RANGE
*inner
)
1416 return (inner
->startPosition
>= outer
->startPosition
) &&
1417 (inner
->startPosition
+ inner
->length
<= outer
->startPosition
+ outer
->length
);
1420 static inline HRESULT
return_range(const struct layout_range_header
*h
, DWRITE_TEXT_RANGE
*r
)
1422 if (r
) *r
= h
->range
;
1426 /* Set attribute value for given range, does all needed splitting/merging of existing ranges. */
1427 static HRESULT
set_layout_range_attr(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
1429 struct layout_range_header
*cur
, *right
, *left
, *outer
;
1430 BOOL changed
= FALSE
;
1431 struct list
*ranges
;
1432 DWRITE_TEXT_RANGE r
;
1434 /* select from ranges lists */
1437 case LAYOUT_RANGE_ATTR_WEIGHT
:
1438 case LAYOUT_RANGE_ATTR_STYLE
:
1439 case LAYOUT_RANGE_ATTR_STRETCH
:
1440 case LAYOUT_RANGE_ATTR_FONTSIZE
:
1441 case LAYOUT_RANGE_ATTR_EFFECT
:
1442 case LAYOUT_RANGE_ATTR_INLINE
:
1443 case LAYOUT_RANGE_ATTR_UNDERLINE
:
1444 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
1445 case LAYOUT_RANGE_ATTR_FONTCOLL
:
1446 case LAYOUT_RANGE_ATTR_LOCALE
:
1447 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
1448 ranges
= &layout
->ranges
;
1450 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
1451 ranges
= &layout
->strike_ranges
;
1454 FIXME("unknown attr kind %d\n", attr
);
1458 /* If new range is completely within existing range, split existing range in two */
1459 if ((outer
= find_outer_range(ranges
, &value
->range
))) {
1461 /* no need to add same range */
1462 if (is_same_layout_attrvalue(outer
, attr
, value
))
1465 /* for matching range bounds just replace data */
1466 if (is_same_text_range(&outer
->range
, &value
->range
)) {
1467 changed
= set_layout_range_attrval(outer
, attr
, value
);
1471 /* add new range to the left */
1472 if (value
->range
.startPosition
== outer
->range
.startPosition
) {
1473 left
= alloc_layout_range_from(outer
, &value
->range
);
1474 if (!left
) return E_OUTOFMEMORY
;
1476 changed
= set_layout_range_attrval(left
, attr
, value
);
1477 list_add_before(&outer
->entry
, &left
->entry
);
1478 outer
->range
.startPosition
+= value
->range
.length
;
1479 outer
->range
.length
-= value
->range
.length
;
1483 /* add new range to the right */
1484 if (value
->range
.startPosition
+ value
->range
.length
== outer
->range
.startPosition
+ outer
->range
.length
) {
1485 right
= alloc_layout_range_from(outer
, &value
->range
);
1486 if (!right
) return E_OUTOFMEMORY
;
1488 changed
= set_layout_range_attrval(right
, attr
, value
);
1489 list_add_after(&outer
->entry
, &right
->entry
);
1490 outer
->range
.length
-= value
->range
.length
;
1494 r
.startPosition
= value
->range
.startPosition
+ value
->range
.length
;
1495 r
.length
= outer
->range
.length
+ outer
->range
.startPosition
- r
.startPosition
;
1498 right
= alloc_layout_range_from(outer
, &r
);
1499 /* new range in the middle */
1500 cur
= alloc_layout_range_from(outer
, &value
->range
);
1501 if (!right
|| !cur
) {
1502 free_layout_range(right
);
1503 free_layout_range(cur
);
1504 return E_OUTOFMEMORY
;
1507 /* reuse container range as a left part */
1508 outer
->range
.length
= value
->range
.startPosition
- outer
->range
.startPosition
;
1511 set_layout_range_attrval(cur
, attr
, value
);
1513 list_add_after(&outer
->entry
, &cur
->entry
);
1514 list_add_after(&cur
->entry
, &right
->entry
);
1519 /* Now it's only possible that given range contains some existing ranges, fully or partially.
1520 Update all of them. */
1521 left
= get_layout_range_header_by_pos(ranges
, value
->range
.startPosition
);
1522 if (left
->range
.startPosition
== value
->range
.startPosition
)
1523 changed
= set_layout_range_attrval(left
, attr
, value
);
1524 else /* need to split */ {
1525 r
.startPosition
= value
->range
.startPosition
;
1526 r
.length
= left
->range
.length
- value
->range
.startPosition
+ left
->range
.startPosition
;
1527 left
->range
.length
-= r
.length
;
1528 cur
= alloc_layout_range_from(left
, &r
);
1529 changed
= set_layout_range_attrval(cur
, attr
, value
);
1530 list_add_after(&left
->entry
, &cur
->entry
);
1532 cur
= LIST_ENTRY(list_next(ranges
, &left
->entry
), struct layout_range_header
, entry
);
1534 /* for all existing ranges covered by new one update value */
1535 while (cur
&& is_in_layout_range(&value
->range
, &cur
->range
)) {
1536 changed
= set_layout_range_attrval(cur
, attr
, value
);
1537 cur
= LIST_ENTRY(list_next(ranges
, &cur
->entry
), struct layout_range_header
, entry
);
1540 /* it's possible rightmost range intersects */
1541 if (cur
&& (cur
->range
.startPosition
< value
->range
.startPosition
+ value
->range
.length
)) {
1542 r
.startPosition
= cur
->range
.startPosition
;
1543 r
.length
= value
->range
.startPosition
+ value
->range
.length
- cur
->range
.startPosition
;
1544 left
= alloc_layout_range_from(cur
, &r
);
1545 changed
= set_layout_range_attrval(left
, attr
, value
);
1546 cur
->range
.startPosition
+= left
->range
.length
;
1547 cur
->range
.length
-= left
->range
.length
;
1548 list_add_before(&cur
->entry
, &left
->entry
);
1553 struct list
*next
, *i
;
1555 layout
->recompute
= RECOMPUTE_EVERYTHING
;
1556 i
= list_head(ranges
);
1557 while ((next
= list_next(ranges
, i
))) {
1558 struct layout_range_header
*next_range
= LIST_ENTRY(next
, struct layout_range_header
, entry
);
1560 cur
= LIST_ENTRY(i
, struct layout_range_header
, entry
);
1561 if (is_same_layout_attributes(cur
, next_range
)) {
1562 /* remove similar range */
1563 cur
->range
.length
+= next_range
->range
.length
;
1565 free_layout_range(next_range
);
1568 i
= list_next(ranges
, i
);
1575 static inline const WCHAR
*get_string_attribute_ptr(struct layout_range
*range
, enum layout_range_attr_kind kind
)
1580 case LAYOUT_RANGE_ATTR_LOCALE
:
1581 str
= range
->locale
;
1583 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
1584 str
= range
->fontfamily
;
1593 static HRESULT
get_string_attribute_length(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind kind
, UINT32 position
,
1594 UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
1596 struct layout_range
*range
;
1599 range
= get_layout_range_by_pos(layout
, position
);
1605 str
= get_string_attribute_ptr(range
, kind
);
1606 *length
= strlenW(str
);
1607 return return_range(&range
->h
, r
);
1610 static HRESULT
get_string_attribute_value(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind kind
, UINT32 position
,
1611 WCHAR
*ret
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
1613 struct layout_range
*range
;
1617 return E_INVALIDARG
;
1620 range
= get_layout_range_by_pos(layout
, position
);
1622 return E_INVALIDARG
;
1624 str
= get_string_attribute_ptr(range
, kind
);
1625 if (length
< strlenW(str
) + 1)
1626 return E_NOT_SUFFICIENT_BUFFER
;
1629 return return_range(&range
->h
, r
);
1632 static HRESULT WINAPI
dwritetextlayout_QueryInterface(IDWriteTextLayout2
*iface
, REFIID riid
, void **obj
)
1634 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1636 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
1640 if (IsEqualIID(riid
, &IID_IDWriteTextLayout2
) ||
1641 IsEqualIID(riid
, &IID_IDWriteTextLayout1
) ||
1642 IsEqualIID(riid
, &IID_IDWriteTextLayout
) ||
1643 IsEqualIID(riid
, &IID_IUnknown
))
1647 else if (IsEqualIID(riid
, &IID_IDWriteTextFormat1
) ||
1648 IsEqualIID(riid
, &IID_IDWriteTextFormat
))
1649 *obj
= &This
->IDWriteTextFormat1_iface
;
1652 IDWriteTextLayout2_AddRef(iface
);
1656 return E_NOINTERFACE
;
1659 static ULONG WINAPI
dwritetextlayout_AddRef(IDWriteTextLayout2
*iface
)
1661 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1662 ULONG ref
= InterlockedIncrement(&This
->ref
);
1663 TRACE("(%p)->(%d)\n", This
, ref
);
1667 static ULONG WINAPI
dwritetextlayout_Release(IDWriteTextLayout2
*iface
)
1669 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1670 ULONG ref
= InterlockedDecrement(&This
->ref
);
1672 TRACE("(%p)->(%d)\n", This
, ref
);
1675 free_layout_ranges_list(This
);
1676 free_layout_eruns(This
);
1677 free_layout_runs(This
);
1678 release_format_data(&This
->format
);
1679 heap_free(This
->nominal_breakpoints
);
1680 heap_free(This
->actual_breakpoints
);
1681 heap_free(This
->clustermetrics
);
1682 heap_free(This
->clusters
);
1683 heap_free(This
->lines
);
1684 heap_free(This
->str
);
1691 static HRESULT WINAPI
dwritetextlayout_SetTextAlignment(IDWriteTextLayout2
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
1693 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1694 TRACE("(%p)->(%d)\n", This
, alignment
);
1695 return IDWriteTextFormat1_SetTextAlignment(&This
->IDWriteTextFormat1_iface
, alignment
);
1698 static HRESULT WINAPI
dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout2
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
1700 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1701 TRACE("(%p)->(%d)\n", This
, alignment
);
1702 return IDWriteTextFormat1_SetParagraphAlignment(&This
->IDWriteTextFormat1_iface
, alignment
);
1705 static HRESULT WINAPI
dwritetextlayout_SetWordWrapping(IDWriteTextLayout2
*iface
, DWRITE_WORD_WRAPPING wrapping
)
1707 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1708 TRACE("(%p)->(%d)\n", This
, wrapping
);
1709 return IDWriteTextFormat1_SetWordWrapping(&This
->IDWriteTextFormat1_iface
, wrapping
);
1712 static HRESULT WINAPI
dwritetextlayout_SetReadingDirection(IDWriteTextLayout2
*iface
, DWRITE_READING_DIRECTION direction
)
1714 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1715 TRACE("(%p)->(%d)\n", This
, direction
);
1716 return IDWriteTextFormat1_SetReadingDirection(&This
->IDWriteTextFormat1_iface
, direction
);
1719 static HRESULT WINAPI
dwritetextlayout_SetFlowDirection(IDWriteTextLayout2
*iface
, DWRITE_FLOW_DIRECTION direction
)
1721 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1722 TRACE("(%p)->(%d)\n", This
, direction
);
1723 return IDWriteTextFormat1_SetFlowDirection(&This
->IDWriteTextFormat1_iface
, direction
);
1726 static HRESULT WINAPI
dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout2
*iface
, FLOAT tabstop
)
1728 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1729 TRACE("(%p)->(%.2f)\n", This
, tabstop
);
1730 return IDWriteTextFormat1_SetIncrementalTabStop(&This
->IDWriteTextFormat1_iface
, tabstop
);
1733 static HRESULT WINAPI
dwritetextlayout_SetTrimming(IDWriteTextLayout2
*iface
, DWRITE_TRIMMING
const *trimming
,
1734 IDWriteInlineObject
*trimming_sign
)
1736 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1737 TRACE("(%p)->(%p %p)\n", This
, trimming
, trimming_sign
);
1738 return IDWriteTextFormat1_SetTrimming(&This
->IDWriteTextFormat1_iface
, trimming
, trimming_sign
);
1741 static HRESULT WINAPI
dwritetextlayout_SetLineSpacing(IDWriteTextLayout2
*iface
, DWRITE_LINE_SPACING_METHOD spacing
,
1742 FLOAT line_spacing
, FLOAT baseline
)
1744 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1745 TRACE("(%p)->(%d %.2f %.2f)\n", This
, spacing
, line_spacing
, baseline
);
1746 return IDWriteTextFormat1_SetLineSpacing(&This
->IDWriteTextFormat1_iface
, spacing
, line_spacing
, baseline
);
1749 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextlayout_GetTextAlignment(IDWriteTextLayout2
*iface
)
1751 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1752 TRACE("(%p)\n", This
);
1753 return IDWriteTextFormat1_GetTextAlignment(&This
->IDWriteTextFormat1_iface
);
1756 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout2
*iface
)
1758 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1759 TRACE("(%p)\n", This
);
1760 return IDWriteTextFormat1_GetParagraphAlignment(&This
->IDWriteTextFormat1_iface
);
1763 static DWRITE_WORD_WRAPPING WINAPI
dwritetextlayout_GetWordWrapping(IDWriteTextLayout2
*iface
)
1765 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1766 TRACE("(%p)\n", This
);
1767 return IDWriteTextFormat1_GetWordWrapping(&This
->IDWriteTextFormat1_iface
);
1770 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_GetReadingDirection(IDWriteTextLayout2
*iface
)
1772 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1773 TRACE("(%p)\n", This
);
1774 return IDWriteTextFormat1_GetReadingDirection(&This
->IDWriteTextFormat1_iface
);
1777 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextlayout_GetFlowDirection(IDWriteTextLayout2
*iface
)
1779 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1780 TRACE("(%p)\n", This
);
1781 return IDWriteTextFormat1_GetFlowDirection(&This
->IDWriteTextFormat1_iface
);
1784 static FLOAT WINAPI
dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout2
*iface
)
1786 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1787 TRACE("(%p)\n", This
);
1788 return IDWriteTextFormat1_GetIncrementalTabStop(&This
->IDWriteTextFormat1_iface
);
1791 static HRESULT WINAPI
dwritetextlayout_GetTrimming(IDWriteTextLayout2
*iface
, DWRITE_TRIMMING
*options
,
1792 IDWriteInlineObject
**trimming_sign
)
1794 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1795 TRACE("(%p)->(%p %p)\n", This
, options
, trimming_sign
);
1796 return IDWriteTextFormat1_GetTrimming(&This
->IDWriteTextFormat1_iface
, options
, trimming_sign
);
1799 static HRESULT WINAPI
dwritetextlayout_GetLineSpacing(IDWriteTextLayout2
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
1800 FLOAT
*spacing
, FLOAT
*baseline
)
1802 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1803 TRACE("(%p)->(%p %p %p)\n", This
, method
, spacing
, baseline
);
1804 return IDWriteTextFormat1_GetLineSpacing(&This
->IDWriteTextFormat1_iface
, method
, spacing
, baseline
);
1807 static HRESULT WINAPI
dwritetextlayout_GetFontCollection(IDWriteTextLayout2
*iface
, IDWriteFontCollection
**collection
)
1809 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1810 TRACE("(%p)->(%p)\n", This
, collection
);
1811 return IDWriteTextFormat1_GetFontCollection(&This
->IDWriteTextFormat1_iface
, collection
);
1814 static UINT32 WINAPI
dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout2
*iface
)
1816 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1817 TRACE("(%p)\n", This
);
1818 return IDWriteTextFormat1_GetFontFamilyNameLength(&This
->IDWriteTextFormat1_iface
);
1821 static HRESULT WINAPI
dwritetextlayout_GetFontFamilyName(IDWriteTextLayout2
*iface
, WCHAR
*name
, UINT32 size
)
1823 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1824 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
1825 return IDWriteTextFormat1_GetFontFamilyName(&This
->IDWriteTextFormat1_iface
, name
, size
);
1828 static DWRITE_FONT_WEIGHT WINAPI
dwritetextlayout_GetFontWeight(IDWriteTextLayout2
*iface
)
1830 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1831 TRACE("(%p)\n", This
);
1832 return IDWriteTextFormat1_GetFontWeight(&This
->IDWriteTextFormat1_iface
);
1835 static DWRITE_FONT_STYLE WINAPI
dwritetextlayout_GetFontStyle(IDWriteTextLayout2
*iface
)
1837 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1838 TRACE("(%p)\n", This
);
1839 return IDWriteTextFormat1_GetFontStyle(&This
->IDWriteTextFormat1_iface
);
1842 static DWRITE_FONT_STRETCH WINAPI
dwritetextlayout_GetFontStretch(IDWriteTextLayout2
*iface
)
1844 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1845 TRACE("(%p)\n", This
);
1846 return IDWriteTextFormat1_GetFontStretch(&This
->IDWriteTextFormat1_iface
);
1849 static FLOAT WINAPI
dwritetextlayout_GetFontSize(IDWriteTextLayout2
*iface
)
1851 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1852 TRACE("(%p)\n", This
);
1853 return IDWriteTextFormat1_GetFontSize(&This
->IDWriteTextFormat1_iface
);
1856 static UINT32 WINAPI
dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout2
*iface
)
1858 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1859 TRACE("(%p)\n", This
);
1860 return IDWriteTextFormat1_GetLocaleNameLength(&This
->IDWriteTextFormat1_iface
);
1863 static HRESULT WINAPI
dwritetextlayout_GetLocaleName(IDWriteTextLayout2
*iface
, WCHAR
*name
, UINT32 size
)
1865 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1866 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
1867 return IDWriteTextFormat1_GetLocaleName(&This
->IDWriteTextFormat1_iface
, name
, size
);
1870 static HRESULT WINAPI
dwritetextlayout_SetMaxWidth(IDWriteTextLayout2
*iface
, FLOAT maxWidth
)
1872 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1873 TRACE("(%p)->(%.1f)\n", This
, maxWidth
);
1876 return E_INVALIDARG
;
1878 This
->maxwidth
= maxWidth
;
1882 static HRESULT WINAPI
dwritetextlayout_SetMaxHeight(IDWriteTextLayout2
*iface
, FLOAT maxHeight
)
1884 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1885 TRACE("(%p)->(%.1f)\n", This
, maxHeight
);
1887 if (maxHeight
< 0.0)
1888 return E_INVALIDARG
;
1890 This
->maxheight
= maxHeight
;
1894 static HRESULT WINAPI
dwritetextlayout_SetFontCollection(IDWriteTextLayout2
*iface
, IDWriteFontCollection
* collection
, DWRITE_TEXT_RANGE range
)
1896 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1897 struct layout_range_attr_value value
;
1899 TRACE("(%p)->(%p %s)\n", This
, collection
, debugstr_range(&range
));
1901 value
.range
= range
;
1902 value
.u
.collection
= collection
;
1903 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTCOLL
, &value
);
1906 static HRESULT WINAPI
dwritetextlayout_SetFontFamilyName(IDWriteTextLayout2
*iface
, WCHAR
const *name
, DWRITE_TEXT_RANGE range
)
1908 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1909 struct layout_range_attr_value value
;
1911 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(name
), debugstr_range(&range
));
1914 return E_INVALIDARG
;
1916 value
.range
= range
;
1917 value
.u
.fontfamily
= name
;
1918 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, &value
);
1921 static HRESULT WINAPI
dwritetextlayout_SetFontWeight(IDWriteTextLayout2
*iface
, DWRITE_FONT_WEIGHT weight
, DWRITE_TEXT_RANGE range
)
1923 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1924 struct layout_range_attr_value value
;
1926 TRACE("(%p)->(%d %s)\n", This
, weight
, debugstr_range(&range
));
1928 value
.range
= range
;
1929 value
.u
.weight
= weight
;
1930 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_WEIGHT
, &value
);
1933 static HRESULT WINAPI
dwritetextlayout_SetFontStyle(IDWriteTextLayout2
*iface
, DWRITE_FONT_STYLE style
, DWRITE_TEXT_RANGE range
)
1935 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1936 struct layout_range_attr_value value
;
1938 TRACE("(%p)->(%d %s)\n", This
, style
, debugstr_range(&range
));
1940 if ((UINT32
)style
> DWRITE_FONT_STYLE_ITALIC
)
1941 return E_INVALIDARG
;
1943 value
.range
= range
;
1944 value
.u
.style
= style
;
1945 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STYLE
, &value
);
1948 static HRESULT WINAPI
dwritetextlayout_SetFontStretch(IDWriteTextLayout2
*iface
, DWRITE_FONT_STRETCH stretch
, DWRITE_TEXT_RANGE range
)
1950 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1951 struct layout_range_attr_value value
;
1953 TRACE("(%p)->(%d %s)\n", This
, stretch
, debugstr_range(&range
));
1955 if (stretch
== DWRITE_FONT_STRETCH_UNDEFINED
|| (UINT32
)stretch
> DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
1956 return E_INVALIDARG
;
1958 value
.range
= range
;
1959 value
.u
.stretch
= stretch
;
1960 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STRETCH
, &value
);
1963 static HRESULT WINAPI
dwritetextlayout_SetFontSize(IDWriteTextLayout2
*iface
, FLOAT size
, DWRITE_TEXT_RANGE range
)
1965 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1966 struct layout_range_attr_value value
;
1968 TRACE("(%p)->(%.2f %s)\n", This
, size
, debugstr_range(&range
));
1971 return E_INVALIDARG
;
1973 value
.range
= range
;
1974 value
.u
.fontsize
= size
;
1975 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTSIZE
, &value
);
1978 static HRESULT WINAPI
dwritetextlayout_SetUnderline(IDWriteTextLayout2
*iface
, BOOL underline
, DWRITE_TEXT_RANGE range
)
1980 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1981 struct layout_range_attr_value value
;
1983 TRACE("(%p)->(%d %s)\n", This
, underline
, debugstr_range(&range
));
1985 value
.range
= range
;
1986 value
.u
.underline
= underline
;
1987 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_UNDERLINE
, &value
);
1990 static HRESULT WINAPI
dwritetextlayout_SetStrikethrough(IDWriteTextLayout2
*iface
, BOOL strikethrough
, DWRITE_TEXT_RANGE range
)
1992 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
1993 struct layout_range_attr_value value
;
1995 TRACE("(%p)->(%d %s)\n", This
, strikethrough
, debugstr_range(&range
));
1997 value
.range
= range
;
1998 value
.u
.strikethrough
= strikethrough
;
1999 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STRIKETHROUGH
, &value
);
2002 static HRESULT WINAPI
dwritetextlayout_SetDrawingEffect(IDWriteTextLayout2
*iface
, IUnknown
* effect
, DWRITE_TEXT_RANGE range
)
2004 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2005 struct layout_range_attr_value value
;
2007 TRACE("(%p)->(%p %s)\n", This
, effect
, debugstr_range(&range
));
2009 value
.range
= range
;
2010 value
.u
.effect
= effect
;
2011 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_EFFECT
, &value
);
2014 static HRESULT WINAPI
dwritetextlayout_SetInlineObject(IDWriteTextLayout2
*iface
, IDWriteInlineObject
*object
, DWRITE_TEXT_RANGE range
)
2016 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2017 struct layout_range_attr_value value
;
2019 TRACE("(%p)->(%p %s)\n", This
, object
, debugstr_range(&range
));
2021 value
.range
= range
;
2022 value
.u
.object
= object
;
2023 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_INLINE
, &value
);
2026 static HRESULT WINAPI
dwritetextlayout_SetTypography(IDWriteTextLayout2
*iface
, IDWriteTypography
* typography
, DWRITE_TEXT_RANGE range
)
2028 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2029 FIXME("(%p)->(%p %s): stub\n", This
, typography
, debugstr_range(&range
));
2033 static HRESULT WINAPI
dwritetextlayout_SetLocaleName(IDWriteTextLayout2
*iface
, WCHAR
const* locale
, DWRITE_TEXT_RANGE range
)
2035 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2036 struct layout_range_attr_value value
;
2038 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(locale
), debugstr_range(&range
));
2040 if (!locale
|| strlenW(locale
) > LOCALE_NAME_MAX_LENGTH
-1)
2041 return E_INVALIDARG
;
2043 value
.range
= range
;
2044 value
.u
.locale
= locale
;
2045 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_LOCALE
, &value
);
2048 static FLOAT WINAPI
dwritetextlayout_GetMaxWidth(IDWriteTextLayout2
*iface
)
2050 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2051 TRACE("(%p)\n", This
);
2052 return This
->maxwidth
;
2055 static FLOAT WINAPI
dwritetextlayout_GetMaxHeight(IDWriteTextLayout2
*iface
)
2057 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2058 TRACE("(%p)\n", This
);
2059 return This
->maxheight
;
2062 static HRESULT WINAPI
dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout2
*iface
, UINT32 position
,
2063 IDWriteFontCollection
** collection
, DWRITE_TEXT_RANGE
*r
)
2065 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2066 struct layout_range
*range
;
2068 TRACE("(%p)->(%u %p %p)\n", This
, position
, collection
, r
);
2070 if (position
>= This
->len
)
2073 range
= get_layout_range_by_pos(This
, position
);
2074 *collection
= range
->collection
;
2076 IDWriteFontCollection_AddRef(*collection
);
2078 return return_range(&range
->h
, r
);
2081 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout2
*iface
,
2082 UINT32 position
, UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
2084 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2085 TRACE("(%p)->(%d %p %p)\n", This
, position
, length
, r
);
2086 return get_string_attribute_length(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, length
, r
);
2089 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout2
*iface
,
2090 UINT32 position
, WCHAR
*name
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
2092 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2093 TRACE("(%p)->(%u %p %u %p)\n", This
, position
, name
, length
, r
);
2094 return get_string_attribute_value(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, name
, length
, r
);
2097 static HRESULT WINAPI
dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout2
*iface
,
2098 UINT32 position
, DWRITE_FONT_WEIGHT
*weight
, DWRITE_TEXT_RANGE
*r
)
2100 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2101 struct layout_range
*range
;
2103 TRACE("(%p)->(%u %p %p)\n", This
, position
, weight
, r
);
2105 if (position
>= This
->len
)
2108 range
= get_layout_range_by_pos(This
, position
);
2109 *weight
= range
->weight
;
2111 return return_range(&range
->h
, r
);
2114 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout2
*iface
,
2115 UINT32 position
, DWRITE_FONT_STYLE
*style
, DWRITE_TEXT_RANGE
*r
)
2117 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2118 struct layout_range
*range
;
2120 TRACE("(%p)->(%u %p %p)\n", This
, position
, style
, r
);
2122 range
= get_layout_range_by_pos(This
, position
);
2123 *style
= range
->style
;
2124 return return_range(&range
->h
, r
);
2127 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout2
*iface
,
2128 UINT32 position
, DWRITE_FONT_STRETCH
*stretch
, DWRITE_TEXT_RANGE
*r
)
2130 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2131 struct layout_range
*range
;
2133 TRACE("(%p)->(%u %p %p)\n", This
, position
, stretch
, r
);
2135 range
= get_layout_range_by_pos(This
, position
);
2136 *stretch
= range
->stretch
;
2137 return return_range(&range
->h
, r
);
2140 static HRESULT WINAPI
dwritetextlayout_layout_GetFontSize(IDWriteTextLayout2
*iface
,
2141 UINT32 position
, FLOAT
*size
, DWRITE_TEXT_RANGE
*r
)
2143 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2144 struct layout_range
*range
;
2146 TRACE("(%p)->(%u %p %p)\n", This
, position
, size
, r
);
2148 range
= get_layout_range_by_pos(This
, position
);
2149 *size
= range
->fontsize
;
2150 return return_range(&range
->h
, r
);
2153 static HRESULT WINAPI
dwritetextlayout_GetUnderline(IDWriteTextLayout2
*iface
,
2154 UINT32 position
, BOOL
*underline
, DWRITE_TEXT_RANGE
*r
)
2156 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2157 struct layout_range
*range
;
2159 TRACE("(%p)->(%u %p %p)\n", This
, position
, underline
, r
);
2161 if (position
>= This
->len
)
2164 range
= get_layout_range_by_pos(This
, position
);
2165 *underline
= range
->underline
;
2167 return return_range(&range
->h
, r
);
2170 static HRESULT WINAPI
dwritetextlayout_GetStrikethrough(IDWriteTextLayout2
*iface
,
2171 UINT32 position
, BOOL
*strikethrough
, DWRITE_TEXT_RANGE
*r
)
2173 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2174 struct layout_range_bool
*range
;
2176 TRACE("(%p)->(%u %p %p)\n", This
, position
, strikethrough
, r
);
2178 if (position
>= This
->len
)
2181 range
= (struct layout_range_bool
*)get_layout_range_header_by_pos(&This
->strike_ranges
, position
);
2182 *strikethrough
= range
->value
;
2184 return return_range(&range
->h
, r
);
2187 static HRESULT WINAPI
dwritetextlayout_GetDrawingEffect(IDWriteTextLayout2
*iface
,
2188 UINT32 position
, IUnknown
**effect
, DWRITE_TEXT_RANGE
*r
)
2190 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2191 struct layout_range
*range
;
2193 TRACE("(%p)->(%u %p %p)\n", This
, position
, effect
, r
);
2195 if (position
>= This
->len
)
2198 range
= get_layout_range_by_pos(This
, position
);
2199 *effect
= range
->effect
;
2201 IUnknown_AddRef(*effect
);
2203 return return_range(&range
->h
, r
);
2206 static HRESULT WINAPI
dwritetextlayout_GetInlineObject(IDWriteTextLayout2
*iface
,
2207 UINT32 position
, IDWriteInlineObject
**object
, DWRITE_TEXT_RANGE
*r
)
2209 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2210 struct layout_range
*range
;
2212 TRACE("(%p)->(%u %p %p)\n", This
, position
, object
, r
);
2214 if (position
>= This
->len
)
2217 range
= get_layout_range_by_pos(This
, position
);
2218 *object
= range
->object
;
2220 IDWriteInlineObject_AddRef(*object
);
2222 return return_range(&range
->h
, r
);
2225 static HRESULT WINAPI
dwritetextlayout_GetTypography(IDWriteTextLayout2
*iface
,
2226 UINT32 position
, IDWriteTypography
** typography
, DWRITE_TEXT_RANGE
*range
)
2228 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2229 FIXME("(%p)->(%u %p %p): stub\n", This
, position
, typography
, range
);
2233 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout2
*iface
,
2234 UINT32 position
, UINT32
* length
, DWRITE_TEXT_RANGE
*r
)
2236 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2237 TRACE("(%p)->(%u %p %p)\n", This
, position
, length
, r
);
2238 return get_string_attribute_length(This
, LAYOUT_RANGE_ATTR_LOCALE
, position
, length
, r
);
2241 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout2
*iface
,
2242 UINT32 position
, WCHAR
* locale
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
2244 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2245 TRACE("(%p)->(%u %p %u %p)\n", This
, position
, locale
, length
, r
);
2246 return get_string_attribute_value(This
, LAYOUT_RANGE_ATTR_LOCALE
, position
, locale
, length
, r
);
2249 static HRESULT WINAPI
dwritetextlayout_Draw(IDWriteTextLayout2
*iface
,
2250 void *context
, IDWriteTextRenderer
* renderer
, FLOAT origin_x
, FLOAT origin_y
)
2252 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2253 struct layout_effective_inline
*inlineobject
;
2254 struct layout_effective_run
*run
;
2255 struct layout_strikethrough
*s
;
2258 TRACE("(%p)->(%p %p %.2f %.2f)\n", This
, context
, renderer
, origin_x
, origin_y
);
2260 hr
= layout_compute_effective_runs(This
);
2264 /* 1. Regular runs */
2265 LIST_FOR_EACH_ENTRY(run
, &This
->eruns
, struct layout_effective_run
, entry
) {
2266 const struct regular_layout_run
*regular
= &run
->run
->u
.regular
;
2267 UINT32 start_glyph
= regular
->clustermap
[run
->start
];
2268 DWRITE_GLYPH_RUN_DESCRIPTION descr
;
2269 DWRITE_GLYPH_RUN glyph_run
;
2271 /* Everything but cluster map will be reused from nominal run, as we only need
2272 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
2273 it can't be reused because it has to start with 0 index for each reported run. */
2274 glyph_run
= regular
->run
;
2275 glyph_run
.glyphCount
= run
->glyphcount
;
2277 /* fixup glyph data arrays */
2278 glyph_run
.glyphIndices
+= start_glyph
;
2279 glyph_run
.glyphAdvances
+= start_glyph
;
2280 glyph_run
.glyphOffsets
+= start_glyph
;
2283 descr
= regular
->descr
;
2284 descr
.stringLength
= run
->length
;
2285 descr
.string
+= run
->start
;
2286 descr
.clusterMap
= run
->clustermap
;
2287 descr
.textPosition
+= run
->start
;
2289 /* return value is ignored */
2290 IDWriteTextRenderer_DrawGlyphRun(renderer
,
2292 run
->origin_x
+ origin_x
,
2293 run
->origin_y
+ origin_y
,
2294 DWRITE_MEASURING_MODE_NATURAL
,
2300 /* 2. Inline objects */
2301 LIST_FOR_EACH_ENTRY(inlineobject
, &This
->inlineobjects
, struct layout_effective_inline
, entry
) {
2302 IDWriteTextRenderer_DrawInlineObject(renderer
,
2304 inlineobject
->origin_x
,
2305 inlineobject
->origin_y
,
2306 inlineobject
->object
,
2307 inlineobject
->is_sideways
,
2308 inlineobject
->is_rtl
,
2312 /* TODO: 3. Underlines */
2314 /* 4. Strikethrough */
2315 LIST_FOR_EACH_ENTRY(s
, &This
->strikethrough
, struct layout_strikethrough
, entry
) {
2316 IDWriteTextRenderer_DrawStrikethrough(renderer
,
2321 s
->run
->run
->effect
);
2327 static HRESULT WINAPI
dwritetextlayout_GetLineMetrics(IDWriteTextLayout2
*iface
,
2328 DWRITE_LINE_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
2330 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2333 TRACE("(%p)->(%p %u %p)\n", This
, metrics
, max_count
, count
);
2335 hr
= layout_compute_effective_runs(This
);
2340 memcpy(metrics
, This
->lines
, sizeof(DWRITE_LINE_METRICS
)*min(max_count
, This
->line_count
));
2342 *count
= This
->line_count
;
2343 return max_count
>= This
->line_count
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
2346 static HRESULT WINAPI
dwritetextlayout_GetMetrics(IDWriteTextLayout2
*iface
, DWRITE_TEXT_METRICS
*metrics
)
2348 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2349 DWRITE_TEXT_METRICS1 metrics1
;
2352 TRACE("(%p)->(%p)\n", This
, metrics
);
2354 hr
= IDWriteTextLayout2_GetMetrics(iface
, &metrics1
);
2356 memcpy(metrics
, &metrics1
, sizeof(*metrics
));
2361 static HRESULT WINAPI
dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout2
*iface
, DWRITE_OVERHANG_METRICS
*overhangs
)
2363 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2364 FIXME("(%p)->(%p): stub\n", This
, overhangs
);
2368 static HRESULT WINAPI
dwritetextlayout_GetClusterMetrics(IDWriteTextLayout2
*iface
,
2369 DWRITE_CLUSTER_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
2371 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2374 TRACE("(%p)->(%p %u %p)\n", This
, metrics
, max_count
, count
);
2376 hr
= layout_compute(This
);
2381 memcpy(metrics
, This
->clustermetrics
, sizeof(DWRITE_CLUSTER_METRICS
)*min(max_count
, This
->cluster_count
));
2383 *count
= This
->cluster_count
;
2384 return max_count
>= This
->cluster_count
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
2387 /* Only to be used with DetermineMinWidth() to find the longest cluster sequence that we don't want to try
2388 too hard to break. */
2389 static inline BOOL
is_terminal_cluster(struct dwrite_textlayout
*layout
, UINT32 index
)
2391 if (layout
->clustermetrics
[index
].isWhitespace
|| layout
->clustermetrics
[index
].isNewline
||
2392 (index
== layout
->cluster_count
- 1))
2394 /* check next one */
2395 return (index
< layout
->cluster_count
- 1) && layout
->clustermetrics
[index
+1].isWhitespace
;
2398 static HRESULT WINAPI
dwritetextlayout_DetermineMinWidth(IDWriteTextLayout2
*iface
, FLOAT
* min_width
)
2400 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2405 TRACE("(%p)->(%p)\n", This
, min_width
);
2408 return E_INVALIDARG
;
2410 if (!(This
->recompute
& RECOMPUTE_MINIMAL_WIDTH
))
2414 hr
= layout_compute(This
);
2418 for (i
= 0; i
< This
->cluster_count
;) {
2419 if (is_terminal_cluster(This
, i
)) {
2420 width
= This
->clustermetrics
[i
].width
;
2425 while (!is_terminal_cluster(This
, i
)) {
2426 width
+= This
->clustermetrics
[i
].width
;
2429 /* count last one too */
2430 width
+= This
->clustermetrics
[i
].width
;
2433 if (width
> This
->minwidth
)
2434 This
->minwidth
= width
;
2436 This
->recompute
&= ~RECOMPUTE_MINIMAL_WIDTH
;
2439 *min_width
= This
->minwidth
;
2443 static HRESULT WINAPI
dwritetextlayout_HitTestPoint(IDWriteTextLayout2
*iface
,
2444 FLOAT pointX
, FLOAT pointY
, BOOL
* is_trailinghit
, BOOL
* is_inside
, DWRITE_HIT_TEST_METRICS
*metrics
)
2446 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2447 FIXME("(%p)->(%f %f %p %p %p): stub\n", This
, pointX
, pointY
, is_trailinghit
, is_inside
, metrics
);
2451 static HRESULT WINAPI
dwritetextlayout_HitTestTextPosition(IDWriteTextLayout2
*iface
,
2452 UINT32 textPosition
, BOOL is_trailinghit
, FLOAT
* pointX
, FLOAT
* pointY
, DWRITE_HIT_TEST_METRICS
*metrics
)
2454 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2455 FIXME("(%p)->(%u %d %p %p %p): stub\n", This
, textPosition
, is_trailinghit
, pointX
, pointY
, metrics
);
2459 static HRESULT WINAPI
dwritetextlayout_HitTestTextRange(IDWriteTextLayout2
*iface
,
2460 UINT32 textPosition
, UINT32 textLength
, FLOAT originX
, FLOAT originY
,
2461 DWRITE_HIT_TEST_METRICS
*metrics
, UINT32 max_metricscount
, UINT32
* actual_metricscount
)
2463 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2464 FIXME("(%p)->(%u %u %f %f %p %u %p): stub\n", This
, textPosition
, textLength
, originX
, originY
, metrics
,
2465 max_metricscount
, actual_metricscount
);
2469 static HRESULT WINAPI
dwritetextlayout1_SetPairKerning(IDWriteTextLayout2
*iface
, BOOL is_pairkerning_enabled
,
2470 DWRITE_TEXT_RANGE range
)
2472 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2473 struct layout_range_attr_value value
;
2475 TRACE("(%p)->(%d %s)\n", This
, is_pairkerning_enabled
, debugstr_range(&range
));
2477 value
.range
= range
;
2478 value
.u
.pair_kerning
= !!is_pairkerning_enabled
;
2479 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_PAIR_KERNING
, &value
);
2482 static HRESULT WINAPI
dwritetextlayout1_GetPairKerning(IDWriteTextLayout2
*iface
, UINT32 position
, BOOL
*is_pairkerning_enabled
,
2483 DWRITE_TEXT_RANGE
*r
)
2485 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2486 struct layout_range
*range
;
2488 TRACE("(%p)->(%u %p %p)\n", This
, position
, is_pairkerning_enabled
, r
);
2490 if (position
>= This
->len
)
2493 range
= get_layout_range_by_pos(This
, position
);
2494 *is_pairkerning_enabled
= range
->pair_kerning
;
2496 return return_range(&range
->h
, r
);
2499 static HRESULT WINAPI
dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout2
*iface
, FLOAT leading_spacing
, FLOAT trailing_spacing
,
2500 FLOAT minimum_advance_width
, DWRITE_TEXT_RANGE range
)
2502 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2503 FIXME("(%p)->(%f %f %f %s): stub\n", This
, leading_spacing
, trailing_spacing
, minimum_advance_width
, debugstr_range(&range
));
2507 static HRESULT WINAPI
dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout2
*iface
, UINT32 position
, FLOAT
* leading_spacing
,
2508 FLOAT
* trailing_spacing
, FLOAT
* minimum_advance_width
, DWRITE_TEXT_RANGE
*range
)
2510 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2511 FIXME("(%p)->(%u %p %p %p %p): stub\n", This
, position
, leading_spacing
, trailing_spacing
, minimum_advance_width
, range
);
2515 static HRESULT WINAPI
dwritetextlayout2_GetMetrics(IDWriteTextLayout2
*iface
, DWRITE_TEXT_METRICS1
*metrics
)
2517 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2518 FIXME("(%p)->(%p): stub\n", This
, metrics
);
2522 static HRESULT WINAPI
dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout2
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
2524 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2526 TRACE("(%p)->(%d)\n", This
, orientation
);
2528 if ((UINT32
)orientation
> DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED
)
2529 return E_INVALIDARG
;
2531 This
->format
.vertical_orientation
= orientation
;
2535 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout2
*iface
)
2537 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2538 TRACE("(%p)\n", This
);
2539 return This
->format
.vertical_orientation
;
2542 static HRESULT WINAPI
dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout2
*iface
, BOOL lastline_wrapping_enabled
)
2544 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2545 FIXME("(%p)->(%d): stub\n", This
, lastline_wrapping_enabled
);
2549 static BOOL WINAPI
dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout2
*iface
)
2551 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2552 FIXME("(%p): stub\n", This
);
2556 static HRESULT WINAPI
dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout2
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
2558 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2559 FIXME("(%p)->(%d): stub\n", This
, alignment
);
2563 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout2
*iface
)
2565 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2566 FIXME("(%p): stub\n", This
);
2567 return DWRITE_OPTICAL_ALIGNMENT_NONE
;
2570 static HRESULT WINAPI
dwritetextlayout2_SetFontFallback(IDWriteTextLayout2
*iface
, IDWriteFontFallback
*fallback
)
2572 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2573 TRACE("(%p)->(%p)\n", This
, fallback
);
2574 return set_fontfallback_for_format(&This
->format
, fallback
);
2577 static HRESULT WINAPI
dwritetextlayout2_GetFontFallback(IDWriteTextLayout2
*iface
, IDWriteFontFallback
**fallback
)
2579 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2580 TRACE("(%p)->(%p)\n", This
, fallback
);
2581 return get_fontfallback_from_format(&This
->format
, fallback
);
2584 static const IDWriteTextLayout2Vtbl dwritetextlayoutvtbl
= {
2585 dwritetextlayout_QueryInterface
,
2586 dwritetextlayout_AddRef
,
2587 dwritetextlayout_Release
,
2588 dwritetextlayout_SetTextAlignment
,
2589 dwritetextlayout_SetParagraphAlignment
,
2590 dwritetextlayout_SetWordWrapping
,
2591 dwritetextlayout_SetReadingDirection
,
2592 dwritetextlayout_SetFlowDirection
,
2593 dwritetextlayout_SetIncrementalTabStop
,
2594 dwritetextlayout_SetTrimming
,
2595 dwritetextlayout_SetLineSpacing
,
2596 dwritetextlayout_GetTextAlignment
,
2597 dwritetextlayout_GetParagraphAlignment
,
2598 dwritetextlayout_GetWordWrapping
,
2599 dwritetextlayout_GetReadingDirection
,
2600 dwritetextlayout_GetFlowDirection
,
2601 dwritetextlayout_GetIncrementalTabStop
,
2602 dwritetextlayout_GetTrimming
,
2603 dwritetextlayout_GetLineSpacing
,
2604 dwritetextlayout_GetFontCollection
,
2605 dwritetextlayout_GetFontFamilyNameLength
,
2606 dwritetextlayout_GetFontFamilyName
,
2607 dwritetextlayout_GetFontWeight
,
2608 dwritetextlayout_GetFontStyle
,
2609 dwritetextlayout_GetFontStretch
,
2610 dwritetextlayout_GetFontSize
,
2611 dwritetextlayout_GetLocaleNameLength
,
2612 dwritetextlayout_GetLocaleName
,
2613 dwritetextlayout_SetMaxWidth
,
2614 dwritetextlayout_SetMaxHeight
,
2615 dwritetextlayout_SetFontCollection
,
2616 dwritetextlayout_SetFontFamilyName
,
2617 dwritetextlayout_SetFontWeight
,
2618 dwritetextlayout_SetFontStyle
,
2619 dwritetextlayout_SetFontStretch
,
2620 dwritetextlayout_SetFontSize
,
2621 dwritetextlayout_SetUnderline
,
2622 dwritetextlayout_SetStrikethrough
,
2623 dwritetextlayout_SetDrawingEffect
,
2624 dwritetextlayout_SetInlineObject
,
2625 dwritetextlayout_SetTypography
,
2626 dwritetextlayout_SetLocaleName
,
2627 dwritetextlayout_GetMaxWidth
,
2628 dwritetextlayout_GetMaxHeight
,
2629 dwritetextlayout_layout_GetFontCollection
,
2630 dwritetextlayout_layout_GetFontFamilyNameLength
,
2631 dwritetextlayout_layout_GetFontFamilyName
,
2632 dwritetextlayout_layout_GetFontWeight
,
2633 dwritetextlayout_layout_GetFontStyle
,
2634 dwritetextlayout_layout_GetFontStretch
,
2635 dwritetextlayout_layout_GetFontSize
,
2636 dwritetextlayout_GetUnderline
,
2637 dwritetextlayout_GetStrikethrough
,
2638 dwritetextlayout_GetDrawingEffect
,
2639 dwritetextlayout_GetInlineObject
,
2640 dwritetextlayout_GetTypography
,
2641 dwritetextlayout_layout_GetLocaleNameLength
,
2642 dwritetextlayout_layout_GetLocaleName
,
2643 dwritetextlayout_Draw
,
2644 dwritetextlayout_GetLineMetrics
,
2645 dwritetextlayout_GetMetrics
,
2646 dwritetextlayout_GetOverhangMetrics
,
2647 dwritetextlayout_GetClusterMetrics
,
2648 dwritetextlayout_DetermineMinWidth
,
2649 dwritetextlayout_HitTestPoint
,
2650 dwritetextlayout_HitTestTextPosition
,
2651 dwritetextlayout_HitTestTextRange
,
2652 dwritetextlayout1_SetPairKerning
,
2653 dwritetextlayout1_GetPairKerning
,
2654 dwritetextlayout1_SetCharacterSpacing
,
2655 dwritetextlayout1_GetCharacterSpacing
,
2656 dwritetextlayout2_GetMetrics
,
2657 dwritetextlayout2_SetVerticalGlyphOrientation
,
2658 dwritetextlayout2_GetVerticalGlyphOrientation
,
2659 dwritetextlayout2_SetLastLineWrapping
,
2660 dwritetextlayout2_GetLastLineWrapping
,
2661 dwritetextlayout2_SetOpticalAlignment
,
2662 dwritetextlayout2_GetOpticalAlignment
,
2663 dwritetextlayout2_SetFontFallback
,
2664 dwritetextlayout2_GetFontFallback
2667 static HRESULT WINAPI
dwritetextformat1_layout_QueryInterface(IDWriteTextFormat1
*iface
, REFIID riid
, void **obj
)
2669 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2670 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
2671 return IDWriteTextLayout2_QueryInterface(&This
->IDWriteTextLayout2_iface
, riid
, obj
);
2674 static ULONG WINAPI
dwritetextformat1_layout_AddRef(IDWriteTextFormat1
*iface
)
2676 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2677 return IDWriteTextLayout2_AddRef(&This
->IDWriteTextLayout2_iface
);
2680 static ULONG WINAPI
dwritetextformat1_layout_Release(IDWriteTextFormat1
*iface
)
2682 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2683 return IDWriteTextLayout2_Release(&This
->IDWriteTextLayout2_iface
);
2686 static HRESULT WINAPI
dwritetextformat1_layout_SetTextAlignment(IDWriteTextFormat1
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
2688 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2689 FIXME("(%p)->(%d): stub\n", This
, alignment
);
2693 static HRESULT WINAPI
dwritetextformat1_layout_SetParagraphAlignment(IDWriteTextFormat1
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
2695 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2696 FIXME("(%p)->(%d): stub\n", This
, alignment
);
2700 static HRESULT WINAPI
dwritetextformat1_layout_SetWordWrapping(IDWriteTextFormat1
*iface
, DWRITE_WORD_WRAPPING wrapping
)
2702 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2703 FIXME("(%p)->(%d): stub\n", This
, wrapping
);
2707 static HRESULT WINAPI
dwritetextformat1_layout_SetReadingDirection(IDWriteTextFormat1
*iface
, DWRITE_READING_DIRECTION direction
)
2709 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2710 FIXME("(%p)->(%d): stub\n", This
, direction
);
2714 static HRESULT WINAPI
dwritetextformat1_layout_SetFlowDirection(IDWriteTextFormat1
*iface
, DWRITE_FLOW_DIRECTION direction
)
2716 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2717 FIXME("(%p)->(%d): stub\n", This
, direction
);
2721 static HRESULT WINAPI
dwritetextformat1_layout_SetIncrementalTabStop(IDWriteTextFormat1
*iface
, FLOAT tabstop
)
2723 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2724 FIXME("(%p)->(%f): stub\n", This
, tabstop
);
2728 static HRESULT WINAPI
dwritetextformat1_layout_SetTrimming(IDWriteTextFormat1
*iface
, DWRITE_TRIMMING
const *trimming
,
2729 IDWriteInlineObject
*trimming_sign
)
2731 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2732 FIXME("(%p)->(%p %p): stub\n", This
, trimming
, trimming_sign
);
2736 static HRESULT WINAPI
dwritetextformat1_layout_SetLineSpacing(IDWriteTextFormat1
*iface
, DWRITE_LINE_SPACING_METHOD spacing
,
2737 FLOAT line_spacing
, FLOAT baseline
)
2739 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2740 FIXME("(%p)->(%d %f %f): stub\n", This
, spacing
, line_spacing
, baseline
);
2744 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextformat1_layout_GetTextAlignment(IDWriteTextFormat1
*iface
)
2746 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2747 TRACE("(%p)\n", This
);
2748 return This
->format
.textalignment
;
2751 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextformat1_layout_GetParagraphAlignment(IDWriteTextFormat1
*iface
)
2753 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2754 TRACE("(%p)\n", This
);
2755 return This
->format
.paralign
;
2758 static DWRITE_WORD_WRAPPING WINAPI
dwritetextformat1_layout_GetWordWrapping(IDWriteTextFormat1
*iface
)
2760 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2761 FIXME("(%p): stub\n", This
);
2762 return This
->format
.wrapping
;
2765 static DWRITE_READING_DIRECTION WINAPI
dwritetextformat1_layout_GetReadingDirection(IDWriteTextFormat1
*iface
)
2767 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2768 TRACE("(%p)\n", This
);
2769 return This
->format
.readingdir
;
2772 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextformat1_layout_GetFlowDirection(IDWriteTextFormat1
*iface
)
2774 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2775 TRACE("(%p)\n", This
);
2776 return This
->format
.flow
;
2779 static FLOAT WINAPI
dwritetextformat1_layout_GetIncrementalTabStop(IDWriteTextFormat1
*iface
)
2781 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2782 FIXME("(%p): stub\n", This
);
2786 static HRESULT WINAPI
dwritetextformat1_layout_GetTrimming(IDWriteTextFormat1
*iface
, DWRITE_TRIMMING
*options
,
2787 IDWriteInlineObject
**trimming_sign
)
2789 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2791 TRACE("(%p)->(%p %p)\n", This
, options
, trimming_sign
);
2793 *options
= This
->format
.trimming
;
2794 *trimming_sign
= This
->format
.trimmingsign
;
2796 IDWriteInlineObject_AddRef(*trimming_sign
);
2800 static HRESULT WINAPI
dwritetextformat1_layout_GetLineSpacing(IDWriteTextFormat1
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
2801 FLOAT
*spacing
, FLOAT
*baseline
)
2803 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2805 TRACE("(%p)->(%p %p %p)\n", This
, method
, spacing
, baseline
);
2807 *method
= This
->format
.spacingmethod
;
2808 *spacing
= This
->format
.spacing
;
2809 *baseline
= This
->format
.baseline
;
2813 static HRESULT WINAPI
dwritetextformat1_layout_GetFontCollection(IDWriteTextFormat1
*iface
, IDWriteFontCollection
**collection
)
2815 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2817 TRACE("(%p)->(%p)\n", This
, collection
);
2819 *collection
= This
->format
.collection
;
2821 IDWriteFontCollection_AddRef(*collection
);
2825 static UINT32 WINAPI
dwritetextformat1_layout_GetFontFamilyNameLength(IDWriteTextFormat1
*iface
)
2827 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2828 TRACE("(%p)\n", This
);
2829 return This
->format
.family_len
;
2832 static HRESULT WINAPI
dwritetextformat1_layout_GetFontFamilyName(IDWriteTextFormat1
*iface
, WCHAR
*name
, UINT32 size
)
2834 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2836 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
2838 if (size
<= This
->format
.family_len
) return E_NOT_SUFFICIENT_BUFFER
;
2839 strcpyW(name
, This
->format
.family_name
);
2843 static DWRITE_FONT_WEIGHT WINAPI
dwritetextformat1_layout_GetFontWeight(IDWriteTextFormat1
*iface
)
2845 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2846 TRACE("(%p)\n", This
);
2847 return This
->format
.weight
;
2850 static DWRITE_FONT_STYLE WINAPI
dwritetextformat1_layout_GetFontStyle(IDWriteTextFormat1
*iface
)
2852 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2853 TRACE("(%p)\n", This
);
2854 return This
->format
.style
;
2857 static DWRITE_FONT_STRETCH WINAPI
dwritetextformat1_layout_GetFontStretch(IDWriteTextFormat1
*iface
)
2859 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2860 TRACE("(%p)\n", This
);
2861 return This
->format
.stretch
;
2864 static FLOAT WINAPI
dwritetextformat1_layout_GetFontSize(IDWriteTextFormat1
*iface
)
2866 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2867 TRACE("(%p)\n", This
);
2868 return This
->format
.fontsize
;
2871 static UINT32 WINAPI
dwritetextformat1_layout_GetLocaleNameLength(IDWriteTextFormat1
*iface
)
2873 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2874 TRACE("(%p)\n", This
);
2875 return This
->format
.locale_len
;
2878 static HRESULT WINAPI
dwritetextformat1_layout_GetLocaleName(IDWriteTextFormat1
*iface
, WCHAR
*name
, UINT32 size
)
2880 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2882 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
2884 if (size
<= This
->format
.locale_len
) return E_NOT_SUFFICIENT_BUFFER
;
2885 strcpyW(name
, This
->format
.locale
);
2889 static HRESULT WINAPI
dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat1
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
2891 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2892 FIXME("(%p)->(%d): stub\n", This
, orientation
);
2896 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat1
*iface
)
2898 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2899 FIXME("(%p): stub\n", This
);
2900 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
2903 static HRESULT WINAPI
dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat1
*iface
, BOOL lastline_wrapping_enabled
)
2905 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2906 FIXME("(%p)->(%d): stub\n", This
, lastline_wrapping_enabled
);
2910 static BOOL WINAPI
dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat1
*iface
)
2912 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2913 FIXME("(%p): stub\n", This
);
2917 static HRESULT WINAPI
dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat1
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
2919 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2920 FIXME("(%p)->(%d): stub\n", This
, alignment
);
2924 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat1
*iface
)
2926 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2927 FIXME("(%p): stub\n", This
);
2928 return DWRITE_OPTICAL_ALIGNMENT_NONE
;
2931 static HRESULT WINAPI
dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat1
*iface
, IDWriteFontFallback
*fallback
)
2933 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2934 TRACE("(%p)->(%p)\n", This
, fallback
);
2935 return IDWriteTextLayout2_SetFontFallback(&This
->IDWriteTextLayout2_iface
, fallback
);
2938 static HRESULT WINAPI
dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat1
*iface
, IDWriteFontFallback
**fallback
)
2940 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
2941 TRACE("(%p)->(%p)\n", This
, fallback
);
2942 return IDWriteTextLayout2_GetFontFallback(&This
->IDWriteTextLayout2_iface
, fallback
);
2945 static const IDWriteTextFormat1Vtbl dwritetextformat1_layout_vtbl
= {
2946 dwritetextformat1_layout_QueryInterface
,
2947 dwritetextformat1_layout_AddRef
,
2948 dwritetextformat1_layout_Release
,
2949 dwritetextformat1_layout_SetTextAlignment
,
2950 dwritetextformat1_layout_SetParagraphAlignment
,
2951 dwritetextformat1_layout_SetWordWrapping
,
2952 dwritetextformat1_layout_SetReadingDirection
,
2953 dwritetextformat1_layout_SetFlowDirection
,
2954 dwritetextformat1_layout_SetIncrementalTabStop
,
2955 dwritetextformat1_layout_SetTrimming
,
2956 dwritetextformat1_layout_SetLineSpacing
,
2957 dwritetextformat1_layout_GetTextAlignment
,
2958 dwritetextformat1_layout_GetParagraphAlignment
,
2959 dwritetextformat1_layout_GetWordWrapping
,
2960 dwritetextformat1_layout_GetReadingDirection
,
2961 dwritetextformat1_layout_GetFlowDirection
,
2962 dwritetextformat1_layout_GetIncrementalTabStop
,
2963 dwritetextformat1_layout_GetTrimming
,
2964 dwritetextformat1_layout_GetLineSpacing
,
2965 dwritetextformat1_layout_GetFontCollection
,
2966 dwritetextformat1_layout_GetFontFamilyNameLength
,
2967 dwritetextformat1_layout_GetFontFamilyName
,
2968 dwritetextformat1_layout_GetFontWeight
,
2969 dwritetextformat1_layout_GetFontStyle
,
2970 dwritetextformat1_layout_GetFontStretch
,
2971 dwritetextformat1_layout_GetFontSize
,
2972 dwritetextformat1_layout_GetLocaleNameLength
,
2973 dwritetextformat1_layout_GetLocaleName
,
2974 dwritetextformat1_layout_SetVerticalGlyphOrientation
,
2975 dwritetextformat1_layout_GetVerticalGlyphOrientation
,
2976 dwritetextformat1_layout_SetLastLineWrapping
,
2977 dwritetextformat1_layout_GetLastLineWrapping
,
2978 dwritetextformat1_layout_SetOpticalAlignment
,
2979 dwritetextformat1_layout_GetOpticalAlignment
,
2980 dwritetextformat1_layout_SetFontFallback
,
2981 dwritetextformat1_layout_GetFontFallback
2984 static HRESULT WINAPI
dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink
*iface
,
2985 REFIID riid
, void **obj
)
2987 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSink
) || IsEqualIID(riid
, &IID_IUnknown
)) {
2989 IDWriteTextAnalysisSink_AddRef(iface
);
2994 return E_NOINTERFACE
;
2997 static ULONG WINAPI
dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink
*iface
)
3002 static ULONG WINAPI
dwritetextlayout_sink_Release(IDWriteTextAnalysisSink
*iface
)
3007 static HRESULT WINAPI
dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink
*iface
,
3008 UINT32 position
, UINT32 length
, DWRITE_SCRIPT_ANALYSIS
const* sa
)
3010 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink(iface
);
3011 struct layout_run
*run
;
3013 TRACE("%u %u script=%d\n", position
, length
, sa
->script
);
3015 run
= alloc_layout_run(LAYOUT_RUN_REGULAR
);
3017 return E_OUTOFMEMORY
;
3019 run
->u
.regular
.descr
.string
= &layout
->str
[position
];
3020 run
->u
.regular
.descr
.stringLength
= length
;
3021 run
->u
.regular
.descr
.textPosition
= position
;
3022 run
->u
.regular
.sa
= *sa
;
3023 list_add_tail(&layout
->runs
, &run
->entry
);
3027 static HRESULT WINAPI
dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink
*iface
,
3028 UINT32 position
, UINT32 length
, DWRITE_LINE_BREAKPOINT
const* breakpoints
)
3030 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink(iface
);
3032 if (position
+ length
> layout
->len
)
3035 memcpy(&layout
->nominal_breakpoints
[position
], breakpoints
, length
*sizeof(DWRITE_LINE_BREAKPOINT
));
3039 static HRESULT WINAPI
dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink
*iface
, UINT32 position
,
3040 UINT32 length
, UINT8 explicitLevel
, UINT8 resolvedLevel
)
3042 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink(iface
);
3043 struct layout_run
*cur_run
;
3045 TRACE("%u %u %u %u\n", position
, length
, explicitLevel
, resolvedLevel
);
3047 LIST_FOR_EACH_ENTRY(cur_run
, &layout
->runs
, struct layout_run
, entry
) {
3048 struct regular_layout_run
*cur
= &cur_run
->u
.regular
;
3049 struct layout_run
*run
;
3051 if (cur_run
->kind
== LAYOUT_RUN_INLINE
)
3054 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
3055 if (position
< cur
->descr
.textPosition
|| position
>= cur
->descr
.textPosition
+ cur
->descr
.stringLength
)
3058 /* full hit - just set run level */
3059 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
== length
) {
3060 cur
->run
.bidiLevel
= resolvedLevel
;
3064 /* current run is fully covered, move to next one */
3065 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
< length
) {
3066 cur
->run
.bidiLevel
= resolvedLevel
;
3067 position
+= cur
->descr
.stringLength
;
3068 length
-= cur
->descr
.stringLength
;
3072 /* all fully covered runs are processed at this point, reuse existing run for remaining
3073 reported bidi range and add another run for the rest of original one */
3075 run
= alloc_layout_run(LAYOUT_RUN_REGULAR
);
3077 return E_OUTOFMEMORY
;
3080 run
->u
.regular
.descr
.textPosition
= position
+ length
;
3081 run
->u
.regular
.descr
.stringLength
= cur
->descr
.stringLength
- length
;
3082 run
->u
.regular
.descr
.string
= &layout
->str
[position
+ length
];
3084 /* reduce existing run */
3085 cur
->run
.bidiLevel
= resolvedLevel
;
3086 cur
->descr
.stringLength
-= length
;
3088 list_add_after(&cur_run
->entry
, &run
->entry
);
3095 static HRESULT WINAPI
dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink
*iface
,
3096 UINT32 position
, UINT32 length
, IDWriteNumberSubstitution
* substitution
)
3101 static const IDWriteTextAnalysisSinkVtbl dwritetextlayoutsinkvtbl
= {
3102 dwritetextlayout_sink_QueryInterface
,
3103 dwritetextlayout_sink_AddRef
,
3104 dwritetextlayout_sink_Release
,
3105 dwritetextlayout_sink_SetScriptAnalysis
,
3106 dwritetextlayout_sink_SetLineBreakpoints
,
3107 dwritetextlayout_sink_SetBidiLevel
,
3108 dwritetextlayout_sink_SetNumberSubstitution
3111 static HRESULT WINAPI
dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource
*iface
,
3112 REFIID riid
, void **obj
)
3114 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSource
) ||
3115 IsEqualIID(riid
, &IID_IUnknown
))
3118 IDWriteTextAnalysisSource_AddRef(iface
);
3123 return E_NOINTERFACE
;
3126 static ULONG WINAPI
dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource
*iface
)
3131 static ULONG WINAPI
dwritetextlayout_source_Release(IDWriteTextAnalysisSource
*iface
)
3136 static HRESULT WINAPI
dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource
*iface
,
3137 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
3139 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource(iface
);
3141 TRACE("(%p)->(%u %p %p)\n", layout
, position
, text
, text_len
);
3143 if (position
< layout
->len
) {
3144 *text
= &layout
->str
[position
];
3145 *text_len
= layout
->len
- position
;
3155 static HRESULT WINAPI
dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource
*iface
,
3156 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
3158 FIXME("%u %p %p: stub\n", position
, text
, text_len
);
3162 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource
*iface
)
3164 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource(iface
);
3165 return IDWriteTextLayout2_GetReadingDirection(&layout
->IDWriteTextLayout2_iface
);
3168 static HRESULT WINAPI
dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource
*iface
,
3169 UINT32 position
, UINT32
* text_len
, WCHAR
const** locale
)
3171 FIXME("%u %p %p: stub\n", position
, text_len
, locale
);
3175 static HRESULT WINAPI
dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource
*iface
,
3176 UINT32 position
, UINT32
* text_len
, IDWriteNumberSubstitution
**substitution
)
3178 FIXME("%u %p %p: stub\n", position
, text_len
, substitution
);
3182 static const IDWriteTextAnalysisSourceVtbl dwritetextlayoutsourcevtbl
= {
3183 dwritetextlayout_source_QueryInterface
,
3184 dwritetextlayout_source_AddRef
,
3185 dwritetextlayout_source_Release
,
3186 dwritetextlayout_source_GetTextAtPosition
,
3187 dwritetextlayout_source_GetTextBeforePosition
,
3188 dwritetextlayout_source_GetParagraphReadingDirection
,
3189 dwritetextlayout_source_GetLocaleName
,
3190 dwritetextlayout_source_GetNumberSubstitution
3193 static HRESULT
layout_format_from_textformat(struct dwrite_textlayout
*layout
, IDWriteTextFormat
*format
)
3195 IDWriteTextFormat1
*format1
;
3199 layout
->format
.weight
= IDWriteTextFormat_GetFontWeight(format
);
3200 layout
->format
.style
= IDWriteTextFormat_GetFontStyle(format
);
3201 layout
->format
.stretch
= IDWriteTextFormat_GetFontStretch(format
);
3202 layout
->format
.fontsize
= IDWriteTextFormat_GetFontSize(format
);
3203 layout
->format
.textalignment
= IDWriteTextFormat_GetTextAlignment(format
);
3204 layout
->format
.paralign
= IDWriteTextFormat_GetParagraphAlignment(format
);
3205 layout
->format
.wrapping
= IDWriteTextFormat_GetWordWrapping(format
);
3206 layout
->format
.readingdir
= IDWriteTextFormat_GetReadingDirection(format
);
3207 layout
->format
.flow
= IDWriteTextFormat_GetFlowDirection(format
);
3208 layout
->format
.fallback
= NULL
;
3209 hr
= IDWriteTextFormat_GetLineSpacing(format
, &layout
->format
.spacingmethod
,
3210 &layout
->format
.spacing
, &layout
->format
.baseline
);
3214 hr
= IDWriteTextFormat_GetTrimming(format
, &layout
->format
.trimming
, &layout
->format
.trimmingsign
);
3218 /* locale name and length */
3219 len
= IDWriteTextFormat_GetLocaleNameLength(format
);
3220 layout
->format
.locale
= heap_alloc((len
+1)*sizeof(WCHAR
));
3221 if (!layout
->format
.locale
)
3222 return E_OUTOFMEMORY
;
3224 hr
= IDWriteTextFormat_GetLocaleName(format
, layout
->format
.locale
, len
+1);
3227 layout
->format
.locale_len
= len
;
3229 /* font family name and length */
3230 len
= IDWriteTextFormat_GetFontFamilyNameLength(format
);
3231 layout
->format
.family_name
= heap_alloc((len
+1)*sizeof(WCHAR
));
3232 if (!layout
->format
.family_name
)
3233 return E_OUTOFMEMORY
;
3235 hr
= IDWriteTextFormat_GetFontFamilyName(format
, layout
->format
.family_name
, len
+1);
3238 layout
->format
.family_len
= len
;
3240 hr
= IDWriteTextFormat_QueryInterface(format
, &IID_IDWriteTextFormat1
, (void**)&format1
);
3242 layout
->format
.vertical_orientation
= IDWriteTextFormat1_GetVerticalGlyphOrientation(format1
);
3243 IDWriteTextFormat1_GetFontFallback(format1
, &layout
->format
.fallback
);
3244 IDWriteTextFormat1_Release(format1
);
3247 layout
->format
.vertical_orientation
= DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
3249 return IDWriteTextFormat_GetFontCollection(format
, &layout
->format
.collection
);
3252 static HRESULT
init_textlayout(const WCHAR
*str
, UINT32 len
, IDWriteTextFormat
*format
, FLOAT maxwidth
, FLOAT maxheight
, struct dwrite_textlayout
*layout
)
3254 struct layout_range_header
*range
, *strike
;
3255 DWRITE_TEXT_RANGE r
;
3258 layout
->IDWriteTextLayout2_iface
.lpVtbl
= &dwritetextlayoutvtbl
;
3259 layout
->IDWriteTextFormat1_iface
.lpVtbl
= &dwritetextformat1_layout_vtbl
;
3260 layout
->IDWriteTextAnalysisSink_iface
.lpVtbl
= &dwritetextlayoutsinkvtbl
;
3261 layout
->IDWriteTextAnalysisSource_iface
.lpVtbl
= &dwritetextlayoutsourcevtbl
;
3264 layout
->maxwidth
= maxwidth
;
3265 layout
->maxheight
= maxheight
;
3266 layout
->recompute
= RECOMPUTE_EVERYTHING
;
3267 layout
->nominal_breakpoints
= NULL
;
3268 layout
->actual_breakpoints
= NULL
;
3269 layout
->cluster_count
= 0;
3270 layout
->clustermetrics
= NULL
;
3271 layout
->clusters
= NULL
;
3272 layout
->lines
= NULL
;
3273 layout
->line_count
= 0;
3274 layout
->line_alloc
= 0;
3275 layout
->minwidth
= 0.0;
3276 list_init(&layout
->eruns
);
3277 list_init(&layout
->inlineobjects
);
3278 list_init(&layout
->strikethrough
);
3279 list_init(&layout
->runs
);
3280 list_init(&layout
->ranges
);
3281 list_init(&layout
->strike_ranges
);
3282 memset(&layout
->format
, 0, sizeof(layout
->format
));
3284 layout
->gdicompatible
= FALSE
;
3285 layout
->pixels_per_dip
= 0.0;
3286 layout
->use_gdi_natural
= FALSE
;
3287 memset(&layout
->transform
, 0, sizeof(layout
->transform
));
3289 layout
->str
= heap_strdupnW(str
, len
);
3290 if (len
&& !layout
->str
) {
3295 hr
= layout_format_from_textformat(layout
, format
);
3299 r
.startPosition
= 0;
3301 range
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_REGULAR
);
3302 r
.startPosition
= 0;
3304 strike
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_STRIKETHROUGH
);
3305 if (!range
|| !strike
) {
3306 free_layout_range(range
);
3307 free_layout_range(strike
);
3312 list_add_head(&layout
->ranges
, &range
->entry
);
3313 list_add_head(&layout
->strike_ranges
, &strike
->entry
);
3317 IDWriteTextLayout2_Release(&layout
->IDWriteTextLayout2_iface
);
3321 HRESULT
create_textlayout(const WCHAR
*str
, UINT32 len
, IDWriteTextFormat
*format
, FLOAT maxwidth
, FLOAT maxheight
, IDWriteTextLayout
**ret
)
3323 struct dwrite_textlayout
*layout
;
3328 layout
= heap_alloc(sizeof(struct dwrite_textlayout
));
3329 if (!layout
) return E_OUTOFMEMORY
;
3331 hr
= init_textlayout(str
, len
, format
, maxwidth
, maxheight
, layout
);
3333 *ret
= (IDWriteTextLayout
*)&layout
->IDWriteTextLayout2_iface
;
3338 HRESULT
create_gdicompat_textlayout(const WCHAR
*str
, UINT32 len
, IDWriteTextFormat
*format
, FLOAT maxwidth
, FLOAT maxheight
,
3339 FLOAT pixels_per_dip
, const DWRITE_MATRIX
*transform
, BOOL use_gdi_natural
, IDWriteTextLayout
**ret
)
3341 struct dwrite_textlayout
*layout
;
3346 layout
= heap_alloc(sizeof(struct dwrite_textlayout
));
3347 if (!layout
) return E_OUTOFMEMORY
;
3349 hr
= init_textlayout(str
, len
, format
, maxwidth
, maxheight
, layout
);
3351 /* set gdi-specific properties */
3352 layout
->gdicompatible
= TRUE
;
3353 layout
->pixels_per_dip
= pixels_per_dip
;
3354 layout
->use_gdi_natural
= use_gdi_natural
;
3355 layout
->transform
= transform
? *transform
: identity
;
3357 *ret
= (IDWriteTextLayout
*)&layout
->IDWriteTextLayout2_iface
;
3363 static HRESULT WINAPI
dwritetrimmingsign_QueryInterface(IDWriteInlineObject
*iface
, REFIID riid
, void **obj
)
3365 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
3367 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
3369 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDWriteInlineObject
)) {
3371 IDWriteInlineObject_AddRef(iface
);
3376 return E_NOINTERFACE
;
3380 static ULONG WINAPI
dwritetrimmingsign_AddRef(IDWriteInlineObject
*iface
)
3382 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
3383 ULONG ref
= InterlockedIncrement(&This
->ref
);
3384 TRACE("(%p)->(%d)\n", This
, ref
);
3388 static ULONG WINAPI
dwritetrimmingsign_Release(IDWriteInlineObject
*iface
)
3390 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
3391 ULONG ref
= InterlockedDecrement(&This
->ref
);
3393 TRACE("(%p)->(%d)\n", This
, ref
);
3401 static HRESULT WINAPI
dwritetrimmingsign_Draw(IDWriteInlineObject
*iface
, void *context
, IDWriteTextRenderer
*renderer
,
3402 FLOAT originX
, FLOAT originY
, BOOL is_sideways
, BOOL is_rtl
, IUnknown
*drawing_effect
)
3404 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
3405 FIXME("(%p)->(%p %p %f %f %d %d %p): stub\n", This
, context
, renderer
, originX
, originY
, is_sideways
, is_rtl
, drawing_effect
);
3409 static HRESULT WINAPI
dwritetrimmingsign_GetMetrics(IDWriteInlineObject
*iface
, DWRITE_INLINE_OBJECT_METRICS
*metrics
)
3411 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
3412 FIXME("(%p)->(%p): stub\n", This
, metrics
);
3413 memset(metrics
, 0, sizeof(*metrics
));
3417 static HRESULT WINAPI
dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject
*iface
, DWRITE_OVERHANG_METRICS
*overhangs
)
3419 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
3420 FIXME("(%p)->(%p): stub\n", This
, overhangs
);
3424 static HRESULT WINAPI
dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject
*iface
, DWRITE_BREAK_CONDITION
*before
,
3425 DWRITE_BREAK_CONDITION
*after
)
3427 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
3429 TRACE("(%p)->(%p %p)\n", This
, before
, after
);
3431 *before
= *after
= DWRITE_BREAK_CONDITION_NEUTRAL
;
3435 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl
= {
3436 dwritetrimmingsign_QueryInterface
,
3437 dwritetrimmingsign_AddRef
,
3438 dwritetrimmingsign_Release
,
3439 dwritetrimmingsign_Draw
,
3440 dwritetrimmingsign_GetMetrics
,
3441 dwritetrimmingsign_GetOverhangMetrics
,
3442 dwritetrimmingsign_GetBreakConditions
3445 HRESULT
create_trimmingsign(IDWriteInlineObject
**sign
)
3447 struct dwrite_trimmingsign
*This
;
3451 This
= heap_alloc(sizeof(struct dwrite_trimmingsign
));
3452 if (!This
) return E_OUTOFMEMORY
;
3454 This
->IDWriteInlineObject_iface
.lpVtbl
= &dwritetrimmingsignvtbl
;
3457 *sign
= &This
->IDWriteInlineObject_iface
;
3462 static HRESULT WINAPI
dwritetextformat_QueryInterface(IDWriteTextFormat1
*iface
, REFIID riid
, void **obj
)
3464 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3466 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
3468 if (IsEqualIID(riid
, &IID_IDWriteTextFormat1
) ||
3469 IsEqualIID(riid
, &IID_IDWriteTextFormat
) ||
3470 IsEqualIID(riid
, &IID_IUnknown
))
3473 IDWriteTextFormat1_AddRef(iface
);
3479 return E_NOINTERFACE
;
3482 static ULONG WINAPI
dwritetextformat_AddRef(IDWriteTextFormat1
*iface
)
3484 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3485 ULONG ref
= InterlockedIncrement(&This
->ref
);
3486 TRACE("(%p)->(%d)\n", This
, ref
);
3490 static ULONG WINAPI
dwritetextformat_Release(IDWriteTextFormat1
*iface
)
3492 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3493 ULONG ref
= InterlockedDecrement(&This
->ref
);
3495 TRACE("(%p)->(%d)\n", This
, ref
);
3499 release_format_data(&This
->format
);
3506 static HRESULT WINAPI
dwritetextformat_SetTextAlignment(IDWriteTextFormat1
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
3508 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3509 TRACE("(%p)->(%d)\n", This
, alignment
);
3510 This
->format
.textalignment
= alignment
;
3514 static HRESULT WINAPI
dwritetextformat_SetParagraphAlignment(IDWriteTextFormat1
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
3516 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3517 TRACE("(%p)->(%d)\n", This
, alignment
);
3518 This
->format
.paralign
= alignment
;
3522 static HRESULT WINAPI
dwritetextformat_SetWordWrapping(IDWriteTextFormat1
*iface
, DWRITE_WORD_WRAPPING wrapping
)
3524 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3525 TRACE("(%p)->(%d)\n", This
, wrapping
);
3526 This
->format
.wrapping
= wrapping
;
3530 static HRESULT WINAPI
dwritetextformat_SetReadingDirection(IDWriteTextFormat1
*iface
, DWRITE_READING_DIRECTION direction
)
3532 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3533 TRACE("(%p)->(%d)\n", This
, direction
);
3534 This
->format
.readingdir
= direction
;
3538 static HRESULT WINAPI
dwritetextformat_SetFlowDirection(IDWriteTextFormat1
*iface
, DWRITE_FLOW_DIRECTION direction
)
3540 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3541 TRACE("(%p)->(%d)\n", This
, direction
);
3542 This
->format
.flow
= direction
;
3546 static HRESULT WINAPI
dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat1
*iface
, FLOAT tabstop
)
3548 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3549 FIXME("(%p)->(%f): stub\n", This
, tabstop
);
3553 static HRESULT WINAPI
dwritetextformat_SetTrimming(IDWriteTextFormat1
*iface
, DWRITE_TRIMMING
const *trimming
,
3554 IDWriteInlineObject
*trimming_sign
)
3556 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3557 TRACE("(%p)->(%p %p)\n", This
, trimming
, trimming_sign
);
3559 This
->format
.trimming
= *trimming
;
3560 if (This
->format
.trimmingsign
)
3561 IDWriteInlineObject_Release(This
->format
.trimmingsign
);
3562 This
->format
.trimmingsign
= trimming_sign
;
3563 if (This
->format
.trimmingsign
)
3564 IDWriteInlineObject_AddRef(This
->format
.trimmingsign
);
3568 static HRESULT WINAPI
dwritetextformat_SetLineSpacing(IDWriteTextFormat1
*iface
, DWRITE_LINE_SPACING_METHOD method
,
3569 FLOAT spacing
, FLOAT baseline
)
3571 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3572 TRACE("(%p)->(%d %f %f)\n", This
, method
, spacing
, baseline
);
3573 This
->format
.spacingmethod
= method
;
3574 This
->format
.spacing
= spacing
;
3575 This
->format
.baseline
= baseline
;
3579 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextformat_GetTextAlignment(IDWriteTextFormat1
*iface
)
3581 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3582 TRACE("(%p)\n", This
);
3583 return This
->format
.textalignment
;
3586 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextformat_GetParagraphAlignment(IDWriteTextFormat1
*iface
)
3588 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3589 TRACE("(%p)\n", This
);
3590 return This
->format
.paralign
;
3593 static DWRITE_WORD_WRAPPING WINAPI
dwritetextformat_GetWordWrapping(IDWriteTextFormat1
*iface
)
3595 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3596 TRACE("(%p)\n", This
);
3597 return This
->format
.wrapping
;
3600 static DWRITE_READING_DIRECTION WINAPI
dwritetextformat_GetReadingDirection(IDWriteTextFormat1
*iface
)
3602 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3603 TRACE("(%p)\n", This
);
3604 return This
->format
.readingdir
;
3607 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextformat_GetFlowDirection(IDWriteTextFormat1
*iface
)
3609 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3610 TRACE("(%p)\n", This
);
3611 return This
->format
.flow
;
3614 static FLOAT WINAPI
dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat1
*iface
)
3616 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3617 FIXME("(%p): stub\n", This
);
3621 static HRESULT WINAPI
dwritetextformat_GetTrimming(IDWriteTextFormat1
*iface
, DWRITE_TRIMMING
*options
,
3622 IDWriteInlineObject
**trimming_sign
)
3624 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3625 TRACE("(%p)->(%p %p)\n", This
, options
, trimming_sign
);
3627 *options
= This
->format
.trimming
;
3628 if ((*trimming_sign
= This
->format
.trimmingsign
))
3629 IDWriteInlineObject_AddRef(*trimming_sign
);
3634 static HRESULT WINAPI
dwritetextformat_GetLineSpacing(IDWriteTextFormat1
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
3635 FLOAT
*spacing
, FLOAT
*baseline
)
3637 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3638 TRACE("(%p)->(%p %p %p)\n", This
, method
, spacing
, baseline
);
3640 *method
= This
->format
.spacingmethod
;
3641 *spacing
= This
->format
.spacing
;
3642 *baseline
= This
->format
.baseline
;
3646 static HRESULT WINAPI
dwritetextformat_GetFontCollection(IDWriteTextFormat1
*iface
, IDWriteFontCollection
**collection
)
3648 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3650 TRACE("(%p)->(%p)\n", This
, collection
);
3652 *collection
= This
->format
.collection
;
3653 IDWriteFontCollection_AddRef(*collection
);
3658 static UINT32 WINAPI
dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat1
*iface
)
3660 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3661 TRACE("(%p)\n", This
);
3662 return This
->format
.family_len
;
3665 static HRESULT WINAPI
dwritetextformat_GetFontFamilyName(IDWriteTextFormat1
*iface
, WCHAR
*name
, UINT32 size
)
3667 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3669 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
3671 if (size
<= This
->format
.family_len
) return E_NOT_SUFFICIENT_BUFFER
;
3672 strcpyW(name
, This
->format
.family_name
);
3676 static DWRITE_FONT_WEIGHT WINAPI
dwritetextformat_GetFontWeight(IDWriteTextFormat1
*iface
)
3678 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3679 TRACE("(%p)\n", This
);
3680 return This
->format
.weight
;
3683 static DWRITE_FONT_STYLE WINAPI
dwritetextformat_GetFontStyle(IDWriteTextFormat1
*iface
)
3685 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3686 TRACE("(%p)\n", This
);
3687 return This
->format
.style
;
3690 static DWRITE_FONT_STRETCH WINAPI
dwritetextformat_GetFontStretch(IDWriteTextFormat1
*iface
)
3692 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3693 TRACE("(%p)\n", This
);
3694 return This
->format
.stretch
;
3697 static FLOAT WINAPI
dwritetextformat_GetFontSize(IDWriteTextFormat1
*iface
)
3699 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3700 TRACE("(%p)\n", This
);
3701 return This
->format
.fontsize
;
3704 static UINT32 WINAPI
dwritetextformat_GetLocaleNameLength(IDWriteTextFormat1
*iface
)
3706 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3707 TRACE("(%p)\n", This
);
3708 return This
->format
.locale_len
;
3711 static HRESULT WINAPI
dwritetextformat_GetLocaleName(IDWriteTextFormat1
*iface
, WCHAR
*name
, UINT32 size
)
3713 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3715 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
3717 if (size
<= This
->format
.locale_len
) return E_NOT_SUFFICIENT_BUFFER
;
3718 strcpyW(name
, This
->format
.locale
);
3722 static HRESULT WINAPI
dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat1
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
3724 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3726 TRACE("(%p)->(%d)\n", This
, orientation
);
3728 if ((UINT32
)orientation
> DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED
)
3729 return E_INVALIDARG
;
3731 This
->format
.vertical_orientation
= orientation
;
3735 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat1
*iface
)
3737 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3738 TRACE("(%p)\n", This
);
3739 return This
->format
.vertical_orientation
;
3742 static HRESULT WINAPI
dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat1
*iface
, BOOL lastline_wrapping_enabled
)
3744 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3745 FIXME("(%p)->(%d): stub\n", This
, lastline_wrapping_enabled
);
3749 static BOOL WINAPI
dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat1
*iface
)
3751 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3752 FIXME("(%p): stub\n", This
);
3756 static HRESULT WINAPI
dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat1
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
3758 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3759 FIXME("(%p)->(%d): stub\n", This
, alignment
);
3763 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat1
*iface
)
3765 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3766 FIXME("(%p): stub\n", This
);
3767 return DWRITE_OPTICAL_ALIGNMENT_NONE
;
3770 static HRESULT WINAPI
dwritetextformat1_SetFontFallback(IDWriteTextFormat1
*iface
, IDWriteFontFallback
*fallback
)
3772 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3773 TRACE("(%p)->(%p)\n", This
, fallback
);
3774 return set_fontfallback_for_format(&This
->format
, fallback
);
3777 static HRESULT WINAPI
dwritetextformat1_GetFontFallback(IDWriteTextFormat1
*iface
, IDWriteFontFallback
**fallback
)
3779 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
3780 TRACE("(%p)->(%p)\n", This
, fallback
);
3781 return get_fontfallback_from_format(&This
->format
, fallback
);
3784 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl
= {
3785 dwritetextformat_QueryInterface
,
3786 dwritetextformat_AddRef
,
3787 dwritetextformat_Release
,
3788 dwritetextformat_SetTextAlignment
,
3789 dwritetextformat_SetParagraphAlignment
,
3790 dwritetextformat_SetWordWrapping
,
3791 dwritetextformat_SetReadingDirection
,
3792 dwritetextformat_SetFlowDirection
,
3793 dwritetextformat_SetIncrementalTabStop
,
3794 dwritetextformat_SetTrimming
,
3795 dwritetextformat_SetLineSpacing
,
3796 dwritetextformat_GetTextAlignment
,
3797 dwritetextformat_GetParagraphAlignment
,
3798 dwritetextformat_GetWordWrapping
,
3799 dwritetextformat_GetReadingDirection
,
3800 dwritetextformat_GetFlowDirection
,
3801 dwritetextformat_GetIncrementalTabStop
,
3802 dwritetextformat_GetTrimming
,
3803 dwritetextformat_GetLineSpacing
,
3804 dwritetextformat_GetFontCollection
,
3805 dwritetextformat_GetFontFamilyNameLength
,
3806 dwritetextformat_GetFontFamilyName
,
3807 dwritetextformat_GetFontWeight
,
3808 dwritetextformat_GetFontStyle
,
3809 dwritetextformat_GetFontStretch
,
3810 dwritetextformat_GetFontSize
,
3811 dwritetextformat_GetLocaleNameLength
,
3812 dwritetextformat_GetLocaleName
,
3813 dwritetextformat1_SetVerticalGlyphOrientation
,
3814 dwritetextformat1_GetVerticalGlyphOrientation
,
3815 dwritetextformat1_SetLastLineWrapping
,
3816 dwritetextformat1_GetLastLineWrapping
,
3817 dwritetextformat1_SetOpticalAlignment
,
3818 dwritetextformat1_GetOpticalAlignment
,
3819 dwritetextformat1_SetFontFallback
,
3820 dwritetextformat1_GetFontFallback
3823 HRESULT
create_textformat(const WCHAR
*family_name
, IDWriteFontCollection
*collection
, DWRITE_FONT_WEIGHT weight
, DWRITE_FONT_STYLE style
,
3824 DWRITE_FONT_STRETCH stretch
, FLOAT size
, const WCHAR
*locale
, IDWriteTextFormat
**format
)
3826 struct dwrite_textformat
*This
;
3830 This
= heap_alloc(sizeof(struct dwrite_textformat
));
3831 if (!This
) return E_OUTOFMEMORY
;
3833 This
->IDWriteTextFormat1_iface
.lpVtbl
= &dwritetextformatvtbl
;
3835 This
->format
.family_name
= heap_strdupW(family_name
);
3836 This
->format
.family_len
= strlenW(family_name
);
3837 This
->format
.locale
= heap_strdupW(locale
);
3838 This
->format
.locale_len
= strlenW(locale
);
3839 This
->format
.weight
= weight
;
3840 This
->format
.style
= style
;
3841 This
->format
.fontsize
= size
;
3842 This
->format
.stretch
= stretch
;
3843 This
->format
.textalignment
= DWRITE_TEXT_ALIGNMENT_LEADING
;
3844 This
->format
.paralign
= DWRITE_PARAGRAPH_ALIGNMENT_NEAR
;
3845 This
->format
.wrapping
= DWRITE_WORD_WRAPPING_WRAP
;
3846 This
->format
.readingdir
= DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
;
3847 This
->format
.flow
= DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM
;
3848 This
->format
.spacingmethod
= DWRITE_LINE_SPACING_METHOD_DEFAULT
;
3849 This
->format
.vertical_orientation
= DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
3850 This
->format
.spacing
= 0.0;
3851 This
->format
.baseline
= 0.0;
3852 This
->format
.trimming
.granularity
= DWRITE_TRIMMING_GRANULARITY_NONE
;
3853 This
->format
.trimming
.delimiter
= 0;
3854 This
->format
.trimming
.delimiterCount
= 0;
3855 This
->format
.trimmingsign
= NULL
;
3856 This
->format
.collection
= collection
;
3857 This
->format
.fallback
= NULL
;
3858 IDWriteFontCollection_AddRef(collection
);
3860 *format
= (IDWriteTextFormat
*)&This
->IDWriteTextFormat1_iface
;
3865 static HRESULT WINAPI
dwritetypography_QueryInterface(IDWriteTypography
*iface
, REFIID riid
, void **obj
)
3867 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
3869 TRACE("(%p)->(%s %p)\n", typography
, debugstr_guid(riid
), obj
);
3871 if (IsEqualIID(riid
, &IID_IDWriteTypography
) || IsEqualIID(riid
, &IID_IUnknown
)) {
3873 IDWriteTypography_AddRef(iface
);
3879 return E_NOINTERFACE
;
3882 static ULONG WINAPI
dwritetypography_AddRef(IDWriteTypography
*iface
)
3884 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
3885 ULONG ref
= InterlockedIncrement(&typography
->ref
);
3886 TRACE("(%p)->(%d)\n", typography
, ref
);
3890 static ULONG WINAPI
dwritetypography_Release(IDWriteTypography
*iface
)
3892 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
3893 ULONG ref
= InterlockedDecrement(&typography
->ref
);
3895 TRACE("(%p)->(%d)\n", typography
, ref
);
3898 heap_free(typography
->features
);
3899 heap_free(typography
);
3905 static HRESULT WINAPI
dwritetypography_AddFontFeature(IDWriteTypography
*iface
, DWRITE_FONT_FEATURE feature
)
3907 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
3909 TRACE("(%p)->(%x %u)\n", typography
, feature
.nameTag
, feature
.parameter
);
3911 if (typography
->count
== typography
->allocated
) {
3912 DWRITE_FONT_FEATURE
*ptr
= heap_realloc(typography
->features
, 2*typography
->allocated
*sizeof(DWRITE_FONT_FEATURE
));
3914 return E_OUTOFMEMORY
;
3916 typography
->features
= ptr
;
3917 typography
->allocated
*= 2;
3920 typography
->features
[typography
->count
++] = feature
;
3924 static UINT32 WINAPI
dwritetypography_GetFontFeatureCount(IDWriteTypography
*iface
)
3926 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
3927 TRACE("(%p)\n", typography
);
3928 return typography
->count
;
3931 static HRESULT WINAPI
dwritetypography_GetFontFeature(IDWriteTypography
*iface
, UINT32 index
, DWRITE_FONT_FEATURE
*feature
)
3933 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
3935 TRACE("(%p)->(%u %p)\n", typography
, index
, feature
);
3937 if (index
>= typography
->count
)
3938 return E_INVALIDARG
;
3940 *feature
= typography
->features
[index
];
3944 static const IDWriteTypographyVtbl dwritetypographyvtbl
= {
3945 dwritetypography_QueryInterface
,
3946 dwritetypography_AddRef
,
3947 dwritetypography_Release
,
3948 dwritetypography_AddFontFeature
,
3949 dwritetypography_GetFontFeatureCount
,
3950 dwritetypography_GetFontFeature
3953 HRESULT
create_typography(IDWriteTypography
**ret
)
3955 struct dwrite_typography
*typography
;
3959 typography
= heap_alloc(sizeof(*typography
));
3961 return E_OUTOFMEMORY
;
3963 typography
->IDWriteTypography_iface
.lpVtbl
= &dwritetypographyvtbl
;
3964 typography
->ref
= 1;
3965 typography
->allocated
= 2;
3966 typography
->count
= 0;
3968 typography
->features
= heap_alloc(typography
->allocated
*sizeof(DWRITE_FONT_FEATURE
));
3969 if (!typography
->features
) {
3970 heap_free(typography
);
3971 return E_OUTOFMEMORY
;
3974 *ret
= &typography
->IDWriteTypography_iface
;