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
29 #include "dwrite_private.h"
31 #include "wine/list.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(dwrite
);
35 struct dwrite_textformat_data
{
41 DWRITE_FONT_WEIGHT weight
;
42 DWRITE_FONT_STYLE style
;
43 DWRITE_FONT_STRETCH stretch
;
45 DWRITE_PARAGRAPH_ALIGNMENT paralign
;
46 DWRITE_READING_DIRECTION readingdir
;
47 DWRITE_WORD_WRAPPING wrapping
;
48 DWRITE_TEXT_ALIGNMENT textalignment
;
49 DWRITE_FLOW_DIRECTION flow
;
50 DWRITE_LINE_SPACING_METHOD spacingmethod
;
51 DWRITE_VERTICAL_GLYPH_ORIENTATION vertical_orientation
;
57 DWRITE_TRIMMING trimming
;
58 IDWriteInlineObject
*trimmingsign
;
60 IDWriteFontCollection
*collection
;
61 IDWriteFontFallback
*fallback
;
64 enum layout_range_attr_kind
{
65 LAYOUT_RANGE_ATTR_WEIGHT
,
66 LAYOUT_RANGE_ATTR_STYLE
,
67 LAYOUT_RANGE_ATTR_STRETCH
,
68 LAYOUT_RANGE_ATTR_FONTSIZE
,
69 LAYOUT_RANGE_ATTR_EFFECT
,
70 LAYOUT_RANGE_ATTR_INLINE
,
71 LAYOUT_RANGE_ATTR_UNDERLINE
,
72 LAYOUT_RANGE_ATTR_STRIKETHROUGH
,
73 LAYOUT_RANGE_ATTR_PAIR_KERNING
,
74 LAYOUT_RANGE_ATTR_FONTCOLL
,
75 LAYOUT_RANGE_ATTR_LOCALE
,
76 LAYOUT_RANGE_ATTR_FONTFAMILY
,
77 LAYOUT_RANGE_ATTR_SPACING
80 struct layout_range_attr_value
{
81 DWRITE_TEXT_RANGE range
;
83 DWRITE_FONT_WEIGHT weight
;
84 DWRITE_FONT_STYLE style
;
85 DWRITE_FONT_STRETCH stretch
;
87 IDWriteInlineObject
*object
;
92 IDWriteFontCollection
*collection
;
94 const WCHAR
*fontfamily
;
95 FLOAT spacing
[3]; /* in arguments order - leading, trailing, advance */
99 enum layout_range_kind
{
100 LAYOUT_RANGE_REGULAR
,
101 LAYOUT_RANGE_STRIKETHROUGH
,
106 struct layout_range_header
{
108 enum layout_range_kind kind
;
109 DWRITE_TEXT_RANGE range
;
112 struct layout_range
{
113 struct layout_range_header h
;
114 DWRITE_FONT_WEIGHT weight
;
115 DWRITE_FONT_STYLE style
;
117 DWRITE_FONT_STRETCH stretch
;
118 IDWriteInlineObject
*object
;
121 IDWriteFontCollection
*collection
;
122 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
126 struct layout_range_bool
{
127 struct layout_range_header h
;
131 struct layout_range_effect
{
132 struct layout_range_header h
;
136 struct layout_range_spacing
{
137 struct layout_range_header h
;
143 enum layout_run_kind
{
148 struct inline_object_run
{
149 IDWriteInlineObject
*object
;
153 struct regular_layout_run
{
154 DWRITE_GLYPH_RUN_DESCRIPTION descr
;
155 DWRITE_GLYPH_RUN run
;
156 DWRITE_SCRIPT_ANALYSIS sa
;
160 DWRITE_GLYPH_OFFSET
*offsets
;
161 /* this is actual glyph count after shaping, it's not necessary the same as reported to Draw() */
167 enum layout_run_kind kind
;
169 struct inline_object_run object
;
170 struct regular_layout_run regular
;
176 struct layout_effective_run
{
178 const struct layout_run
*run
; /* nominal run this one is based on */
179 UINT32 start
; /* relative text position, 0 means first text position of a nominal run */
180 UINT32 length
; /* length in codepoints that this run covers */
181 UINT32 glyphcount
; /* total glyph count in this run */
182 FLOAT origin_x
; /* baseline X position */
183 FLOAT origin_y
; /* baseline Y position */
184 FLOAT align_dx
; /* adjustment from text alignment */
185 FLOAT width
; /* run width */
186 UINT16
*clustermap
; /* effective clustermap, allocated separately, is not reused from nominal map */
190 struct layout_effective_inline
{
192 IDWriteInlineObject
*object
;
203 struct layout_strikethrough
{
205 const struct layout_effective_run
*run
;
206 DWRITE_STRIKETHROUGH s
;
209 struct layout_cluster
{
210 const struct layout_run
*run
; /* link to nominal run this cluster belongs to */
211 UINT32 position
; /* relative to run, first cluster has 0 position */
214 enum layout_recompute_mask
{
215 RECOMPUTE_NOMINAL_RUNS
= 1 << 0,
216 RECOMPUTE_MINIMAL_WIDTH
= 1 << 1,
217 RECOMPUTE_EFFECTIVE_RUNS
= 1 << 2,
218 RECOMPUTE_EVERYTHING
= 0xffff
221 struct dwrite_textlayout
{
222 IDWriteTextLayout2 IDWriteTextLayout2_iface
;
223 IDWriteTextFormat1 IDWriteTextFormat1_iface
;
224 IDWriteTextAnalysisSink IDWriteTextAnalysisSink_iface
;
225 IDWriteTextAnalysisSource IDWriteTextAnalysisSource_iface
;
230 struct dwrite_textformat_data format
;
231 struct list strike_ranges
;
236 /* lists ready to use by Draw() */
238 struct list inlineobjects
;
239 struct list strikethrough
;
242 DWRITE_LINE_BREAKPOINT
*nominal_breakpoints
;
243 DWRITE_LINE_BREAKPOINT
*actual_breakpoints
;
245 struct layout_cluster
*clusters
;
246 DWRITE_CLUSTER_METRICS
*clustermetrics
;
247 UINT32 cluster_count
;
250 DWRITE_LINE_METRICS
*lines
;
253 DWRITE_TEXT_METRICS1 metrics
;
255 /* gdi-compatible layout specifics */
257 FLOAT pixels_per_dip
;
258 BOOL use_gdi_natural
;
259 DWRITE_MATRIX transform
;
262 struct dwrite_textformat
{
263 IDWriteTextFormat1 IDWriteTextFormat1_iface
;
265 struct dwrite_textformat_data format
;
268 struct dwrite_trimmingsign
{
269 IDWriteInlineObject IDWriteInlineObject_iface
;
272 IDWriteTextLayout
*layout
;
275 struct dwrite_typography
{
276 IDWriteTypography IDWriteTypography_iface
;
279 DWRITE_FONT_FEATURE
*features
;
284 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl
;
286 static void release_format_data(struct dwrite_textformat_data
*data
)
288 if (data
->collection
) IDWriteFontCollection_Release(data
->collection
);
289 if (data
->fallback
) IDWriteFontFallback_Release(data
->fallback
);
290 if (data
->trimmingsign
) IDWriteInlineObject_Release(data
->trimmingsign
);
291 heap_free(data
->family_name
);
292 heap_free(data
->locale
);
295 static inline struct dwrite_textlayout
*impl_from_IDWriteTextLayout2(IDWriteTextLayout2
*iface
)
297 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextLayout2_iface
);
300 static inline struct dwrite_textlayout
*impl_layout_form_IDWriteTextFormat1(IDWriteTextFormat1
*iface
)
302 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextFormat1_iface
);
305 static inline struct dwrite_textlayout
*impl_from_IDWriteTextAnalysisSink(IDWriteTextAnalysisSink
*iface
)
307 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextAnalysisSink_iface
);
310 static inline struct dwrite_textlayout
*impl_from_IDWriteTextAnalysisSource(IDWriteTextAnalysisSource
*iface
)
312 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextAnalysisSource_iface
);
315 static inline struct dwrite_textformat
*impl_from_IDWriteTextFormat1(IDWriteTextFormat1
*iface
)
317 return CONTAINING_RECORD(iface
, struct dwrite_textformat
, IDWriteTextFormat1_iface
);
320 static inline struct dwrite_trimmingsign
*impl_from_IDWriteInlineObject(IDWriteInlineObject
*iface
)
322 return CONTAINING_RECORD(iface
, struct dwrite_trimmingsign
, IDWriteInlineObject_iface
);
325 static inline struct dwrite_typography
*impl_from_IDWriteTypography(IDWriteTypography
*iface
)
327 return CONTAINING_RECORD(iface
, struct dwrite_typography
, IDWriteTypography_iface
);
330 static inline const char *debugstr_run(const struct regular_layout_run
*run
)
332 return wine_dbg_sprintf("[%u,%u)", run
->descr
.textPosition
, run
->descr
.textPosition
+
333 run
->descr
.stringLength
);
336 static inline HRESULT
format_set_textalignment(struct dwrite_textformat_data
*format
, DWRITE_TEXT_ALIGNMENT alignment
,
339 if ((UINT32
)alignment
> DWRITE_TEXT_ALIGNMENT_JUSTIFIED
)
341 if (changed
) *changed
= format
->textalignment
!= alignment
;
342 format
->textalignment
= alignment
;
346 static inline HRESULT
format_set_paralignment(struct dwrite_textformat_data
*format
,
347 DWRITE_PARAGRAPH_ALIGNMENT alignment
, BOOL
*changed
)
349 if ((UINT32
)alignment
> DWRITE_PARAGRAPH_ALIGNMENT_CENTER
)
351 if (changed
) *changed
= format
->paralign
!= alignment
;
352 format
->paralign
= alignment
;
356 static inline HRESULT
format_set_readingdirection(struct dwrite_textformat_data
*format
,
357 DWRITE_READING_DIRECTION direction
, BOOL
*changed
)
359 if ((UINT32
)direction
> DWRITE_READING_DIRECTION_BOTTOM_TO_TOP
)
361 if (changed
) *changed
= format
->readingdir
!= direction
;
362 format
->readingdir
= direction
;
366 static inline HRESULT
format_set_wordwrapping(struct dwrite_textformat_data
*format
,
367 DWRITE_WORD_WRAPPING wrapping
, BOOL
*changed
)
369 if ((UINT32
)wrapping
> DWRITE_WORD_WRAPPING_CHARACTER
)
371 if (changed
) *changed
= format
->wrapping
!= wrapping
;
372 format
->wrapping
= wrapping
;
376 static HRESULT
get_fontfallback_from_format(const struct dwrite_textformat_data
*format
, IDWriteFontFallback
**fallback
)
378 *fallback
= format
->fallback
;
380 IDWriteFontFallback_AddRef(*fallback
);
384 static HRESULT
set_fontfallback_for_format(struct dwrite_textformat_data
*format
, IDWriteFontFallback
*fallback
)
386 if (format
->fallback
)
387 IDWriteFontFallback_Release(format
->fallback
);
388 format
->fallback
= fallback
;
390 IDWriteFontFallback_AddRef(fallback
);
394 static struct layout_run
*alloc_layout_run(enum layout_run_kind kind
)
396 struct layout_run
*ret
;
398 ret
= heap_alloc(sizeof(*ret
));
399 if (!ret
) return NULL
;
401 memset(ret
, 0, sizeof(*ret
));
403 if (kind
== LAYOUT_RUN_REGULAR
) {
404 ret
->u
.regular
.sa
.script
= Script_Unknown
;
405 ret
->u
.regular
.sa
.shapes
= DWRITE_SCRIPT_SHAPES_DEFAULT
;
411 static void free_layout_runs(struct dwrite_textlayout
*layout
)
413 struct layout_run
*cur
, *cur2
;
414 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->runs
, struct layout_run
, entry
) {
415 list_remove(&cur
->entry
);
416 if (cur
->kind
== LAYOUT_RUN_REGULAR
) {
417 if (cur
->u
.regular
.run
.fontFace
)
418 IDWriteFontFace_Release(cur
->u
.regular
.run
.fontFace
);
419 heap_free(cur
->u
.regular
.glyphs
);
420 heap_free(cur
->u
.regular
.clustermap
);
421 heap_free(cur
->u
.regular
.advances
);
422 heap_free(cur
->u
.regular
.offsets
);
428 static void free_layout_eruns(struct dwrite_textlayout
*layout
)
430 struct layout_effective_inline
*in
, *in2
;
431 struct layout_effective_run
*cur
, *cur2
;
432 struct layout_strikethrough
*s
, *s2
;
434 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->eruns
, struct layout_effective_run
, entry
) {
435 list_remove(&cur
->entry
);
436 heap_free(cur
->clustermap
);
440 LIST_FOR_EACH_ENTRY_SAFE(in
, in2
, &layout
->inlineobjects
, struct layout_effective_inline
, entry
) {
441 list_remove(&in
->entry
);
445 LIST_FOR_EACH_ENTRY_SAFE(s
, s2
, &layout
->strikethrough
, struct layout_strikethrough
, entry
) {
446 list_remove(&s
->entry
);
451 /* Used to resolve break condition by forcing stronger condition over weaker. */
452 static inline DWRITE_BREAK_CONDITION
override_break_condition(DWRITE_BREAK_CONDITION existingbreak
, DWRITE_BREAK_CONDITION newbreak
)
454 switch (existingbreak
) {
455 case DWRITE_BREAK_CONDITION_NEUTRAL
:
457 case DWRITE_BREAK_CONDITION_CAN_BREAK
:
458 return newbreak
== DWRITE_BREAK_CONDITION_NEUTRAL
? existingbreak
: newbreak
;
459 /* let's keep stronger conditions as is */
460 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
:
461 case DWRITE_BREAK_CONDITION_MUST_BREAK
:
464 ERR("unknown break condition %d\n", existingbreak
);
467 return existingbreak
;
470 /* This helper should be used to get effective range length, in other words it returns number of text
471 positions from range starting point to the end of the range, limited by layout text length */
472 static inline UINT32
get_clipped_range_length(const struct dwrite_textlayout
*layout
, const struct layout_range
*range
)
474 if (range
->h
.range
.startPosition
+ range
->h
.range
.length
<= layout
->len
)
475 return range
->h
.range
.length
;
476 return layout
->len
- range
->h
.range
.startPosition
;
479 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
480 static HRESULT
layout_update_breakpoints_range(struct dwrite_textlayout
*layout
, const struct layout_range
*cur
)
482 DWRITE_BREAK_CONDITION before
, after
;
486 /* ignore returned conditions if failed */
487 hr
= IDWriteInlineObject_GetBreakConditions(cur
->object
, &before
, &after
);
489 after
= before
= DWRITE_BREAK_CONDITION_NEUTRAL
;
491 if (!layout
->actual_breakpoints
) {
492 layout
->actual_breakpoints
= heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT
)*layout
->len
);
493 if (!layout
->actual_breakpoints
)
494 return E_OUTOFMEMORY
;
495 memcpy(layout
->actual_breakpoints
, layout
->nominal_breakpoints
, sizeof(DWRITE_LINE_BREAKPOINT
)*layout
->len
);
498 length
= get_clipped_range_length(layout
, cur
);
499 for (i
= cur
->h
.range
.startPosition
; i
< length
+ cur
->h
.range
.startPosition
; i
++) {
500 /* for first codepoint check if there's anything before it and update accordingly */
501 if (i
== cur
->h
.range
.startPosition
) {
503 layout
->actual_breakpoints
[i
].breakConditionBefore
= layout
->actual_breakpoints
[i
-1].breakConditionAfter
=
504 override_break_condition(layout
->actual_breakpoints
[i
-1].breakConditionAfter
, before
);
506 layout
->actual_breakpoints
[i
].breakConditionBefore
= before
;
507 layout
->actual_breakpoints
[i
].breakConditionAfter
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
509 /* similar check for last codepoint */
510 else if (i
== cur
->h
.range
.startPosition
+ length
- 1) {
511 if (i
== layout
->len
- 1)
512 layout
->actual_breakpoints
[i
].breakConditionAfter
= after
;
514 layout
->actual_breakpoints
[i
].breakConditionAfter
= layout
->actual_breakpoints
[i
+1].breakConditionBefore
=
515 override_break_condition(layout
->actual_breakpoints
[i
+1].breakConditionBefore
, after
);
516 layout
->actual_breakpoints
[i
].breakConditionBefore
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
518 /* for all positions within a range disable breaks */
520 layout
->actual_breakpoints
[i
].breakConditionBefore
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
521 layout
->actual_breakpoints
[i
].breakConditionAfter
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
524 layout
->actual_breakpoints
[i
].isWhitespace
= FALSE
;
525 layout
->actual_breakpoints
[i
].isSoftHyphen
= FALSE
;
531 static struct layout_range
*get_layout_range_by_pos(struct dwrite_textlayout
*layout
, UINT32 pos
);
533 static inline DWRITE_LINE_BREAKPOINT
get_effective_breakpoint(const struct dwrite_textlayout
*layout
, UINT32 pos
)
535 if (layout
->actual_breakpoints
)
536 return layout
->actual_breakpoints
[pos
];
537 return layout
->nominal_breakpoints
[pos
];
540 static inline void init_cluster_metrics(const struct dwrite_textlayout
*layout
, const struct regular_layout_run
*run
,
541 UINT16 start_glyph
, UINT16 stop_glyph
, UINT32 stop_position
, UINT16 length
, DWRITE_CLUSTER_METRICS
*metrics
)
543 UINT8 breakcondition
;
547 /* For clusters made of control chars we report zero glyphs, and we need zero cluster
548 width as well; advances are already computed at this point and are not necessary zero. */
549 metrics
->width
= 0.0;
550 if (run
->run
.glyphCount
) {
551 for (j
= start_glyph
; j
< stop_glyph
; j
++)
552 metrics
->width
+= run
->run
.glyphAdvances
[j
];
554 metrics
->length
= length
;
556 position
= stop_position
;
557 if (stop_glyph
== run
->glyphcount
)
558 breakcondition
= get_effective_breakpoint(layout
, stop_position
).breakConditionAfter
;
560 breakcondition
= get_effective_breakpoint(layout
, stop_position
).breakConditionBefore
;
561 if (stop_position
) position
= stop_position
- 1;
564 metrics
->canWrapLineAfter
= breakcondition
== DWRITE_BREAK_CONDITION_CAN_BREAK
||
565 breakcondition
== DWRITE_BREAK_CONDITION_MUST_BREAK
;
566 if (metrics
->length
== 1) {
569 GetStringTypeW(CT_CTYPE1
, &layout
->str
[position
], 1, &type
);
570 metrics
->isWhitespace
= !!(type
& C1_SPACE
);
571 metrics
->isNewline
= FALSE
/* FIXME */;
572 metrics
->isSoftHyphen
= layout
->str
[position
] == 0x00ad /* Unicode Soft Hyphen */;
575 metrics
->isWhitespace
= FALSE
;
576 metrics
->isNewline
= FALSE
;
577 metrics
->isSoftHyphen
= FALSE
;
579 metrics
->isRightToLeft
= run
->run
.bidiLevel
& 1;
580 metrics
->padding
= 0;
585 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
586 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
587 Note that there's no need to reallocate anything at this point as we allocate one cluster per
591 static void layout_set_cluster_metrics(struct dwrite_textlayout
*layout
, const struct layout_run
*r
, UINT32
*cluster
)
593 DWRITE_CLUSTER_METRICS
*metrics
= &layout
->clustermetrics
[*cluster
];
594 struct layout_cluster
*c
= &layout
->clusters
[*cluster
];
595 const struct regular_layout_run
*run
= &r
->u
.regular
;
598 for (i
= 0; i
< run
->descr
.stringLength
; i
++) {
599 BOOL end
= i
== run
->descr
.stringLength
- 1;
601 if (run
->descr
.clusterMap
[start
] != run
->descr
.clusterMap
[i
]) {
602 init_cluster_metrics(layout
, run
, run
->descr
.clusterMap
[start
], run
->descr
.clusterMap
[i
], i
,
614 init_cluster_metrics(layout
, run
, run
->descr
.clusterMap
[start
], run
->glyphcount
, i
,
615 i
- start
+ 1, metrics
);
625 static inline FLOAT
get_scaled_font_metric(UINT32 metric
, FLOAT emSize
, const DWRITE_FONT_METRICS
*metrics
)
627 return (FLOAT
)metric
* emSize
/ (FLOAT
)metrics
->designUnitsPerEm
;
630 static HRESULT
layout_compute_runs(struct dwrite_textlayout
*layout
)
632 IDWriteTextAnalyzer
*analyzer
;
633 struct layout_range
*range
;
634 struct layout_run
*r
;
638 free_layout_eruns(layout
);
639 free_layout_runs(layout
);
641 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
642 if (!layout
->clustermetrics
) {
643 layout
->clustermetrics
= heap_alloc(layout
->len
*sizeof(*layout
->clustermetrics
));
644 layout
->clusters
= heap_alloc(layout
->len
*sizeof(*layout
->clusters
));
645 if (!layout
->clustermetrics
|| !layout
->clusters
) {
646 heap_free(layout
->clustermetrics
);
647 heap_free(layout
->clusters
);
648 return E_OUTOFMEMORY
;
651 layout
->cluster_count
= 0;
653 hr
= get_textanalyzer(&analyzer
);
657 LIST_FOR_EACH_ENTRY(range
, &layout
->ranges
, struct layout_range
, h
.entry
) {
658 /* we don't care about ranges that don't contain any text */
659 if (range
->h
.range
.startPosition
>= layout
->len
)
662 /* inline objects override actual text in a range */
664 hr
= layout_update_breakpoints_range(layout
, range
);
668 r
= alloc_layout_run(LAYOUT_RUN_INLINE
);
670 return E_OUTOFMEMORY
;
672 r
->u
.object
.object
= range
->object
;
673 r
->u
.object
.length
= get_clipped_range_length(layout
, range
);
674 list_add_tail(&layout
->runs
, &r
->entry
);
678 /* initial splitting by script */
679 hr
= IDWriteTextAnalyzer_AnalyzeScript(analyzer
, &layout
->IDWriteTextAnalysisSource_iface
,
680 range
->h
.range
.startPosition
, get_clipped_range_length(layout
, range
), &layout
->IDWriteTextAnalysisSink_iface
);
684 /* this splits it further */
685 hr
= IDWriteTextAnalyzer_AnalyzeBidi(analyzer
, &layout
->IDWriteTextAnalysisSource_iface
,
686 range
->h
.range
.startPosition
, get_clipped_range_length(layout
, range
), &layout
->IDWriteTextAnalysisSink_iface
);
692 LIST_FOR_EACH_ENTRY(r
, &layout
->runs
, struct layout_run
, entry
) {
693 DWRITE_SHAPING_GLYPH_PROPERTIES
*glyph_props
= NULL
;
694 DWRITE_SHAPING_TEXT_PROPERTIES
*text_props
= NULL
;
695 struct regular_layout_run
*run
= &r
->u
.regular
;
696 DWRITE_FONT_METRICS fontmetrics
= { 0 };
697 IDWriteFontFamily
*family
;
698 UINT32 index
, max_count
;
702 /* we need to do very little in case of inline objects */
703 if (r
->kind
== LAYOUT_RUN_INLINE
) {
704 DWRITE_CLUSTER_METRICS
*metrics
= &layout
->clustermetrics
[cluster
];
705 struct layout_cluster
*c
= &layout
->clusters
[cluster
];
706 DWRITE_INLINE_OBJECT_METRICS inlinemetrics
;
708 metrics
->width
= 0.0;
709 metrics
->length
= r
->u
.object
.length
;
710 metrics
->canWrapLineAfter
= FALSE
;
711 metrics
->isWhitespace
= FALSE
;
712 metrics
->isNewline
= FALSE
;
713 metrics
->isSoftHyphen
= FALSE
;
714 metrics
->isRightToLeft
= FALSE
;
715 metrics
->padding
= 0;
717 c
->position
= 0; /* there's always one cluster per inline object, so 0 is valid value */
720 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
721 hr
= IDWriteInlineObject_GetMetrics(r
->u
.object
.object
, &inlinemetrics
);
723 memset(&inlinemetrics
, 0, sizeof(inlinemetrics
));
726 metrics
->width
= inlinemetrics
.width
;
727 r
->baseline
= inlinemetrics
.baseline
;
728 r
->height
= inlinemetrics
.height
;
730 /* FIXME: use resolved breakpoints in this case too */
735 range
= get_layout_range_by_pos(layout
, run
->descr
.textPosition
);
737 hr
= IDWriteFontCollection_FindFamilyName(range
->collection
, range
->fontfamily
, &index
, &exists
);
738 if (FAILED(hr
) || !exists
) {
739 WARN("%s: family %s not found in collection %p\n", debugstr_run(run
), debugstr_w(range
->fontfamily
), range
->collection
);
743 hr
= IDWriteFontCollection_GetFontFamily(range
->collection
, index
, &family
);
747 hr
= IDWriteFontFamily_GetFirstMatchingFont(family
, range
->weight
, range
->stretch
, range
->style
, &font
);
748 IDWriteFontFamily_Release(family
);
750 WARN("%s: failed to get a matching font\n", debugstr_run(run
));
754 hr
= IDWriteFont_CreateFontFace(font
, &run
->run
.fontFace
);
755 IDWriteFont_Release(font
);
759 run
->run
.fontEmSize
= range
->fontsize
;
760 run
->descr
.localeName
= range
->locale
;
761 run
->clustermap
= heap_alloc(run
->descr
.stringLength
*sizeof(UINT16
));
763 max_count
= 3*run
->descr
.stringLength
/2 + 16;
764 run
->glyphs
= heap_alloc(max_count
*sizeof(UINT16
));
765 if (!run
->clustermap
|| !run
->glyphs
)
768 text_props
= heap_alloc(run
->descr
.stringLength
*sizeof(DWRITE_SHAPING_TEXT_PROPERTIES
));
769 glyph_props
= heap_alloc(max_count
*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES
));
770 if (!text_props
|| !glyph_props
)
774 hr
= IDWriteTextAnalyzer_GetGlyphs(analyzer
, run
->descr
.string
, run
->descr
.stringLength
,
775 run
->run
.fontFace
, run
->run
.isSideways
, run
->run
.bidiLevel
& 1, &run
->sa
, run
->descr
.localeName
,
776 NULL
/* FIXME */, NULL
, NULL
, 0, max_count
, run
->clustermap
, text_props
, run
->glyphs
, glyph_props
,
778 if (hr
== E_NOT_SUFFICIENT_BUFFER
) {
779 heap_free(run
->glyphs
);
780 heap_free(glyph_props
);
782 max_count
= run
->glyphcount
;
784 run
->glyphs
= heap_alloc(max_count
*sizeof(UINT16
));
785 glyph_props
= heap_alloc(max_count
*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES
));
786 if (!run
->glyphs
|| !glyph_props
)
796 heap_free(text_props
);
797 heap_free(glyph_props
);
798 WARN("%s: shaping failed 0x%08x\n", debugstr_run(run
), hr
);
802 run
->run
.glyphIndices
= run
->glyphs
;
803 run
->descr
.clusterMap
= run
->clustermap
;
805 run
->advances
= heap_alloc(run
->glyphcount
*sizeof(FLOAT
));
806 run
->offsets
= heap_alloc(run
->glyphcount
*sizeof(DWRITE_GLYPH_OFFSET
));
807 if (!run
->advances
|| !run
->offsets
)
810 /* now set advances and offsets */
811 if (layout
->gdicompatible
)
812 hr
= IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer
, run
->descr
.string
, run
->descr
.clusterMap
,
813 text_props
, run
->descr
.stringLength
, run
->run
.glyphIndices
, glyph_props
, run
->glyphcount
,
814 run
->run
.fontFace
, run
->run
.fontEmSize
, layout
->pixels_per_dip
, &layout
->transform
, layout
->use_gdi_natural
,
815 run
->run
.isSideways
, run
->run
.bidiLevel
& 1, &run
->sa
, run
->descr
.localeName
, NULL
, NULL
, 0,
816 run
->advances
, run
->offsets
);
818 hr
= IDWriteTextAnalyzer_GetGlyphPlacements(analyzer
, run
->descr
.string
, run
->descr
.clusterMap
, text_props
,
819 run
->descr
.stringLength
, run
->run
.glyphIndices
, glyph_props
, run
->glyphcount
, run
->run
.fontFace
,
820 run
->run
.fontEmSize
, run
->run
.isSideways
, run
->run
.bidiLevel
& 1, &run
->sa
, run
->descr
.localeName
,
821 NULL
, NULL
, 0, run
->advances
, run
->offsets
);
823 heap_free(text_props
);
824 heap_free(glyph_props
);
826 WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_run(run
), hr
);
828 run
->run
.glyphAdvances
= run
->advances
;
829 run
->run
.glyphOffsets
= run
->offsets
;
831 /* Special treatment of control script, shaping code adds normal glyphs for it,
832 with non-zero advances, and layout code exposes those as zero width clusters,
833 so we have to do it manually. */
834 if (run
->sa
.script
== Script_Common
)
835 run
->run
.glyphCount
= 0;
837 run
->run
.glyphCount
= run
->glyphcount
;
839 /* baseline derived from font metrics */
840 if (layout
->gdicompatible
) {
841 hr
= IDWriteFontFace_GetGdiCompatibleMetrics(run
->run
.fontFace
,
843 layout
->pixels_per_dip
,
847 WARN("failed to get compat metrics, 0x%08x\n", hr
);
850 IDWriteFontFace_GetMetrics(run
->run
.fontFace
, &fontmetrics
);
852 r
->baseline
= get_scaled_font_metric(fontmetrics
.ascent
, run
->run
.fontEmSize
, &fontmetrics
);
853 r
->height
= get_scaled_font_metric(fontmetrics
.ascent
+ fontmetrics
.descent
, run
->run
.fontEmSize
, &fontmetrics
);
855 layout_set_cluster_metrics(layout
, r
, &cluster
);
860 heap_free(text_props
);
861 heap_free(glyph_props
);
862 heap_free(run
->clustermap
);
863 heap_free(run
->glyphs
);
864 heap_free(run
->advances
);
865 heap_free(run
->offsets
);
866 run
->advances
= NULL
;
868 run
->clustermap
= run
->glyphs
= NULL
;
874 layout
->cluster_count
= cluster
;
876 layout
->clustermetrics
[cluster
-1].canWrapLineAfter
= TRUE
;
879 IDWriteTextAnalyzer_Release(analyzer
);
883 static HRESULT
layout_compute(struct dwrite_textlayout
*layout
)
887 if (!(layout
->recompute
& RECOMPUTE_NOMINAL_RUNS
))
890 /* nominal breakpoints are evaluated only once, because string never changes */
891 if (!layout
->nominal_breakpoints
) {
892 IDWriteTextAnalyzer
*analyzer
;
895 layout
->nominal_breakpoints
= heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT
)*layout
->len
);
896 if (!layout
->nominal_breakpoints
)
897 return E_OUTOFMEMORY
;
899 hr
= get_textanalyzer(&analyzer
);
903 hr
= IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer
, &layout
->IDWriteTextAnalysisSource_iface
,
904 0, layout
->len
, &layout
->IDWriteTextAnalysisSink_iface
);
905 IDWriteTextAnalyzer_Release(analyzer
);
907 if (layout
->actual_breakpoints
) {
908 heap_free(layout
->actual_breakpoints
);
909 layout
->actual_breakpoints
= NULL
;
912 hr
= layout_compute_runs(layout
);
914 if (TRACE_ON(dwrite
)) {
915 struct layout_run
*cur
;
917 LIST_FOR_EACH_ENTRY(cur
, &layout
->runs
, struct layout_run
, entry
) {
918 if (cur
->kind
== LAYOUT_RUN_INLINE
)
919 TRACE("run inline object %p, len %u\n", cur
->u
.object
.object
, cur
->u
.object
.length
);
921 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur
->u
.regular
.descr
.textPosition
, cur
->u
.regular
.descr
.textPosition
+
922 cur
->u
.regular
.descr
.stringLength
-1, cur
->u
.regular
.descr
.stringLength
, cur
->u
.regular
.run
.bidiLevel
);
926 layout
->recompute
&= ~RECOMPUTE_NOMINAL_RUNS
;
930 static inline FLOAT
get_cluster_range_width(struct dwrite_textlayout
*layout
, UINT32 start
, UINT32 end
)
933 for (; start
< end
; start
++)
934 width
+= layout
->clustermetrics
[start
].width
;
938 static struct layout_range_header
*get_layout_range_header_by_pos(struct list
*ranges
, UINT32 pos
)
940 struct layout_range_header
*cur
;
942 LIST_FOR_EACH_ENTRY(cur
, ranges
, struct layout_range_header
, entry
) {
943 DWRITE_TEXT_RANGE
*r
= &cur
->range
;
944 if (r
->startPosition
<= pos
&& pos
< r
->startPosition
+ r
->length
)
951 static inline IUnknown
*layout_get_effect_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
953 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->effects
, pos
);
954 return ((struct layout_range_effect
*)h
)->effect
;
957 static inline BOOL
layout_is_erun_rtl(const struct layout_effective_run
*erun
)
959 return erun
->run
->u
.regular
.run
.bidiLevel
& 1;
962 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
963 'cluster_count' indicates how many clusters to add, including first one. */
964 static HRESULT
layout_add_effective_run(struct dwrite_textlayout
*layout
, const struct layout_run
*r
, UINT32 first_cluster
,
965 UINT32 cluster_count
, UINT32 line
, FLOAT origin_x
, BOOL strikethrough
)
967 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
968 UINT32 i
, start
, length
, last_cluster
;
969 struct layout_effective_run
*run
;
971 if (r
->kind
== LAYOUT_RUN_INLINE
) {
972 struct layout_effective_inline
*inlineobject
;
974 inlineobject
= heap_alloc(sizeof(*inlineobject
));
976 return E_OUTOFMEMORY
;
978 inlineobject
->object
= r
->u
.object
.object
;
979 inlineobject
->width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
980 inlineobject
->origin_x
= is_rtl
? origin_x
- inlineobject
->width
: origin_x
;
981 inlineobject
->origin_y
= 0.0; /* set after line is built */
982 inlineobject
->align_dx
= 0.0;
984 /* It's not clear how these two are set, possibly directionality
985 is derived from surrounding text (replaced text could have
986 different ranges which differ in reading direction). */
987 inlineobject
->is_sideways
= FALSE
;
988 inlineobject
->is_rtl
= FALSE
;
989 inlineobject
->line
= line
;
991 /* effect assigned from start position and on is used for inline objects */
992 inlineobject
->effect
= layout_get_effect_from_pos(layout
, layout
->clusters
[first_cluster
].position
);
994 list_add_tail(&layout
->inlineobjects
, &inlineobject
->entry
);
998 run
= heap_alloc(sizeof(*run
));
1000 return E_OUTOFMEMORY
;
1002 /* No need to iterate for that, use simple fact that:
1003 <last cluster position> = first cluster position> + <sum of cluster lengths not including last one> */
1004 last_cluster
= first_cluster
+ cluster_count
- 1;
1005 length
= layout
->clusters
[last_cluster
].position
- layout
->clusters
[first_cluster
].position
+
1006 layout
->clustermetrics
[last_cluster
].length
;
1008 run
->clustermap
= heap_alloc(sizeof(UINT16
)*length
);
1009 if (!run
->clustermap
) {
1011 return E_OUTOFMEMORY
;
1015 run
->start
= start
= layout
->clusters
[first_cluster
].position
;
1016 run
->length
= length
;
1017 run
->width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1019 /* Check if run direction matches paragraph direction, if it doesn't adjust by
1021 if (layout_is_erun_rtl(run
) ^ is_rtl
)
1022 run
->origin_x
= is_rtl
? origin_x
- run
->width
: origin_x
+ run
->width
;
1024 run
->origin_x
= origin_x
;
1026 run
->origin_y
= 0.0; /* set after line is built */
1027 run
->align_dx
= 0.0;
1030 if (r
->u
.regular
.run
.glyphCount
) {
1031 /* trim from the left */
1032 run
->glyphcount
= r
->u
.regular
.run
.glyphCount
- r
->u
.regular
.clustermap
[start
];
1033 /* trim from the right */
1034 if (start
+ length
< r
->u
.regular
.descr
.stringLength
- 1)
1035 run
->glyphcount
-= r
->u
.regular
.run
.glyphCount
- r
->u
.regular
.clustermap
[start
+ length
];
1038 run
->glyphcount
= 0;
1040 /* cluster map needs to be shifted */
1041 for (i
= 0; i
< length
; i
++)
1042 run
->clustermap
[i
] = r
->u
.regular
.clustermap
[start
+ i
] - r
->u
.regular
.clustermap
[start
];
1044 list_add_tail(&layout
->eruns
, &run
->entry
);
1046 /* Strikethrough style is guaranteed to be consistent within effective run,
1047 it's width equals to run width, thikness and offset are derived from
1048 font metrics, rest of the values are from layout or run itself */
1049 if (strikethrough
) {
1050 DWRITE_FONT_METRICS metrics
= { 0 };
1051 struct layout_strikethrough
*s
;
1053 s
= heap_alloc(sizeof(*s
));
1055 return E_OUTOFMEMORY
;
1057 if (layout
->gdicompatible
) {
1058 HRESULT hr
= IDWriteFontFace_GetGdiCompatibleMetrics(
1059 r
->u
.regular
.run
.fontFace
,
1060 r
->u
.regular
.run
.fontEmSize
,
1061 layout
->pixels_per_dip
,
1065 WARN("failed to get font metrics, 0x%08x\n", hr
);
1068 IDWriteFontFace_GetMetrics(r
->u
.regular
.run
.fontFace
, &metrics
);
1070 s
->s
.width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1071 s
->s
.thickness
= metrics
.strikethroughThickness
;
1072 s
->s
.offset
= metrics
.strikethroughPosition
;
1073 s
->s
.readingDirection
= layout
->format
.readingdir
;
1074 s
->s
.flowDirection
= layout
->format
.flow
;
1075 s
->s
.localeName
= r
->u
.regular
.descr
.localeName
;
1076 s
->s
.measuringMode
= DWRITE_MEASURING_MODE_NATURAL
; /* FIXME */
1079 list_add_tail(&layout
->strikethrough
, &s
->entry
);
1085 static HRESULT
layout_set_line_metrics(struct dwrite_textlayout
*layout
, DWRITE_LINE_METRICS
*metrics
, UINT32
*line
)
1087 if (!layout
->line_alloc
) {
1088 layout
->line_alloc
= 5;
1089 layout
->lines
= heap_alloc(layout
->line_alloc
*sizeof(*layout
->lines
));
1091 return E_OUTOFMEMORY
;
1094 if (layout
->metrics
.lineCount
== layout
->line_alloc
) {
1095 DWRITE_LINE_METRICS
*l
= heap_realloc(layout
->lines
, layout
->line_alloc
*2*sizeof(*layout
->lines
));
1097 return E_OUTOFMEMORY
;
1099 layout
->line_alloc
*= 2;
1102 layout
->lines
[*line
] = *metrics
;
1103 layout
->metrics
.lineCount
+= 1;
1108 static inline BOOL
layout_get_strikethrough_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
1110 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->strike_ranges
, pos
);
1111 return ((struct layout_range_bool
*)h
)->value
;
1114 static inline struct layout_effective_run
*layout_get_next_erun(struct dwrite_textlayout
*layout
,
1115 const struct layout_effective_run
*cur
)
1120 e
= list_head(&layout
->eruns
);
1122 e
= list_next(&layout
->eruns
, &cur
->entry
);
1125 return LIST_ENTRY(e
, struct layout_effective_run
, entry
);
1128 static inline struct layout_effective_inline
*layout_get_next_inline_run(struct dwrite_textlayout
*layout
,
1129 const struct layout_effective_inline
*cur
)
1134 e
= list_head(&layout
->inlineobjects
);
1136 e
= list_next(&layout
->inlineobjects
, &cur
->entry
);
1139 return LIST_ENTRY(e
, struct layout_effective_inline
, entry
);
1142 static FLOAT
layout_get_line_width(struct dwrite_textlayout
*layout
,
1143 struct layout_effective_run
*erun
, struct layout_effective_inline
*inrun
, UINT32 line
)
1147 while (erun
&& erun
->line
== line
) {
1148 width
+= erun
->width
;
1149 erun
= layout_get_next_erun(layout
, erun
);
1154 while (inrun
&& inrun
->line
== line
) {
1155 width
+= inrun
->width
;
1156 inrun
= layout_get_next_inline_run(layout
, inrun
);
1164 static void layout_apply_leading_alignment(struct dwrite_textlayout
*layout
)
1166 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1167 struct layout_effective_inline
*inrun
;
1168 struct layout_effective_run
*erun
;
1170 erun
= layout_get_next_erun(layout
, NULL
);
1171 inrun
= layout_get_next_inline_run(layout
, NULL
);
1174 erun
->align_dx
= 0.0;
1175 erun
= layout_get_next_erun(layout
, erun
);
1179 inrun
->align_dx
= 0.0;
1180 inrun
= layout_get_next_inline_run(layout
, inrun
);
1183 layout
->metrics
.left
= is_rtl
? layout
->metrics
.layoutWidth
- layout
->metrics
.width
: 0.0;
1186 static void layout_apply_trailing_alignment(struct dwrite_textlayout
*layout
)
1188 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1189 struct layout_effective_inline
*inrun
;
1190 struct layout_effective_run
*erun
;
1193 erun
= layout_get_next_erun(layout
, NULL
);
1194 inrun
= layout_get_next_inline_run(layout
, NULL
);
1196 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1197 FLOAT width
= layout_get_line_width(layout
, erun
, inrun
, line
);
1198 FLOAT shift
= layout
->metrics
.layoutWidth
- width
;
1203 while (erun
&& erun
->line
== line
) {
1204 erun
->align_dx
= shift
;
1205 erun
= layout_get_next_erun(layout
, erun
);
1208 while (inrun
&& inrun
->line
== line
) {
1209 inrun
->align_dx
= shift
;
1210 inrun
= layout_get_next_inline_run(layout
, inrun
);
1214 layout
->metrics
.left
= is_rtl
? 0.0 : layout
->metrics
.layoutWidth
- layout
->metrics
.width
;
1217 static void layout_apply_centered_alignment(struct dwrite_textlayout
*layout
)
1219 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1220 struct layout_effective_inline
*inrun
;
1221 struct layout_effective_run
*erun
;
1224 erun
= layout_get_next_erun(layout
, NULL
);
1225 inrun
= layout_get_next_inline_run(layout
, NULL
);
1227 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1228 FLOAT width
= layout_get_line_width(layout
, erun
, inrun
, line
);
1229 FLOAT shift
= (layout
->metrics
.layoutWidth
- width
) / 2.0;
1234 while (erun
&& erun
->line
== line
) {
1235 erun
->align_dx
= shift
;
1236 erun
= layout_get_next_erun(layout
, erun
);
1239 while (inrun
&& inrun
->line
== line
) {
1240 inrun
->align_dx
= shift
;
1241 inrun
= layout_get_next_inline_run(layout
, inrun
);
1245 layout
->metrics
.left
= (layout
->metrics
.layoutWidth
- layout
->metrics
.width
) / 2.0;
1248 static void layout_apply_text_alignment(struct dwrite_textlayout
*layout
)
1250 switch (layout
->format
.textalignment
)
1252 case DWRITE_TEXT_ALIGNMENT_LEADING
:
1253 layout_apply_leading_alignment(layout
);
1255 case DWRITE_TEXT_ALIGNMENT_TRAILING
:
1256 layout_apply_trailing_alignment(layout
);
1258 case DWRITE_TEXT_ALIGNMENT_CENTER
:
1259 layout_apply_centered_alignment(layout
);
1261 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED
:
1262 FIXME("alignment %d not implemented\n", layout
->format
.textalignment
);
1269 static void layout_apply_par_alignment(struct dwrite_textlayout
*layout
)
1271 struct layout_effective_inline
*inrun
;
1272 struct layout_effective_run
*erun
;
1273 FLOAT origin_y
= 0.0;
1276 /* alignment mode defines origin, after that all run origins are updated
1279 switch (layout
->format
.paralign
)
1281 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR
:
1284 case DWRITE_PARAGRAPH_ALIGNMENT_FAR
:
1285 origin_y
= layout
->metrics
.layoutHeight
- layout
->metrics
.height
;
1287 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER
:
1288 origin_y
= (layout
->metrics
.layoutHeight
- layout
->metrics
.height
) / 2.0;
1294 layout
->metrics
.top
= origin_y
;
1296 erun
= layout_get_next_erun(layout
, NULL
);
1297 inrun
= layout_get_next_inline_run(layout
, NULL
);
1298 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1299 origin_y
+= layout
->lines
[line
].baseline
;
1301 while (erun
&& erun
->line
== line
) {
1302 erun
->origin_y
= origin_y
;
1303 erun
= layout_get_next_erun(layout
, erun
);
1306 while (inrun
&& inrun
->line
== line
) {
1307 inrun
->origin_y
= origin_y
;
1308 inrun
= layout_get_next_inline_run(layout
, inrun
);
1313 static HRESULT
layout_compute_effective_runs(struct dwrite_textlayout
*layout
)
1315 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1316 struct layout_effective_inline
*inrun
;
1317 struct layout_effective_run
*erun
;
1318 const struct layout_run
*run
;
1319 DWRITE_LINE_METRICS metrics
;
1320 FLOAT width
, origin_x
, origin_y
;
1321 UINT32 i
, start
, line
, textpos
;
1325 if (!(layout
->recompute
& RECOMPUTE_EFFECTIVE_RUNS
))
1328 hr
= layout_compute(layout
);
1332 layout
->metrics
.lineCount
= 0;
1333 origin_x
= is_rtl
? layout
->metrics
.layoutWidth
: 0.0;
1335 run
= layout
->clusters
[0].run
;
1336 memset(&metrics
, 0, sizeof(metrics
));
1337 s
[0] = s
[1] = layout_get_strikethrough_from_pos(layout
, 0);
1339 for (i
= 0, start
= 0, textpos
= 0, width
= 0.0; i
< layout
->cluster_count
; i
++) {
1342 s
[1] = layout_get_strikethrough_from_pos(layout
, textpos
);
1344 /* switched to next nominal run, at this point all previous pending clusters are already
1345 checked for layout line overflow, so new effective run will fit in current line */
1346 if (run
!= layout
->clusters
[i
].run
|| s
[0] != s
[1]) {
1347 hr
= layout_add_effective_run(layout
, run
, start
, i
- start
, line
, origin_x
, s
[0]);
1350 origin_x
+= is_rtl
? -get_cluster_range_width(layout
, start
, i
) :
1351 get_cluster_range_width(layout
, start
, i
);
1352 run
= layout
->clusters
[i
].run
;
1356 overflow
= layout
->clustermetrics
[i
].canWrapLineAfter
&&
1357 (width
+ layout
->clustermetrics
[i
].width
> layout
->metrics
.layoutWidth
);
1358 /* check if we got new */
1360 layout
->clustermetrics
[i
].isNewline
|| /* always wrap on new line */
1361 i
== layout
->cluster_count
- 1) /* end of the text */ {
1363 UINT32 strlength
, last_cluster
= i
, index
;
1364 FLOAT descent
, trailingspacewidth
;
1367 width
+= layout
->clustermetrics
[i
].width
;
1368 metrics
.length
+= layout
->clustermetrics
[i
].length
;
1372 last_cluster
= i
? i
- 1 : i
;
1375 hr
= layout_add_effective_run(layout
, run
, start
, last_cluster
- start
+ 1, line
, origin_x
, s
[0]);
1378 /* we don't need to update origin for next run as we're going to wrap */
1381 /* take a look at clusters we got for this line in reverse order to set
1382 trailing properties for current line */
1383 strlength
= metrics
.length
;
1384 index
= last_cluster
;
1385 trailingspacewidth
= 0.0;
1387 DWRITE_CLUSTER_METRICS
*cluster
= &layout
->clustermetrics
[index
];
1389 if (!cluster
->isNewline
&& !cluster
->isWhitespace
)
1392 if (cluster
->isNewline
) {
1393 metrics
.trailingWhitespaceLength
+= cluster
->length
;
1394 metrics
.newlineLength
+= cluster
->length
;
1397 if (cluster
->isWhitespace
) {
1398 metrics
.trailingWhitespaceLength
+= cluster
->length
;
1399 trailingspacewidth
+= cluster
->width
;
1402 strlength
-= cluster
->length
;
1406 /* look for max baseline and descent for this line */
1407 strlength
= metrics
.length
;
1408 index
= last_cluster
;
1409 metrics
.baseline
= 0.0;
1412 DWRITE_CLUSTER_METRICS
*cluster
= &layout
->clustermetrics
[index
];
1413 const struct layout_run
*cur
= layout
->clusters
[index
].run
;
1414 FLOAT cur_descent
= cur
->height
- cur
->baseline
;
1416 if (cur
->baseline
> metrics
.baseline
)
1417 metrics
.baseline
= cur
->baseline
;
1419 if (cur_descent
> descent
)
1420 descent
= cur_descent
;
1422 strlength
-= cluster
->length
;
1425 metrics
.height
= descent
+ metrics
.baseline
;
1427 if (width
> layout
->metrics
.widthIncludingTrailingWhitespace
)
1428 layout
->metrics
.widthIncludingTrailingWhitespace
= width
;
1429 if (width
- trailingspacewidth
> layout
->metrics
.width
)
1430 layout
->metrics
.width
= width
- trailingspacewidth
;
1432 metrics
.isTrimmed
= width
> layout
->metrics
.layoutWidth
;
1433 hr
= layout_set_line_metrics(layout
, &metrics
, &line
);
1437 width
= layout
->clustermetrics
[i
].width
;
1438 memset(&metrics
, 0, sizeof(metrics
));
1439 origin_x
= is_rtl
? layout
->metrics
.layoutWidth
: 0.0;
1443 metrics
.length
+= layout
->clustermetrics
[i
].length
;
1444 width
+= layout
->clustermetrics
[i
].width
;
1448 textpos
+= layout
->clustermetrics
[i
].length
;
1451 layout
->metrics
.left
= is_rtl
? layout
->metrics
.layoutWidth
- layout
->metrics
.width
: 0;
1452 layout
->metrics
.top
= 0.0;
1453 layout
->metrics
.maxBidiReorderingDepth
= 1; /* FIXME */
1454 layout
->metrics
.height
= 0.0;
1456 /* Now all line info is here, update effective runs positions in flow direction */
1457 erun
= layout_get_next_erun(layout
, NULL
);
1458 inrun
= layout_get_next_inline_run(layout
, NULL
);
1461 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1463 origin_y
+= layout
->lines
[line
].baseline
;
1465 /* For all runs on this line */
1466 while (erun
&& erun
->line
== line
) {
1467 erun
->origin_y
= origin_y
;
1468 erun
= layout_get_next_erun(layout
, erun
);
1471 /* Same for inline runs */
1472 while (inrun
&& inrun
->line
== line
) {
1473 inrun
->origin_y
= origin_y
;
1474 inrun
= layout_get_next_inline_run(layout
, inrun
);
1477 layout
->metrics
.height
+= layout
->lines
[line
].height
;
1480 /* initial alignment is always leading */
1481 if (layout
->format
.textalignment
!= DWRITE_TEXT_ALIGNMENT_LEADING
)
1482 layout_apply_text_alignment(layout
);
1484 /* initial paragraph alignment is always near */
1485 if (layout
->format
.paralign
!= DWRITE_PARAGRAPH_ALIGNMENT_NEAR
)
1486 layout_apply_par_alignment(layout
);
1488 layout
->metrics
.heightIncludingTrailingWhitespace
= layout
->metrics
.height
; /* FIXME: not true for vertical text */
1490 layout
->recompute
&= ~RECOMPUTE_EFFECTIVE_RUNS
;
1494 static BOOL
is_same_layout_attrvalue(struct layout_range_header
const *h
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
1496 struct layout_range_spacing
const *range_spacing
= (struct layout_range_spacing
*)h
;
1497 struct layout_range_effect
const *range_effect
= (struct layout_range_effect
*)h
;
1498 struct layout_range_bool
const *range_bool
= (struct layout_range_bool
*)h
;
1499 struct layout_range
const *range
= (struct layout_range
*)h
;
1502 case LAYOUT_RANGE_ATTR_WEIGHT
:
1503 return range
->weight
== value
->u
.weight
;
1504 case LAYOUT_RANGE_ATTR_STYLE
:
1505 return range
->style
== value
->u
.style
;
1506 case LAYOUT_RANGE_ATTR_STRETCH
:
1507 return range
->stretch
== value
->u
.stretch
;
1508 case LAYOUT_RANGE_ATTR_FONTSIZE
:
1509 return range
->fontsize
== value
->u
.fontsize
;
1510 case LAYOUT_RANGE_ATTR_INLINE
:
1511 return range
->object
== value
->u
.object
;
1512 case LAYOUT_RANGE_ATTR_EFFECT
:
1513 return range_effect
->effect
== value
->u
.effect
;
1514 case LAYOUT_RANGE_ATTR_UNDERLINE
:
1515 return range
->underline
== value
->u
.underline
;
1516 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
1517 return range_bool
->value
== value
->u
.strikethrough
;
1518 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
1519 return range
->pair_kerning
== value
->u
.pair_kerning
;
1520 case LAYOUT_RANGE_ATTR_FONTCOLL
:
1521 return range
->collection
== value
->u
.collection
;
1522 case LAYOUT_RANGE_ATTR_LOCALE
:
1523 return strcmpW(range
->locale
, value
->u
.locale
) == 0;
1524 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
1525 return strcmpW(range
->fontfamily
, value
->u
.fontfamily
) == 0;
1526 case LAYOUT_RANGE_ATTR_SPACING
:
1527 return range_spacing
->leading
== value
->u
.spacing
[0] &&
1528 range_spacing
->trailing
== value
->u
.spacing
[1] &&
1529 range_spacing
->min_advance
== value
->u
.spacing
[2];
1537 static inline BOOL
is_same_layout_attributes(struct layout_range_header
const *hleft
, struct layout_range_header
const *hright
)
1539 switch (hleft
->kind
)
1541 case LAYOUT_RANGE_REGULAR
:
1543 struct layout_range
const *left
= (struct layout_range
const*)hleft
;
1544 struct layout_range
const *right
= (struct layout_range
const*)hright
;
1545 return left
->weight
== right
->weight
&&
1546 left
->style
== right
->style
&&
1547 left
->stretch
== right
->stretch
&&
1548 left
->fontsize
== right
->fontsize
&&
1549 left
->object
== right
->object
&&
1550 left
->underline
== right
->underline
&&
1551 left
->pair_kerning
== right
->pair_kerning
&&
1552 left
->collection
== right
->collection
&&
1553 !strcmpW(left
->locale
, right
->locale
) &&
1554 !strcmpW(left
->fontfamily
, right
->fontfamily
);
1556 case LAYOUT_RANGE_STRIKETHROUGH
:
1558 struct layout_range_bool
const *left
= (struct layout_range_bool
const*)hleft
;
1559 struct layout_range_bool
const *right
= (struct layout_range_bool
const*)hright
;
1560 return left
->value
== right
->value
;
1562 case LAYOUT_RANGE_EFFECT
:
1564 struct layout_range_effect
const *left
= (struct layout_range_effect
const*)hleft
;
1565 struct layout_range_effect
const *right
= (struct layout_range_effect
const*)hright
;
1566 return left
->effect
== right
->effect
;
1568 case LAYOUT_RANGE_SPACING
:
1570 struct layout_range_spacing
const *left
= (struct layout_range_spacing
const*)hleft
;
1571 struct layout_range_spacing
const *right
= (struct layout_range_spacing
const*)hright
;
1572 return left
->leading
== right
->leading
&&
1573 left
->trailing
== right
->trailing
&&
1574 left
->min_advance
== right
->min_advance
;
1577 FIXME("unknown range kind %d\n", hleft
->kind
);
1582 static inline BOOL
is_same_text_range(const DWRITE_TEXT_RANGE
*left
, const DWRITE_TEXT_RANGE
*right
)
1584 return left
->startPosition
== right
->startPosition
&& left
->length
== right
->length
;
1587 /* Allocates range and inits it with default values from text format. */
1588 static struct layout_range_header
*alloc_layout_range(struct dwrite_textlayout
*layout
, const DWRITE_TEXT_RANGE
*r
,
1589 enum layout_range_kind kind
)
1591 struct layout_range_header
*h
;
1595 case LAYOUT_RANGE_REGULAR
:
1597 struct layout_range
*range
;
1599 range
= heap_alloc(sizeof(*range
));
1600 if (!range
) return NULL
;
1602 range
->weight
= layout
->format
.weight
;
1603 range
->style
= layout
->format
.style
;
1604 range
->stretch
= layout
->format
.stretch
;
1605 range
->fontsize
= layout
->format
.fontsize
;
1606 range
->object
= NULL
;
1607 range
->underline
= FALSE
;
1608 range
->pair_kerning
= FALSE
;
1610 range
->fontfamily
= heap_strdupW(layout
->format
.family_name
);
1611 if (!range
->fontfamily
) {
1616 range
->collection
= layout
->format
.collection
;
1617 if (range
->collection
)
1618 IDWriteFontCollection_AddRef(range
->collection
);
1619 strcpyW(range
->locale
, layout
->format
.locale
);
1624 case LAYOUT_RANGE_STRIKETHROUGH
:
1626 struct layout_range_bool
*range
;
1628 range
= heap_alloc(sizeof(*range
));
1629 if (!range
) return NULL
;
1631 range
->value
= FALSE
;
1635 case LAYOUT_RANGE_EFFECT
:
1637 struct layout_range_effect
*range
;
1639 range
= heap_alloc(sizeof(*range
));
1640 if (!range
) return NULL
;
1642 range
->effect
= NULL
;
1646 case LAYOUT_RANGE_SPACING
:
1648 struct layout_range_spacing
*range
;
1650 range
= heap_alloc(sizeof(*range
));
1651 if (!range
) return NULL
;
1653 range
->leading
= 0.0;
1654 range
->trailing
= 0.0;
1655 range
->min_advance
= 0.0;
1660 FIXME("unknown range kind %d\n", kind
);
1669 static struct layout_range_header
*alloc_layout_range_from(struct layout_range_header
*h
, const DWRITE_TEXT_RANGE
*r
)
1671 struct layout_range_header
*ret
;
1675 case LAYOUT_RANGE_REGULAR
:
1677 struct layout_range
*from
= (struct layout_range
*)h
;
1679 struct layout_range
*range
= heap_alloc(sizeof(*range
));
1680 if (!range
) return NULL
;
1683 range
->fontfamily
= heap_strdupW(from
->fontfamily
);
1684 if (!range
->fontfamily
) {
1689 /* update refcounts */
1691 IDWriteInlineObject_AddRef(range
->object
);
1692 if (range
->collection
)
1693 IDWriteFontCollection_AddRef(range
->collection
);
1697 case LAYOUT_RANGE_STRIKETHROUGH
:
1699 struct layout_range_bool
*strike
= heap_alloc(sizeof(*strike
));
1700 if (!strike
) return NULL
;
1702 *strike
= *(struct layout_range_bool
*)h
;
1706 case LAYOUT_RANGE_EFFECT
:
1708 struct layout_range_effect
*effect
= heap_alloc(sizeof(*effect
));
1709 if (!effect
) return NULL
;
1711 *effect
= *(struct layout_range_effect
*)h
;
1713 IUnknown_AddRef(effect
->effect
);
1717 case LAYOUT_RANGE_SPACING
:
1719 struct layout_range_spacing
*spacing
= heap_alloc(sizeof(*spacing
));
1720 if (!spacing
) return NULL
;
1722 *spacing
= *(struct layout_range_spacing
*)h
;
1727 FIXME("unknown range kind %d\n", h
->kind
);
1735 static void free_layout_range(struct layout_range_header
*h
)
1742 case LAYOUT_RANGE_REGULAR
:
1744 struct layout_range
*range
= (struct layout_range
*)h
;
1747 IDWriteInlineObject_Release(range
->object
);
1748 if (range
->collection
)
1749 IDWriteFontCollection_Release(range
->collection
);
1750 heap_free(range
->fontfamily
);
1753 case LAYOUT_RANGE_EFFECT
:
1755 struct layout_range_effect
*effect
= (struct layout_range_effect
*)h
;
1757 IUnknown_Release(effect
->effect
);
1767 static void free_layout_ranges_list(struct dwrite_textlayout
*layout
)
1769 struct layout_range_header
*cur
, *cur2
;
1771 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->ranges
, struct layout_range_header
, entry
) {
1772 list_remove(&cur
->entry
);
1773 free_layout_range(cur
);
1776 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->strike_ranges
, struct layout_range_header
, entry
) {
1777 list_remove(&cur
->entry
);
1778 free_layout_range(cur
);
1781 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->effects
, struct layout_range_header
, entry
) {
1782 list_remove(&cur
->entry
);
1783 free_layout_range(cur
);
1786 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->spacing
, struct layout_range_header
, entry
) {
1787 list_remove(&cur
->entry
);
1788 free_layout_range(cur
);
1792 static struct layout_range_header
*find_outer_range(struct list
*ranges
, const DWRITE_TEXT_RANGE
*range
)
1794 struct layout_range_header
*cur
;
1796 LIST_FOR_EACH_ENTRY(cur
, ranges
, struct layout_range_header
, entry
) {
1798 if (cur
->range
.startPosition
> range
->startPosition
)
1801 if ((cur
->range
.startPosition
+ cur
->range
.length
< range
->startPosition
+ range
->length
) &&
1802 (range
->startPosition
< cur
->range
.startPosition
+ cur
->range
.length
))
1804 if (cur
->range
.startPosition
+ cur
->range
.length
>= range
->startPosition
+ range
->length
)
1811 static struct layout_range
*get_layout_range_by_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
1813 struct layout_range
*cur
;
1815 LIST_FOR_EACH_ENTRY(cur
, &layout
->ranges
, struct layout_range
, h
.entry
) {
1816 DWRITE_TEXT_RANGE
*r
= &cur
->h
.range
;
1817 if (r
->startPosition
<= pos
&& pos
< r
->startPosition
+ r
->length
)
1824 static inline BOOL
set_layout_range_iface_attr(IUnknown
**dest
, IUnknown
*value
)
1826 if (*dest
== value
) return FALSE
;
1829 IUnknown_Release(*dest
);
1832 IUnknown_AddRef(*dest
);
1837 static BOOL
set_layout_range_attrval(struct layout_range_header
*h
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
1839 struct layout_range_spacing
*dest_spacing
= (struct layout_range_spacing
*)h
;
1840 struct layout_range_effect
*dest_effect
= (struct layout_range_effect
*)h
;
1841 struct layout_range_bool
*dest_bool
= (struct layout_range_bool
*)h
;
1842 struct layout_range
*dest
= (struct layout_range
*)h
;
1844 BOOL changed
= FALSE
;
1847 case LAYOUT_RANGE_ATTR_WEIGHT
:
1848 changed
= dest
->weight
!= value
->u
.weight
;
1849 dest
->weight
= value
->u
.weight
;
1851 case LAYOUT_RANGE_ATTR_STYLE
:
1852 changed
= dest
->style
!= value
->u
.style
;
1853 dest
->style
= value
->u
.style
;
1855 case LAYOUT_RANGE_ATTR_STRETCH
:
1856 changed
= dest
->stretch
!= value
->u
.stretch
;
1857 dest
->stretch
= value
->u
.stretch
;
1859 case LAYOUT_RANGE_ATTR_FONTSIZE
:
1860 changed
= dest
->fontsize
!= value
->u
.fontsize
;
1861 dest
->fontsize
= value
->u
.fontsize
;
1863 case LAYOUT_RANGE_ATTR_INLINE
:
1864 changed
= set_layout_range_iface_attr((IUnknown
**)&dest
->object
, (IUnknown
*)value
->u
.object
);
1866 case LAYOUT_RANGE_ATTR_EFFECT
:
1867 changed
= set_layout_range_iface_attr((IUnknown
**)&dest_effect
->effect
, (IUnknown
*)value
->u
.effect
);
1869 case LAYOUT_RANGE_ATTR_UNDERLINE
:
1870 changed
= dest
->underline
!= value
->u
.underline
;
1871 dest
->underline
= value
->u
.underline
;
1873 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
1874 changed
= dest_bool
->value
!= value
->u
.strikethrough
;
1875 dest_bool
->value
= value
->u
.strikethrough
;
1877 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
1878 changed
= dest
->pair_kerning
!= value
->u
.pair_kerning
;
1879 dest
->pair_kerning
= value
->u
.pair_kerning
;
1881 case LAYOUT_RANGE_ATTR_FONTCOLL
:
1882 changed
= set_layout_range_iface_attr((IUnknown
**)&dest
->collection
, (IUnknown
*)value
->u
.collection
);
1884 case LAYOUT_RANGE_ATTR_LOCALE
:
1885 changed
= strcmpW(dest
->locale
, value
->u
.locale
) != 0;
1887 strcpyW(dest
->locale
, value
->u
.locale
);
1889 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
1890 changed
= strcmpW(dest
->fontfamily
, value
->u
.fontfamily
) != 0;
1892 heap_free(dest
->fontfamily
);
1893 dest
->fontfamily
= heap_strdupW(value
->u
.fontfamily
);
1896 case LAYOUT_RANGE_ATTR_SPACING
:
1897 changed
= dest_spacing
->leading
!= value
->u
.spacing
[0] ||
1898 dest_spacing
->trailing
!= value
->u
.spacing
[1] ||
1899 dest_spacing
->min_advance
!= value
->u
.spacing
[2];
1900 dest_spacing
->leading
= value
->u
.spacing
[0];
1901 dest_spacing
->trailing
= value
->u
.spacing
[1];
1902 dest_spacing
->min_advance
= value
->u
.spacing
[2];
1911 static inline BOOL
is_in_layout_range(const DWRITE_TEXT_RANGE
*outer
, const DWRITE_TEXT_RANGE
*inner
)
1913 return (inner
->startPosition
>= outer
->startPosition
) &&
1914 (inner
->startPosition
+ inner
->length
<= outer
->startPosition
+ outer
->length
);
1917 static inline HRESULT
return_range(const struct layout_range_header
*h
, DWRITE_TEXT_RANGE
*r
)
1919 if (r
) *r
= h
->range
;
1923 /* Set attribute value for given range, does all needed splitting/merging of existing ranges. */
1924 static HRESULT
set_layout_range_attr(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
1926 struct layout_range_header
*cur
, *right
, *left
, *outer
;
1927 BOOL changed
= FALSE
;
1928 struct list
*ranges
;
1929 DWRITE_TEXT_RANGE r
;
1931 /* ignore zero length ranges */
1932 if (value
->range
.length
== 0)
1935 /* select from ranges lists */
1938 case LAYOUT_RANGE_ATTR_WEIGHT
:
1939 case LAYOUT_RANGE_ATTR_STYLE
:
1940 case LAYOUT_RANGE_ATTR_STRETCH
:
1941 case LAYOUT_RANGE_ATTR_FONTSIZE
:
1942 case LAYOUT_RANGE_ATTR_INLINE
:
1943 case LAYOUT_RANGE_ATTR_UNDERLINE
:
1944 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
1945 case LAYOUT_RANGE_ATTR_FONTCOLL
:
1946 case LAYOUT_RANGE_ATTR_LOCALE
:
1947 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
1948 ranges
= &layout
->ranges
;
1950 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
1951 ranges
= &layout
->strike_ranges
;
1953 case LAYOUT_RANGE_ATTR_EFFECT
:
1954 ranges
= &layout
->effects
;
1956 case LAYOUT_RANGE_ATTR_SPACING
:
1957 ranges
= &layout
->spacing
;
1960 FIXME("unknown attr kind %d\n", attr
);
1964 /* If new range is completely within existing range, split existing range in two */
1965 if ((outer
= find_outer_range(ranges
, &value
->range
))) {
1967 /* no need to add same range */
1968 if (is_same_layout_attrvalue(outer
, attr
, value
))
1971 /* for matching range bounds just replace data */
1972 if (is_same_text_range(&outer
->range
, &value
->range
)) {
1973 changed
= set_layout_range_attrval(outer
, attr
, value
);
1977 /* add new range to the left */
1978 if (value
->range
.startPosition
== outer
->range
.startPosition
) {
1979 left
= alloc_layout_range_from(outer
, &value
->range
);
1980 if (!left
) return E_OUTOFMEMORY
;
1982 changed
= set_layout_range_attrval(left
, attr
, value
);
1983 list_add_before(&outer
->entry
, &left
->entry
);
1984 outer
->range
.startPosition
+= value
->range
.length
;
1985 outer
->range
.length
-= value
->range
.length
;
1989 /* add new range to the right */
1990 if (value
->range
.startPosition
+ value
->range
.length
== outer
->range
.startPosition
+ outer
->range
.length
) {
1991 right
= alloc_layout_range_from(outer
, &value
->range
);
1992 if (!right
) return E_OUTOFMEMORY
;
1994 changed
= set_layout_range_attrval(right
, attr
, value
);
1995 list_add_after(&outer
->entry
, &right
->entry
);
1996 outer
->range
.length
-= value
->range
.length
;
2000 r
.startPosition
= value
->range
.startPosition
+ value
->range
.length
;
2001 r
.length
= outer
->range
.length
+ outer
->range
.startPosition
- r
.startPosition
;
2004 right
= alloc_layout_range_from(outer
, &r
);
2005 /* new range in the middle */
2006 cur
= alloc_layout_range_from(outer
, &value
->range
);
2007 if (!right
|| !cur
) {
2008 free_layout_range(right
);
2009 free_layout_range(cur
);
2010 return E_OUTOFMEMORY
;
2013 /* reuse container range as a left part */
2014 outer
->range
.length
= value
->range
.startPosition
- outer
->range
.startPosition
;
2017 set_layout_range_attrval(cur
, attr
, value
);
2019 list_add_after(&outer
->entry
, &cur
->entry
);
2020 list_add_after(&cur
->entry
, &right
->entry
);
2025 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2026 Update all of them. */
2027 left
= get_layout_range_header_by_pos(ranges
, value
->range
.startPosition
);
2028 if (left
->range
.startPosition
== value
->range
.startPosition
)
2029 changed
= set_layout_range_attrval(left
, attr
, value
);
2030 else /* need to split */ {
2031 r
.startPosition
= value
->range
.startPosition
;
2032 r
.length
= left
->range
.length
- value
->range
.startPosition
+ left
->range
.startPosition
;
2033 left
->range
.length
-= r
.length
;
2034 cur
= alloc_layout_range_from(left
, &r
);
2035 changed
= set_layout_range_attrval(cur
, attr
, value
);
2036 list_add_after(&left
->entry
, &cur
->entry
);
2038 cur
= LIST_ENTRY(list_next(ranges
, &left
->entry
), struct layout_range_header
, entry
);
2040 /* for all existing ranges covered by new one update value */
2041 while (cur
&& is_in_layout_range(&value
->range
, &cur
->range
)) {
2042 changed
= set_layout_range_attrval(cur
, attr
, value
);
2043 cur
= LIST_ENTRY(list_next(ranges
, &cur
->entry
), struct layout_range_header
, entry
);
2046 /* it's possible rightmost range intersects */
2047 if (cur
&& (cur
->range
.startPosition
< value
->range
.startPosition
+ value
->range
.length
)) {
2048 r
.startPosition
= cur
->range
.startPosition
;
2049 r
.length
= value
->range
.startPosition
+ value
->range
.length
- cur
->range
.startPosition
;
2050 left
= alloc_layout_range_from(cur
, &r
);
2051 changed
= set_layout_range_attrval(left
, attr
, value
);
2052 cur
->range
.startPosition
+= left
->range
.length
;
2053 cur
->range
.length
-= left
->range
.length
;
2054 list_add_before(&cur
->entry
, &left
->entry
);
2059 struct list
*next
, *i
;
2061 layout
->recompute
= RECOMPUTE_EVERYTHING
;
2062 i
= list_head(ranges
);
2063 while ((next
= list_next(ranges
, i
))) {
2064 struct layout_range_header
*next_range
= LIST_ENTRY(next
, struct layout_range_header
, entry
);
2066 cur
= LIST_ENTRY(i
, struct layout_range_header
, entry
);
2067 if (is_same_layout_attributes(cur
, next_range
)) {
2068 /* remove similar range */
2069 cur
->range
.length
+= next_range
->range
.length
;
2071 free_layout_range(next_range
);
2074 i
= list_next(ranges
, i
);
2081 static inline const WCHAR
*get_string_attribute_ptr(struct layout_range
*range
, enum layout_range_attr_kind kind
)
2086 case LAYOUT_RANGE_ATTR_LOCALE
:
2087 str
= range
->locale
;
2089 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2090 str
= range
->fontfamily
;
2099 static HRESULT
get_string_attribute_length(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind kind
, UINT32 position
,
2100 UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
2102 struct layout_range
*range
;
2105 range
= get_layout_range_by_pos(layout
, position
);
2111 str
= get_string_attribute_ptr(range
, kind
);
2112 *length
= strlenW(str
);
2113 return return_range(&range
->h
, r
);
2116 static HRESULT
get_string_attribute_value(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind kind
, UINT32 position
,
2117 WCHAR
*ret
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
2119 struct layout_range
*range
;
2123 return E_INVALIDARG
;
2126 range
= get_layout_range_by_pos(layout
, position
);
2128 return E_INVALIDARG
;
2130 str
= get_string_attribute_ptr(range
, kind
);
2131 if (length
< strlenW(str
) + 1)
2132 return E_NOT_SUFFICIENT_BUFFER
;
2135 return return_range(&range
->h
, r
);
2138 static HRESULT WINAPI
dwritetextlayout_QueryInterface(IDWriteTextLayout2
*iface
, REFIID riid
, void **obj
)
2140 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2142 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
2146 if (IsEqualIID(riid
, &IID_IDWriteTextLayout2
) ||
2147 IsEqualIID(riid
, &IID_IDWriteTextLayout1
) ||
2148 IsEqualIID(riid
, &IID_IDWriteTextLayout
) ||
2149 IsEqualIID(riid
, &IID_IUnknown
))
2153 else if (IsEqualIID(riid
, &IID_IDWriteTextFormat1
) ||
2154 IsEqualIID(riid
, &IID_IDWriteTextFormat
))
2155 *obj
= &This
->IDWriteTextFormat1_iface
;
2158 IDWriteTextLayout2_AddRef(iface
);
2162 return E_NOINTERFACE
;
2165 static ULONG WINAPI
dwritetextlayout_AddRef(IDWriteTextLayout2
*iface
)
2167 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2168 ULONG ref
= InterlockedIncrement(&This
->ref
);
2169 TRACE("(%p)->(%d)\n", This
, ref
);
2173 static ULONG WINAPI
dwritetextlayout_Release(IDWriteTextLayout2
*iface
)
2175 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2176 ULONG ref
= InterlockedDecrement(&This
->ref
);
2178 TRACE("(%p)->(%d)\n", This
, ref
);
2181 free_layout_ranges_list(This
);
2182 free_layout_eruns(This
);
2183 free_layout_runs(This
);
2184 release_format_data(&This
->format
);
2185 heap_free(This
->nominal_breakpoints
);
2186 heap_free(This
->actual_breakpoints
);
2187 heap_free(This
->clustermetrics
);
2188 heap_free(This
->clusters
);
2189 heap_free(This
->lines
);
2190 heap_free(This
->str
);
2197 static HRESULT WINAPI
dwritetextlayout_SetTextAlignment(IDWriteTextLayout2
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
2199 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2200 return IDWriteTextFormat1_SetTextAlignment(&This
->IDWriteTextFormat1_iface
, alignment
);
2203 static HRESULT WINAPI
dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout2
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
2205 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2206 return IDWriteTextFormat1_SetParagraphAlignment(&This
->IDWriteTextFormat1_iface
, alignment
);
2209 static HRESULT WINAPI
dwritetextlayout_SetWordWrapping(IDWriteTextLayout2
*iface
, DWRITE_WORD_WRAPPING wrapping
)
2211 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2212 return IDWriteTextFormat1_SetWordWrapping(&This
->IDWriteTextFormat1_iface
, wrapping
);
2215 static HRESULT WINAPI
dwritetextlayout_SetReadingDirection(IDWriteTextLayout2
*iface
, DWRITE_READING_DIRECTION direction
)
2217 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2218 return IDWriteTextFormat1_SetReadingDirection(&This
->IDWriteTextFormat1_iface
, direction
);
2221 static HRESULT WINAPI
dwritetextlayout_SetFlowDirection(IDWriteTextLayout2
*iface
, DWRITE_FLOW_DIRECTION direction
)
2223 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2224 TRACE("(%p)->(%d)\n", This
, direction
);
2225 return IDWriteTextFormat1_SetFlowDirection(&This
->IDWriteTextFormat1_iface
, direction
);
2228 static HRESULT WINAPI
dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout2
*iface
, FLOAT tabstop
)
2230 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2231 TRACE("(%p)->(%.2f)\n", This
, tabstop
);
2232 return IDWriteTextFormat1_SetIncrementalTabStop(&This
->IDWriteTextFormat1_iface
, tabstop
);
2235 static HRESULT WINAPI
dwritetextlayout_SetTrimming(IDWriteTextLayout2
*iface
, DWRITE_TRIMMING
const *trimming
,
2236 IDWriteInlineObject
*trimming_sign
)
2238 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2239 TRACE("(%p)->(%p %p)\n", This
, trimming
, trimming_sign
);
2240 return IDWriteTextFormat1_SetTrimming(&This
->IDWriteTextFormat1_iface
, trimming
, trimming_sign
);
2243 static HRESULT WINAPI
dwritetextlayout_SetLineSpacing(IDWriteTextLayout2
*iface
, DWRITE_LINE_SPACING_METHOD spacing
,
2244 FLOAT line_spacing
, FLOAT baseline
)
2246 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2247 TRACE("(%p)->(%d %.2f %.2f)\n", This
, spacing
, line_spacing
, baseline
);
2248 return IDWriteTextFormat1_SetLineSpacing(&This
->IDWriteTextFormat1_iface
, spacing
, line_spacing
, baseline
);
2251 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextlayout_GetTextAlignment(IDWriteTextLayout2
*iface
)
2253 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2254 return IDWriteTextFormat1_GetTextAlignment(&This
->IDWriteTextFormat1_iface
);
2257 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout2
*iface
)
2259 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2260 return IDWriteTextFormat1_GetParagraphAlignment(&This
->IDWriteTextFormat1_iface
);
2263 static DWRITE_WORD_WRAPPING WINAPI
dwritetextlayout_GetWordWrapping(IDWriteTextLayout2
*iface
)
2265 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2266 return IDWriteTextFormat1_GetWordWrapping(&This
->IDWriteTextFormat1_iface
);
2269 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_GetReadingDirection(IDWriteTextLayout2
*iface
)
2271 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2272 return IDWriteTextFormat1_GetReadingDirection(&This
->IDWriteTextFormat1_iface
);
2275 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextlayout_GetFlowDirection(IDWriteTextLayout2
*iface
)
2277 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2278 return IDWriteTextFormat1_GetFlowDirection(&This
->IDWriteTextFormat1_iface
);
2281 static FLOAT WINAPI
dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout2
*iface
)
2283 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2284 return IDWriteTextFormat1_GetIncrementalTabStop(&This
->IDWriteTextFormat1_iface
);
2287 static HRESULT WINAPI
dwritetextlayout_GetTrimming(IDWriteTextLayout2
*iface
, DWRITE_TRIMMING
*options
,
2288 IDWriteInlineObject
**trimming_sign
)
2290 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2291 return IDWriteTextFormat1_GetTrimming(&This
->IDWriteTextFormat1_iface
, options
, trimming_sign
);
2294 static HRESULT WINAPI
dwritetextlayout_GetLineSpacing(IDWriteTextLayout2
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
2295 FLOAT
*spacing
, FLOAT
*baseline
)
2297 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2298 return IDWriteTextFormat1_GetLineSpacing(&This
->IDWriteTextFormat1_iface
, method
, spacing
, baseline
);
2301 static HRESULT WINAPI
dwritetextlayout_GetFontCollection(IDWriteTextLayout2
*iface
, IDWriteFontCollection
**collection
)
2303 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2304 return IDWriteTextFormat1_GetFontCollection(&This
->IDWriteTextFormat1_iface
, collection
);
2307 static UINT32 WINAPI
dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout2
*iface
)
2309 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2310 return IDWriteTextFormat1_GetFontFamilyNameLength(&This
->IDWriteTextFormat1_iface
);
2313 static HRESULT WINAPI
dwritetextlayout_GetFontFamilyName(IDWriteTextLayout2
*iface
, WCHAR
*name
, UINT32 size
)
2315 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2316 return IDWriteTextFormat1_GetFontFamilyName(&This
->IDWriteTextFormat1_iface
, name
, size
);
2319 static DWRITE_FONT_WEIGHT WINAPI
dwritetextlayout_GetFontWeight(IDWriteTextLayout2
*iface
)
2321 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2322 return IDWriteTextFormat1_GetFontWeight(&This
->IDWriteTextFormat1_iface
);
2325 static DWRITE_FONT_STYLE WINAPI
dwritetextlayout_GetFontStyle(IDWriteTextLayout2
*iface
)
2327 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2328 return IDWriteTextFormat1_GetFontStyle(&This
->IDWriteTextFormat1_iface
);
2331 static DWRITE_FONT_STRETCH WINAPI
dwritetextlayout_GetFontStretch(IDWriteTextLayout2
*iface
)
2333 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2334 return IDWriteTextFormat1_GetFontStretch(&This
->IDWriteTextFormat1_iface
);
2337 static FLOAT WINAPI
dwritetextlayout_GetFontSize(IDWriteTextLayout2
*iface
)
2339 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2340 return IDWriteTextFormat1_GetFontSize(&This
->IDWriteTextFormat1_iface
);
2343 static UINT32 WINAPI
dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout2
*iface
)
2345 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2346 return IDWriteTextFormat1_GetLocaleNameLength(&This
->IDWriteTextFormat1_iface
);
2349 static HRESULT WINAPI
dwritetextlayout_GetLocaleName(IDWriteTextLayout2
*iface
, WCHAR
*name
, UINT32 size
)
2351 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2352 return IDWriteTextFormat1_GetLocaleName(&This
->IDWriteTextFormat1_iface
, name
, size
);
2355 static HRESULT WINAPI
dwritetextlayout_SetMaxWidth(IDWriteTextLayout2
*iface
, FLOAT maxWidth
)
2357 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2359 TRACE("(%p)->(%.2f)\n", This
, maxWidth
);
2362 return E_INVALIDARG
;
2364 This
->metrics
.layoutWidth
= maxWidth
;
2368 static HRESULT WINAPI
dwritetextlayout_SetMaxHeight(IDWriteTextLayout2
*iface
, FLOAT maxHeight
)
2370 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2372 TRACE("(%p)->(%.2f)\n", This
, maxHeight
);
2374 if (maxHeight
< 0.0)
2375 return E_INVALIDARG
;
2377 This
->metrics
.layoutHeight
= maxHeight
;
2381 static HRESULT WINAPI
dwritetextlayout_SetFontCollection(IDWriteTextLayout2
*iface
, IDWriteFontCollection
* collection
, DWRITE_TEXT_RANGE range
)
2383 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2384 struct layout_range_attr_value value
;
2386 TRACE("(%p)->(%p %s)\n", This
, collection
, debugstr_range(&range
));
2388 value
.range
= range
;
2389 value
.u
.collection
= collection
;
2390 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTCOLL
, &value
);
2393 static HRESULT WINAPI
dwritetextlayout_SetFontFamilyName(IDWriteTextLayout2
*iface
, WCHAR
const *name
, DWRITE_TEXT_RANGE range
)
2395 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2396 struct layout_range_attr_value value
;
2398 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(name
), debugstr_range(&range
));
2401 return E_INVALIDARG
;
2403 value
.range
= range
;
2404 value
.u
.fontfamily
= name
;
2405 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, &value
);
2408 static HRESULT WINAPI
dwritetextlayout_SetFontWeight(IDWriteTextLayout2
*iface
, DWRITE_FONT_WEIGHT weight
, DWRITE_TEXT_RANGE range
)
2410 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2411 struct layout_range_attr_value value
;
2413 TRACE("(%p)->(%d %s)\n", This
, weight
, debugstr_range(&range
));
2415 value
.range
= range
;
2416 value
.u
.weight
= weight
;
2417 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_WEIGHT
, &value
);
2420 static HRESULT WINAPI
dwritetextlayout_SetFontStyle(IDWriteTextLayout2
*iface
, DWRITE_FONT_STYLE style
, DWRITE_TEXT_RANGE range
)
2422 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2423 struct layout_range_attr_value value
;
2425 TRACE("(%p)->(%d %s)\n", This
, style
, debugstr_range(&range
));
2427 if ((UINT32
)style
> DWRITE_FONT_STYLE_ITALIC
)
2428 return E_INVALIDARG
;
2430 value
.range
= range
;
2431 value
.u
.style
= style
;
2432 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STYLE
, &value
);
2435 static HRESULT WINAPI
dwritetextlayout_SetFontStretch(IDWriteTextLayout2
*iface
, DWRITE_FONT_STRETCH stretch
, DWRITE_TEXT_RANGE range
)
2437 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2438 struct layout_range_attr_value value
;
2440 TRACE("(%p)->(%d %s)\n", This
, stretch
, debugstr_range(&range
));
2442 if (stretch
== DWRITE_FONT_STRETCH_UNDEFINED
|| (UINT32
)stretch
> DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
2443 return E_INVALIDARG
;
2445 value
.range
= range
;
2446 value
.u
.stretch
= stretch
;
2447 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STRETCH
, &value
);
2450 static HRESULT WINAPI
dwritetextlayout_SetFontSize(IDWriteTextLayout2
*iface
, FLOAT size
, DWRITE_TEXT_RANGE range
)
2452 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2453 struct layout_range_attr_value value
;
2455 TRACE("(%p)->(%.2f %s)\n", This
, size
, debugstr_range(&range
));
2458 return E_INVALIDARG
;
2460 value
.range
= range
;
2461 value
.u
.fontsize
= size
;
2462 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTSIZE
, &value
);
2465 static HRESULT WINAPI
dwritetextlayout_SetUnderline(IDWriteTextLayout2
*iface
, BOOL underline
, DWRITE_TEXT_RANGE range
)
2467 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2468 struct layout_range_attr_value value
;
2470 TRACE("(%p)->(%d %s)\n", This
, underline
, debugstr_range(&range
));
2472 value
.range
= range
;
2473 value
.u
.underline
= underline
;
2474 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_UNDERLINE
, &value
);
2477 static HRESULT WINAPI
dwritetextlayout_SetStrikethrough(IDWriteTextLayout2
*iface
, BOOL strikethrough
, DWRITE_TEXT_RANGE range
)
2479 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2480 struct layout_range_attr_value value
;
2482 TRACE("(%p)->(%d %s)\n", This
, strikethrough
, debugstr_range(&range
));
2484 value
.range
= range
;
2485 value
.u
.strikethrough
= strikethrough
;
2486 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STRIKETHROUGH
, &value
);
2489 static HRESULT WINAPI
dwritetextlayout_SetDrawingEffect(IDWriteTextLayout2
*iface
, IUnknown
* effect
, DWRITE_TEXT_RANGE range
)
2491 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2492 struct layout_range_attr_value value
;
2494 TRACE("(%p)->(%p %s)\n", This
, effect
, debugstr_range(&range
));
2496 value
.range
= range
;
2497 value
.u
.effect
= effect
;
2498 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_EFFECT
, &value
);
2501 static HRESULT WINAPI
dwritetextlayout_SetInlineObject(IDWriteTextLayout2
*iface
, IDWriteInlineObject
*object
, DWRITE_TEXT_RANGE range
)
2503 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2504 struct layout_range_attr_value value
;
2506 TRACE("(%p)->(%p %s)\n", This
, object
, debugstr_range(&range
));
2508 value
.range
= range
;
2509 value
.u
.object
= object
;
2510 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_INLINE
, &value
);
2513 static HRESULT WINAPI
dwritetextlayout_SetTypography(IDWriteTextLayout2
*iface
, IDWriteTypography
* typography
, DWRITE_TEXT_RANGE range
)
2515 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2516 FIXME("(%p)->(%p %s): stub\n", This
, typography
, debugstr_range(&range
));
2520 static HRESULT WINAPI
dwritetextlayout_SetLocaleName(IDWriteTextLayout2
*iface
, WCHAR
const* locale
, DWRITE_TEXT_RANGE range
)
2522 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2523 struct layout_range_attr_value value
;
2525 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(locale
), debugstr_range(&range
));
2527 if (!locale
|| strlenW(locale
) > LOCALE_NAME_MAX_LENGTH
-1)
2528 return E_INVALIDARG
;
2530 value
.range
= range
;
2531 value
.u
.locale
= locale
;
2532 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_LOCALE
, &value
);
2535 static FLOAT WINAPI
dwritetextlayout_GetMaxWidth(IDWriteTextLayout2
*iface
)
2537 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2538 TRACE("(%p)\n", This
);
2539 return This
->metrics
.layoutWidth
;
2542 static FLOAT WINAPI
dwritetextlayout_GetMaxHeight(IDWriteTextLayout2
*iface
)
2544 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2545 TRACE("(%p)\n", This
);
2546 return This
->metrics
.layoutHeight
;
2549 static HRESULT WINAPI
dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout2
*iface
, UINT32 position
,
2550 IDWriteFontCollection
** collection
, DWRITE_TEXT_RANGE
*r
)
2552 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2553 struct layout_range
*range
;
2555 TRACE("(%p)->(%u %p %p)\n", This
, position
, collection
, r
);
2557 if (position
>= This
->len
)
2560 range
= get_layout_range_by_pos(This
, position
);
2561 *collection
= range
->collection
;
2563 IDWriteFontCollection_AddRef(*collection
);
2565 return return_range(&range
->h
, r
);
2568 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout2
*iface
,
2569 UINT32 position
, UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
2571 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2572 TRACE("(%p)->(%d %p %p)\n", This
, position
, length
, r
);
2573 return get_string_attribute_length(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, length
, r
);
2576 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout2
*iface
,
2577 UINT32 position
, WCHAR
*name
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
2579 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2580 TRACE("(%p)->(%u %p %u %p)\n", This
, position
, name
, length
, r
);
2581 return get_string_attribute_value(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, name
, length
, r
);
2584 static HRESULT WINAPI
dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout2
*iface
,
2585 UINT32 position
, DWRITE_FONT_WEIGHT
*weight
, DWRITE_TEXT_RANGE
*r
)
2587 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2588 struct layout_range
*range
;
2590 TRACE("(%p)->(%u %p %p)\n", This
, position
, weight
, r
);
2592 if (position
>= This
->len
)
2595 range
= get_layout_range_by_pos(This
, position
);
2596 *weight
= range
->weight
;
2598 return return_range(&range
->h
, r
);
2601 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout2
*iface
,
2602 UINT32 position
, DWRITE_FONT_STYLE
*style
, DWRITE_TEXT_RANGE
*r
)
2604 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2605 struct layout_range
*range
;
2607 TRACE("(%p)->(%u %p %p)\n", This
, position
, style
, r
);
2609 range
= get_layout_range_by_pos(This
, position
);
2610 *style
= range
->style
;
2611 return return_range(&range
->h
, r
);
2614 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout2
*iface
,
2615 UINT32 position
, DWRITE_FONT_STRETCH
*stretch
, DWRITE_TEXT_RANGE
*r
)
2617 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2618 struct layout_range
*range
;
2620 TRACE("(%p)->(%u %p %p)\n", This
, position
, stretch
, r
);
2622 range
= get_layout_range_by_pos(This
, position
);
2623 *stretch
= range
->stretch
;
2624 return return_range(&range
->h
, r
);
2627 static HRESULT WINAPI
dwritetextlayout_layout_GetFontSize(IDWriteTextLayout2
*iface
,
2628 UINT32 position
, FLOAT
*size
, DWRITE_TEXT_RANGE
*r
)
2630 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2631 struct layout_range
*range
;
2633 TRACE("(%p)->(%u %p %p)\n", This
, position
, size
, r
);
2635 range
= get_layout_range_by_pos(This
, position
);
2636 *size
= range
->fontsize
;
2637 return return_range(&range
->h
, r
);
2640 static HRESULT WINAPI
dwritetextlayout_GetUnderline(IDWriteTextLayout2
*iface
,
2641 UINT32 position
, BOOL
*underline
, DWRITE_TEXT_RANGE
*r
)
2643 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2644 struct layout_range
*range
;
2646 TRACE("(%p)->(%u %p %p)\n", This
, position
, underline
, r
);
2648 if (position
>= This
->len
)
2651 range
= get_layout_range_by_pos(This
, position
);
2652 *underline
= range
->underline
;
2654 return return_range(&range
->h
, r
);
2657 static HRESULT WINAPI
dwritetextlayout_GetStrikethrough(IDWriteTextLayout2
*iface
,
2658 UINT32 position
, BOOL
*strikethrough
, DWRITE_TEXT_RANGE
*r
)
2660 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2661 struct layout_range_bool
*range
;
2663 TRACE("(%p)->(%u %p %p)\n", This
, position
, strikethrough
, r
);
2665 range
= (struct layout_range_bool
*)get_layout_range_header_by_pos(&This
->strike_ranges
, position
);
2666 *strikethrough
= range
->value
;
2668 return return_range(&range
->h
, r
);
2671 static HRESULT WINAPI
dwritetextlayout_GetDrawingEffect(IDWriteTextLayout2
*iface
,
2672 UINT32 position
, IUnknown
**effect
, DWRITE_TEXT_RANGE
*r
)
2674 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2675 struct layout_range_effect
*range
;
2677 TRACE("(%p)->(%u %p %p)\n", This
, position
, effect
, r
);
2679 range
= (struct layout_range_effect
*)get_layout_range_header_by_pos(&This
->effects
, position
);
2680 *effect
= range
->effect
;
2682 IUnknown_AddRef(*effect
);
2684 return return_range(&range
->h
, r
);
2687 static HRESULT WINAPI
dwritetextlayout_GetInlineObject(IDWriteTextLayout2
*iface
,
2688 UINT32 position
, IDWriteInlineObject
**object
, DWRITE_TEXT_RANGE
*r
)
2690 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2691 struct layout_range
*range
;
2693 TRACE("(%p)->(%u %p %p)\n", This
, position
, object
, r
);
2695 if (position
>= This
->len
)
2698 range
= get_layout_range_by_pos(This
, position
);
2699 *object
= range
->object
;
2701 IDWriteInlineObject_AddRef(*object
);
2703 return return_range(&range
->h
, r
);
2706 static HRESULT WINAPI
dwritetextlayout_GetTypography(IDWriteTextLayout2
*iface
,
2707 UINT32 position
, IDWriteTypography
** typography
, DWRITE_TEXT_RANGE
*range
)
2709 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2710 FIXME("(%p)->(%u %p %p): stub\n", This
, position
, typography
, range
);
2714 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout2
*iface
,
2715 UINT32 position
, UINT32
* length
, DWRITE_TEXT_RANGE
*r
)
2717 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2718 TRACE("(%p)->(%u %p %p)\n", This
, position
, length
, r
);
2719 return get_string_attribute_length(This
, LAYOUT_RANGE_ATTR_LOCALE
, position
, length
, r
);
2722 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout2
*iface
,
2723 UINT32 position
, WCHAR
* locale
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
2725 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2726 TRACE("(%p)->(%u %p %u %p)\n", This
, position
, locale
, length
, r
);
2727 return get_string_attribute_value(This
, LAYOUT_RANGE_ATTR_LOCALE
, position
, locale
, length
, r
);
2730 static inline FLOAT
renderer_apply_snapping(FLOAT coord
, BOOL skiptransform
, FLOAT ppdip
, FLOAT det
,
2731 const DWRITE_MATRIX
*m
)
2733 FLOAT vec
[2], vec2
[2];
2735 if (!skiptransform
) {
2736 /* apply transform */
2740 vec2
[0] = m
->m11
* vec
[0] + m
->m12
* vec
[1] + m
->dx
;
2741 vec2
[1] = m
->m21
* vec
[0] + m
->m22
* vec
[1] + m
->dy
;
2744 vec2
[0] = floorf(vec2
[0] * ppdip
+ 0.5f
) / ppdip
;
2745 vec2
[1] = floorf(vec2
[1] * ppdip
+ 0.5f
) / ppdip
;
2747 /* apply inverted transform, we don't care about X component at this point */
2748 vec
[1] = (-m
->m21
* vec2
[0] + m
->m11
* vec2
[1] - (m
->m11
* m
->dy
- m
->m12
* m
->dx
)) / det
;
2751 vec
[1] = floorf(coord
* ppdip
+ 0.5f
) / ppdip
;
2756 static HRESULT WINAPI
dwritetextlayout_Draw(IDWriteTextLayout2
*iface
,
2757 void *context
, IDWriteTextRenderer
* renderer
, FLOAT origin_x
, FLOAT origin_y
)
2759 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2760 BOOL disabled
= FALSE
, skiptransform
= FALSE
;
2761 struct layout_effective_inline
*inlineobject
;
2762 struct layout_effective_run
*run
;
2763 struct layout_strikethrough
*s
;
2764 FLOAT det
= 0.0, ppdip
= 0.0;
2765 DWRITE_MATRIX m
= { 0 };
2768 TRACE("(%p)->(%p %p %.2f %.2f)\n", This
, context
, renderer
, origin_x
, origin_y
);
2770 hr
= layout_compute_effective_runs(This
);
2774 hr
= IDWriteTextRenderer_IsPixelSnappingDisabled(renderer
, context
, &disabled
);
2779 hr
= IDWriteTextRenderer_GetPixelsPerDip(renderer
, context
, &ppdip
);
2783 hr
= IDWriteTextRenderer_GetCurrentTransform(renderer
, context
, &m
);
2787 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
2789 (m
.m11
* m
.m22
!= 0.0 && (m
.m12
!= 0.0 || m
.m21
!= 0.0)) ||
2790 (m
.m12
* m
.m21
!= 0.0 && (m
.m11
!= 0.0 || m
.m22
!= 0.0)))
2793 det
= m
.m11
* m
.m22
- m
.m12
* m
.m21
;
2795 /* on certain conditions we can skip transform */
2796 if (!memcmp(&m
, &identity
, sizeof(m
)) || fabsf(det
) <= 1e-10f
)
2797 skiptransform
= TRUE
;
2801 #define SNAP_COORD(x) renderer_apply_snapping((x), skiptransform, ppdip, det, &m)
2802 /* 1. Regular runs */
2803 LIST_FOR_EACH_ENTRY(run
, &This
->eruns
, struct layout_effective_run
, entry
) {
2804 const struct regular_layout_run
*regular
= &run
->run
->u
.regular
;
2805 UINT32 start_glyph
= regular
->clustermap
[run
->start
];
2806 DWRITE_GLYPH_RUN_DESCRIPTION descr
;
2807 DWRITE_GLYPH_RUN glyph_run
;
2809 /* Everything but cluster map will be reused from nominal run, as we only need
2810 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
2811 it can't be reused because it has to start with 0 index for each reported run. */
2812 glyph_run
= regular
->run
;
2813 glyph_run
.glyphCount
= run
->glyphcount
;
2815 /* fixup glyph data arrays */
2816 glyph_run
.glyphIndices
+= start_glyph
;
2817 glyph_run
.glyphAdvances
+= start_glyph
;
2818 glyph_run
.glyphOffsets
+= start_glyph
;
2821 descr
= regular
->descr
;
2822 descr
.stringLength
= run
->length
;
2823 descr
.string
+= run
->start
;
2824 descr
.clusterMap
= run
->clustermap
;
2825 descr
.textPosition
+= run
->start
;
2827 /* return value is ignored */
2828 IDWriteTextRenderer_DrawGlyphRun(renderer
,
2830 run
->origin_x
+ run
->align_dx
+ origin_x
,
2831 disabled
? run
->origin_y
+ origin_y
: SNAP_COORD(run
->origin_y
+ origin_y
),
2832 DWRITE_MEASURING_MODE_NATURAL
,
2838 /* 2. Inline objects */
2839 LIST_FOR_EACH_ENTRY(inlineobject
, &This
->inlineobjects
, struct layout_effective_inline
, entry
) {
2840 IDWriteTextRenderer_DrawInlineObject(renderer
,
2842 inlineobject
->origin_x
+ inlineobject
->align_dx
+ origin_x
,
2843 disabled
? inlineobject
->origin_y
+ origin_y
: SNAP_COORD(inlineobject
->origin_y
+ origin_y
),
2844 inlineobject
->object
,
2845 inlineobject
->is_sideways
,
2846 inlineobject
->is_rtl
,
2847 inlineobject
->effect
);
2850 /* TODO: 3. Underlines */
2852 /* 4. Strikethrough */
2853 LIST_FOR_EACH_ENTRY(s
, &This
->strikethrough
, struct layout_strikethrough
, entry
) {
2854 IDWriteTextRenderer_DrawStrikethrough(renderer
,
2857 disabled
? s
->run
->origin_y
: SNAP_COORD(s
->run
->origin_y
),
2866 static HRESULT WINAPI
dwritetextlayout_GetLineMetrics(IDWriteTextLayout2
*iface
,
2867 DWRITE_LINE_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
2869 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2872 TRACE("(%p)->(%p %u %p)\n", This
, metrics
, max_count
, count
);
2874 hr
= layout_compute_effective_runs(This
);
2879 memcpy(metrics
, This
->lines
, sizeof(*metrics
)*min(max_count
, This
->metrics
.lineCount
));
2881 *count
= This
->metrics
.lineCount
;
2882 return max_count
>= This
->metrics
.lineCount
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
2885 static HRESULT WINAPI
dwritetextlayout_GetMetrics(IDWriteTextLayout2
*iface
, DWRITE_TEXT_METRICS
*metrics
)
2887 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2888 DWRITE_TEXT_METRICS1 metrics1
;
2891 TRACE("(%p)->(%p)\n", This
, metrics
);
2893 hr
= IDWriteTextLayout2_GetMetrics(iface
, &metrics1
);
2895 memcpy(metrics
, &metrics1
, sizeof(*metrics
));
2900 static HRESULT WINAPI
dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout2
*iface
, DWRITE_OVERHANG_METRICS
*overhangs
)
2902 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2903 FIXME("(%p)->(%p): stub\n", This
, overhangs
);
2907 static HRESULT WINAPI
dwritetextlayout_GetClusterMetrics(IDWriteTextLayout2
*iface
,
2908 DWRITE_CLUSTER_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
2910 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2913 TRACE("(%p)->(%p %u %p)\n", This
, metrics
, max_count
, count
);
2915 hr
= layout_compute(This
);
2920 memcpy(metrics
, This
->clustermetrics
, sizeof(DWRITE_CLUSTER_METRICS
)*min(max_count
, This
->cluster_count
));
2922 *count
= This
->cluster_count
;
2923 return max_count
>= This
->cluster_count
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
2926 /* Only to be used with DetermineMinWidth() to find the longest cluster sequence that we don't want to try
2927 too hard to break. */
2928 static inline BOOL
is_terminal_cluster(struct dwrite_textlayout
*layout
, UINT32 index
)
2930 if (layout
->clustermetrics
[index
].isWhitespace
|| layout
->clustermetrics
[index
].isNewline
||
2931 (index
== layout
->cluster_count
- 1))
2933 /* check next one */
2934 return (index
< layout
->cluster_count
- 1) && layout
->clustermetrics
[index
+1].isWhitespace
;
2937 static HRESULT WINAPI
dwritetextlayout_DetermineMinWidth(IDWriteTextLayout2
*iface
, FLOAT
* min_width
)
2939 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2944 TRACE("(%p)->(%p)\n", This
, min_width
);
2947 return E_INVALIDARG
;
2949 if (!(This
->recompute
& RECOMPUTE_MINIMAL_WIDTH
))
2953 hr
= layout_compute(This
);
2957 for (i
= 0; i
< This
->cluster_count
;) {
2958 if (is_terminal_cluster(This
, i
)) {
2959 width
= This
->clustermetrics
[i
].width
;
2964 while (!is_terminal_cluster(This
, i
)) {
2965 width
+= This
->clustermetrics
[i
].width
;
2968 /* count last one too */
2969 width
+= This
->clustermetrics
[i
].width
;
2972 if (width
> This
->minwidth
)
2973 This
->minwidth
= width
;
2975 This
->recompute
&= ~RECOMPUTE_MINIMAL_WIDTH
;
2978 *min_width
= This
->minwidth
;
2982 static HRESULT WINAPI
dwritetextlayout_HitTestPoint(IDWriteTextLayout2
*iface
,
2983 FLOAT pointX
, FLOAT pointY
, BOOL
* is_trailinghit
, BOOL
* is_inside
, DWRITE_HIT_TEST_METRICS
*metrics
)
2985 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2986 FIXME("(%p)->(%f %f %p %p %p): stub\n", This
, pointX
, pointY
, is_trailinghit
, is_inside
, metrics
);
2990 static HRESULT WINAPI
dwritetextlayout_HitTestTextPosition(IDWriteTextLayout2
*iface
,
2991 UINT32 textPosition
, BOOL is_trailinghit
, FLOAT
* pointX
, FLOAT
* pointY
, DWRITE_HIT_TEST_METRICS
*metrics
)
2993 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
2994 FIXME("(%p)->(%u %d %p %p %p): stub\n", This
, textPosition
, is_trailinghit
, pointX
, pointY
, metrics
);
2998 static HRESULT WINAPI
dwritetextlayout_HitTestTextRange(IDWriteTextLayout2
*iface
,
2999 UINT32 textPosition
, UINT32 textLength
, FLOAT originX
, FLOAT originY
,
3000 DWRITE_HIT_TEST_METRICS
*metrics
, UINT32 max_metricscount
, UINT32
* actual_metricscount
)
3002 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3003 FIXME("(%p)->(%u %u %f %f %p %u %p): stub\n", This
, textPosition
, textLength
, originX
, originY
, metrics
,
3004 max_metricscount
, actual_metricscount
);
3008 static HRESULT WINAPI
dwritetextlayout1_SetPairKerning(IDWriteTextLayout2
*iface
, BOOL is_pairkerning_enabled
,
3009 DWRITE_TEXT_RANGE range
)
3011 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3012 struct layout_range_attr_value value
;
3014 TRACE("(%p)->(%d %s)\n", This
, is_pairkerning_enabled
, debugstr_range(&range
));
3016 value
.range
= range
;
3017 value
.u
.pair_kerning
= !!is_pairkerning_enabled
;
3018 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_PAIR_KERNING
, &value
);
3021 static HRESULT WINAPI
dwritetextlayout1_GetPairKerning(IDWriteTextLayout2
*iface
, UINT32 position
, BOOL
*is_pairkerning_enabled
,
3022 DWRITE_TEXT_RANGE
*r
)
3024 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3025 struct layout_range
*range
;
3027 TRACE("(%p)->(%u %p %p)\n", This
, position
, is_pairkerning_enabled
, r
);
3029 if (position
>= This
->len
)
3032 range
= get_layout_range_by_pos(This
, position
);
3033 *is_pairkerning_enabled
= range
->pair_kerning
;
3035 return return_range(&range
->h
, r
);
3038 static HRESULT WINAPI
dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout2
*iface
, FLOAT leading
, FLOAT trailing
,
3039 FLOAT min_advance
, DWRITE_TEXT_RANGE range
)
3041 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3042 struct layout_range_attr_value value
;
3044 TRACE("(%p)->(%.2f %.2f %.2f %s)\n", This
, leading
, trailing
, min_advance
, debugstr_range(&range
));
3046 if (min_advance
< 0.0)
3047 return E_INVALIDARG
;
3049 value
.range
= range
;
3050 value
.u
.spacing
[0] = leading
;
3051 value
.u
.spacing
[1] = trailing
;
3052 value
.u
.spacing
[2] = min_advance
;
3053 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_SPACING
, &value
);
3056 static HRESULT WINAPI
dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout2
*iface
, UINT32 position
, FLOAT
*leading
,
3057 FLOAT
*trailing
, FLOAT
*min_advance
, DWRITE_TEXT_RANGE
*r
)
3059 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3060 struct layout_range_spacing
*range
;
3062 TRACE("(%p)->(%u %p %p %p %p)\n", This
, position
, leading
, trailing
, min_advance
, r
);
3064 range
= (struct layout_range_spacing
*)get_layout_range_header_by_pos(&This
->spacing
, position
);
3065 *leading
= range
->leading
;
3066 *trailing
= range
->trailing
;
3067 *min_advance
= range
->min_advance
;
3069 return return_range(&range
->h
, r
);
3072 static HRESULT WINAPI
dwritetextlayout2_GetMetrics(IDWriteTextLayout2
*iface
, DWRITE_TEXT_METRICS1
*metrics
)
3074 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3077 TRACE("(%p)->(%p)\n", This
, metrics
);
3079 hr
= layout_compute_effective_runs(This
);
3083 *metrics
= This
->metrics
;
3087 static HRESULT WINAPI
dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout2
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
3089 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3091 TRACE("(%p)->(%d)\n", This
, orientation
);
3093 if ((UINT32
)orientation
> DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED
)
3094 return E_INVALIDARG
;
3096 This
->format
.vertical_orientation
= orientation
;
3100 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout2
*iface
)
3102 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3103 TRACE("(%p)\n", This
);
3104 return This
->format
.vertical_orientation
;
3107 static HRESULT WINAPI
dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout2
*iface
, BOOL lastline_wrapping_enabled
)
3109 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3110 FIXME("(%p)->(%d): stub\n", This
, lastline_wrapping_enabled
);
3114 static BOOL WINAPI
dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout2
*iface
)
3116 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3117 FIXME("(%p): stub\n", This
);
3121 static HRESULT WINAPI
dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout2
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
3123 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3124 FIXME("(%p)->(%d): stub\n", This
, alignment
);
3128 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout2
*iface
)
3130 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3131 FIXME("(%p): stub\n", This
);
3132 return DWRITE_OPTICAL_ALIGNMENT_NONE
;
3135 static HRESULT WINAPI
dwritetextlayout2_SetFontFallback(IDWriteTextLayout2
*iface
, IDWriteFontFallback
*fallback
)
3137 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3138 TRACE("(%p)->(%p)\n", This
, fallback
);
3139 return set_fontfallback_for_format(&This
->format
, fallback
);
3142 static HRESULT WINAPI
dwritetextlayout2_GetFontFallback(IDWriteTextLayout2
*iface
, IDWriteFontFallback
**fallback
)
3144 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout2(iface
);
3145 TRACE("(%p)->(%p)\n", This
, fallback
);
3146 return get_fontfallback_from_format(&This
->format
, fallback
);
3149 static const IDWriteTextLayout2Vtbl dwritetextlayoutvtbl
= {
3150 dwritetextlayout_QueryInterface
,
3151 dwritetextlayout_AddRef
,
3152 dwritetextlayout_Release
,
3153 dwritetextlayout_SetTextAlignment
,
3154 dwritetextlayout_SetParagraphAlignment
,
3155 dwritetextlayout_SetWordWrapping
,
3156 dwritetextlayout_SetReadingDirection
,
3157 dwritetextlayout_SetFlowDirection
,
3158 dwritetextlayout_SetIncrementalTabStop
,
3159 dwritetextlayout_SetTrimming
,
3160 dwritetextlayout_SetLineSpacing
,
3161 dwritetextlayout_GetTextAlignment
,
3162 dwritetextlayout_GetParagraphAlignment
,
3163 dwritetextlayout_GetWordWrapping
,
3164 dwritetextlayout_GetReadingDirection
,
3165 dwritetextlayout_GetFlowDirection
,
3166 dwritetextlayout_GetIncrementalTabStop
,
3167 dwritetextlayout_GetTrimming
,
3168 dwritetextlayout_GetLineSpacing
,
3169 dwritetextlayout_GetFontCollection
,
3170 dwritetextlayout_GetFontFamilyNameLength
,
3171 dwritetextlayout_GetFontFamilyName
,
3172 dwritetextlayout_GetFontWeight
,
3173 dwritetextlayout_GetFontStyle
,
3174 dwritetextlayout_GetFontStretch
,
3175 dwritetextlayout_GetFontSize
,
3176 dwritetextlayout_GetLocaleNameLength
,
3177 dwritetextlayout_GetLocaleName
,
3178 dwritetextlayout_SetMaxWidth
,
3179 dwritetextlayout_SetMaxHeight
,
3180 dwritetextlayout_SetFontCollection
,
3181 dwritetextlayout_SetFontFamilyName
,
3182 dwritetextlayout_SetFontWeight
,
3183 dwritetextlayout_SetFontStyle
,
3184 dwritetextlayout_SetFontStretch
,
3185 dwritetextlayout_SetFontSize
,
3186 dwritetextlayout_SetUnderline
,
3187 dwritetextlayout_SetStrikethrough
,
3188 dwritetextlayout_SetDrawingEffect
,
3189 dwritetextlayout_SetInlineObject
,
3190 dwritetextlayout_SetTypography
,
3191 dwritetextlayout_SetLocaleName
,
3192 dwritetextlayout_GetMaxWidth
,
3193 dwritetextlayout_GetMaxHeight
,
3194 dwritetextlayout_layout_GetFontCollection
,
3195 dwritetextlayout_layout_GetFontFamilyNameLength
,
3196 dwritetextlayout_layout_GetFontFamilyName
,
3197 dwritetextlayout_layout_GetFontWeight
,
3198 dwritetextlayout_layout_GetFontStyle
,
3199 dwritetextlayout_layout_GetFontStretch
,
3200 dwritetextlayout_layout_GetFontSize
,
3201 dwritetextlayout_GetUnderline
,
3202 dwritetextlayout_GetStrikethrough
,
3203 dwritetextlayout_GetDrawingEffect
,
3204 dwritetextlayout_GetInlineObject
,
3205 dwritetextlayout_GetTypography
,
3206 dwritetextlayout_layout_GetLocaleNameLength
,
3207 dwritetextlayout_layout_GetLocaleName
,
3208 dwritetextlayout_Draw
,
3209 dwritetextlayout_GetLineMetrics
,
3210 dwritetextlayout_GetMetrics
,
3211 dwritetextlayout_GetOverhangMetrics
,
3212 dwritetextlayout_GetClusterMetrics
,
3213 dwritetextlayout_DetermineMinWidth
,
3214 dwritetextlayout_HitTestPoint
,
3215 dwritetextlayout_HitTestTextPosition
,
3216 dwritetextlayout_HitTestTextRange
,
3217 dwritetextlayout1_SetPairKerning
,
3218 dwritetextlayout1_GetPairKerning
,
3219 dwritetextlayout1_SetCharacterSpacing
,
3220 dwritetextlayout1_GetCharacterSpacing
,
3221 dwritetextlayout2_GetMetrics
,
3222 dwritetextlayout2_SetVerticalGlyphOrientation
,
3223 dwritetextlayout2_GetVerticalGlyphOrientation
,
3224 dwritetextlayout2_SetLastLineWrapping
,
3225 dwritetextlayout2_GetLastLineWrapping
,
3226 dwritetextlayout2_SetOpticalAlignment
,
3227 dwritetextlayout2_GetOpticalAlignment
,
3228 dwritetextlayout2_SetFontFallback
,
3229 dwritetextlayout2_GetFontFallback
3232 static HRESULT WINAPI
dwritetextformat1_layout_QueryInterface(IDWriteTextFormat1
*iface
, REFIID riid
, void **obj
)
3234 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3235 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
3236 return IDWriteTextLayout2_QueryInterface(&This
->IDWriteTextLayout2_iface
, riid
, obj
);
3239 static ULONG WINAPI
dwritetextformat1_layout_AddRef(IDWriteTextFormat1
*iface
)
3241 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3242 return IDWriteTextLayout2_AddRef(&This
->IDWriteTextLayout2_iface
);
3245 static ULONG WINAPI
dwritetextformat1_layout_Release(IDWriteTextFormat1
*iface
)
3247 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3248 return IDWriteTextLayout2_Release(&This
->IDWriteTextLayout2_iface
);
3251 static HRESULT WINAPI
dwritetextformat1_layout_SetTextAlignment(IDWriteTextFormat1
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
3253 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3257 TRACE("(%p)->(%d)\n", This
, alignment
);
3259 hr
= format_set_textalignment(&This
->format
, alignment
, &changed
);
3263 /* if layout is not ready there's nothing to align */
3264 if (changed
&& !(This
->recompute
& RECOMPUTE_EFFECTIVE_RUNS
))
3265 layout_apply_text_alignment(This
);
3270 static HRESULT WINAPI
dwritetextformat1_layout_SetParagraphAlignment(IDWriteTextFormat1
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
3272 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3276 TRACE("(%p)->(%d)\n", This
, alignment
);
3278 hr
= format_set_paralignment(&This
->format
, alignment
, &changed
);
3282 /* if layout is not ready there's nothing to align */
3283 if (changed
&& !(This
->recompute
& RECOMPUTE_EFFECTIVE_RUNS
))
3284 layout_apply_par_alignment(This
);
3289 static HRESULT WINAPI
dwritetextformat1_layout_SetWordWrapping(IDWriteTextFormat1
*iface
, DWRITE_WORD_WRAPPING wrapping
)
3291 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3295 TRACE("(%p)->(%d)\n", This
, wrapping
);
3297 hr
= format_set_wordwrapping(&This
->format
, wrapping
, &changed
);
3302 This
->recompute
|= RECOMPUTE_EFFECTIVE_RUNS
;
3307 static HRESULT WINAPI
dwritetextformat1_layout_SetReadingDirection(IDWriteTextFormat1
*iface
, DWRITE_READING_DIRECTION direction
)
3309 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3313 TRACE("(%p)->(%d)\n", This
, direction
);
3315 hr
= format_set_readingdirection(&This
->format
, direction
, &changed
);
3320 This
->recompute
= RECOMPUTE_EVERYTHING
;
3325 static HRESULT WINAPI
dwritetextformat1_layout_SetFlowDirection(IDWriteTextFormat1
*iface
, DWRITE_FLOW_DIRECTION direction
)
3327 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3328 FIXME("(%p)->(%d): stub\n", This
, direction
);
3332 static HRESULT WINAPI
dwritetextformat1_layout_SetIncrementalTabStop(IDWriteTextFormat1
*iface
, FLOAT tabstop
)
3334 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3335 FIXME("(%p)->(%f): stub\n", This
, tabstop
);
3339 static HRESULT WINAPI
dwritetextformat1_layout_SetTrimming(IDWriteTextFormat1
*iface
, DWRITE_TRIMMING
const *trimming
,
3340 IDWriteInlineObject
*trimming_sign
)
3342 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3343 FIXME("(%p)->(%p %p): stub\n", This
, trimming
, trimming_sign
);
3347 static HRESULT WINAPI
dwritetextformat1_layout_SetLineSpacing(IDWriteTextFormat1
*iface
, DWRITE_LINE_SPACING_METHOD spacing
,
3348 FLOAT line_spacing
, FLOAT baseline
)
3350 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3351 FIXME("(%p)->(%d %f %f): stub\n", This
, spacing
, line_spacing
, baseline
);
3355 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextformat1_layout_GetTextAlignment(IDWriteTextFormat1
*iface
)
3357 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3358 TRACE("(%p)\n", This
);
3359 return This
->format
.textalignment
;
3362 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextformat1_layout_GetParagraphAlignment(IDWriteTextFormat1
*iface
)
3364 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3365 TRACE("(%p)\n", This
);
3366 return This
->format
.paralign
;
3369 static DWRITE_WORD_WRAPPING WINAPI
dwritetextformat1_layout_GetWordWrapping(IDWriteTextFormat1
*iface
)
3371 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3372 TRACE("(%p)\n", This
);
3373 return This
->format
.wrapping
;
3376 static DWRITE_READING_DIRECTION WINAPI
dwritetextformat1_layout_GetReadingDirection(IDWriteTextFormat1
*iface
)
3378 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3379 TRACE("(%p)\n", This
);
3380 return This
->format
.readingdir
;
3383 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextformat1_layout_GetFlowDirection(IDWriteTextFormat1
*iface
)
3385 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3386 TRACE("(%p)\n", This
);
3387 return This
->format
.flow
;
3390 static FLOAT WINAPI
dwritetextformat1_layout_GetIncrementalTabStop(IDWriteTextFormat1
*iface
)
3392 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3393 FIXME("(%p): stub\n", This
);
3397 static HRESULT WINAPI
dwritetextformat1_layout_GetTrimming(IDWriteTextFormat1
*iface
, DWRITE_TRIMMING
*options
,
3398 IDWriteInlineObject
**trimming_sign
)
3400 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3402 TRACE("(%p)->(%p %p)\n", This
, options
, trimming_sign
);
3404 *options
= This
->format
.trimming
;
3405 *trimming_sign
= This
->format
.trimmingsign
;
3407 IDWriteInlineObject_AddRef(*trimming_sign
);
3411 static HRESULT WINAPI
dwritetextformat1_layout_GetLineSpacing(IDWriteTextFormat1
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
3412 FLOAT
*spacing
, FLOAT
*baseline
)
3414 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3416 TRACE("(%p)->(%p %p %p)\n", This
, method
, spacing
, baseline
);
3418 *method
= This
->format
.spacingmethod
;
3419 *spacing
= This
->format
.spacing
;
3420 *baseline
= This
->format
.baseline
;
3424 static HRESULT WINAPI
dwritetextformat1_layout_GetFontCollection(IDWriteTextFormat1
*iface
, IDWriteFontCollection
**collection
)
3426 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3428 TRACE("(%p)->(%p)\n", This
, collection
);
3430 *collection
= This
->format
.collection
;
3432 IDWriteFontCollection_AddRef(*collection
);
3436 static UINT32 WINAPI
dwritetextformat1_layout_GetFontFamilyNameLength(IDWriteTextFormat1
*iface
)
3438 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3439 TRACE("(%p)\n", This
);
3440 return This
->format
.family_len
;
3443 static HRESULT WINAPI
dwritetextformat1_layout_GetFontFamilyName(IDWriteTextFormat1
*iface
, WCHAR
*name
, UINT32 size
)
3445 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3447 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
3449 if (size
<= This
->format
.family_len
) return E_NOT_SUFFICIENT_BUFFER
;
3450 strcpyW(name
, This
->format
.family_name
);
3454 static DWRITE_FONT_WEIGHT WINAPI
dwritetextformat1_layout_GetFontWeight(IDWriteTextFormat1
*iface
)
3456 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3457 TRACE("(%p)\n", This
);
3458 return This
->format
.weight
;
3461 static DWRITE_FONT_STYLE WINAPI
dwritetextformat1_layout_GetFontStyle(IDWriteTextFormat1
*iface
)
3463 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3464 TRACE("(%p)\n", This
);
3465 return This
->format
.style
;
3468 static DWRITE_FONT_STRETCH WINAPI
dwritetextformat1_layout_GetFontStretch(IDWriteTextFormat1
*iface
)
3470 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3471 TRACE("(%p)\n", This
);
3472 return This
->format
.stretch
;
3475 static FLOAT WINAPI
dwritetextformat1_layout_GetFontSize(IDWriteTextFormat1
*iface
)
3477 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3478 TRACE("(%p)\n", This
);
3479 return This
->format
.fontsize
;
3482 static UINT32 WINAPI
dwritetextformat1_layout_GetLocaleNameLength(IDWriteTextFormat1
*iface
)
3484 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3485 TRACE("(%p)\n", This
);
3486 return This
->format
.locale_len
;
3489 static HRESULT WINAPI
dwritetextformat1_layout_GetLocaleName(IDWriteTextFormat1
*iface
, WCHAR
*name
, UINT32 size
)
3491 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3493 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
3495 if (size
<= This
->format
.locale_len
) return E_NOT_SUFFICIENT_BUFFER
;
3496 strcpyW(name
, This
->format
.locale
);
3500 static HRESULT WINAPI
dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat1
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
3502 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3503 FIXME("(%p)->(%d): stub\n", This
, orientation
);
3507 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat1
*iface
)
3509 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3510 FIXME("(%p): stub\n", This
);
3511 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
3514 static HRESULT WINAPI
dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat1
*iface
, BOOL lastline_wrapping_enabled
)
3516 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3517 FIXME("(%p)->(%d): stub\n", This
, lastline_wrapping_enabled
);
3521 static BOOL WINAPI
dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat1
*iface
)
3523 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3524 FIXME("(%p): stub\n", This
);
3528 static HRESULT WINAPI
dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat1
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
3530 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3531 FIXME("(%p)->(%d): stub\n", This
, alignment
);
3535 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat1
*iface
)
3537 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3538 FIXME("(%p): stub\n", This
);
3539 return DWRITE_OPTICAL_ALIGNMENT_NONE
;
3542 static HRESULT WINAPI
dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat1
*iface
, IDWriteFontFallback
*fallback
)
3544 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3545 TRACE("(%p)->(%p)\n", This
, fallback
);
3546 return IDWriteTextLayout2_SetFontFallback(&This
->IDWriteTextLayout2_iface
, fallback
);
3549 static HRESULT WINAPI
dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat1
*iface
, IDWriteFontFallback
**fallback
)
3551 struct dwrite_textlayout
*This
= impl_layout_form_IDWriteTextFormat1(iface
);
3552 TRACE("(%p)->(%p)\n", This
, fallback
);
3553 return IDWriteTextLayout2_GetFontFallback(&This
->IDWriteTextLayout2_iface
, fallback
);
3556 static const IDWriteTextFormat1Vtbl dwritetextformat1_layout_vtbl
= {
3557 dwritetextformat1_layout_QueryInterface
,
3558 dwritetextformat1_layout_AddRef
,
3559 dwritetextformat1_layout_Release
,
3560 dwritetextformat1_layout_SetTextAlignment
,
3561 dwritetextformat1_layout_SetParagraphAlignment
,
3562 dwritetextformat1_layout_SetWordWrapping
,
3563 dwritetextformat1_layout_SetReadingDirection
,
3564 dwritetextformat1_layout_SetFlowDirection
,
3565 dwritetextformat1_layout_SetIncrementalTabStop
,
3566 dwritetextformat1_layout_SetTrimming
,
3567 dwritetextformat1_layout_SetLineSpacing
,
3568 dwritetextformat1_layout_GetTextAlignment
,
3569 dwritetextformat1_layout_GetParagraphAlignment
,
3570 dwritetextformat1_layout_GetWordWrapping
,
3571 dwritetextformat1_layout_GetReadingDirection
,
3572 dwritetextformat1_layout_GetFlowDirection
,
3573 dwritetextformat1_layout_GetIncrementalTabStop
,
3574 dwritetextformat1_layout_GetTrimming
,
3575 dwritetextformat1_layout_GetLineSpacing
,
3576 dwritetextformat1_layout_GetFontCollection
,
3577 dwritetextformat1_layout_GetFontFamilyNameLength
,
3578 dwritetextformat1_layout_GetFontFamilyName
,
3579 dwritetextformat1_layout_GetFontWeight
,
3580 dwritetextformat1_layout_GetFontStyle
,
3581 dwritetextformat1_layout_GetFontStretch
,
3582 dwritetextformat1_layout_GetFontSize
,
3583 dwritetextformat1_layout_GetLocaleNameLength
,
3584 dwritetextformat1_layout_GetLocaleName
,
3585 dwritetextformat1_layout_SetVerticalGlyphOrientation
,
3586 dwritetextformat1_layout_GetVerticalGlyphOrientation
,
3587 dwritetextformat1_layout_SetLastLineWrapping
,
3588 dwritetextformat1_layout_GetLastLineWrapping
,
3589 dwritetextformat1_layout_SetOpticalAlignment
,
3590 dwritetextformat1_layout_GetOpticalAlignment
,
3591 dwritetextformat1_layout_SetFontFallback
,
3592 dwritetextformat1_layout_GetFontFallback
3595 static HRESULT WINAPI
dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink
*iface
,
3596 REFIID riid
, void **obj
)
3598 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSink
) || IsEqualIID(riid
, &IID_IUnknown
)) {
3600 IDWriteTextAnalysisSink_AddRef(iface
);
3605 return E_NOINTERFACE
;
3608 static ULONG WINAPI
dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink
*iface
)
3613 static ULONG WINAPI
dwritetextlayout_sink_Release(IDWriteTextAnalysisSink
*iface
)
3618 static HRESULT WINAPI
dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink
*iface
,
3619 UINT32 position
, UINT32 length
, DWRITE_SCRIPT_ANALYSIS
const* sa
)
3621 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink(iface
);
3622 struct layout_run
*run
;
3624 TRACE("%u %u script=%d\n", position
, length
, sa
->script
);
3626 run
= alloc_layout_run(LAYOUT_RUN_REGULAR
);
3628 return E_OUTOFMEMORY
;
3630 run
->u
.regular
.descr
.string
= &layout
->str
[position
];
3631 run
->u
.regular
.descr
.stringLength
= length
;
3632 run
->u
.regular
.descr
.textPosition
= position
;
3633 run
->u
.regular
.sa
= *sa
;
3634 list_add_tail(&layout
->runs
, &run
->entry
);
3638 static HRESULT WINAPI
dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink
*iface
,
3639 UINT32 position
, UINT32 length
, DWRITE_LINE_BREAKPOINT
const* breakpoints
)
3641 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink(iface
);
3643 if (position
+ length
> layout
->len
)
3646 memcpy(&layout
->nominal_breakpoints
[position
], breakpoints
, length
*sizeof(DWRITE_LINE_BREAKPOINT
));
3650 static HRESULT WINAPI
dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink
*iface
, UINT32 position
,
3651 UINT32 length
, UINT8 explicitLevel
, UINT8 resolvedLevel
)
3653 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink(iface
);
3654 struct layout_run
*cur_run
;
3656 TRACE("%u %u %u %u\n", position
, length
, explicitLevel
, resolvedLevel
);
3658 LIST_FOR_EACH_ENTRY(cur_run
, &layout
->runs
, struct layout_run
, entry
) {
3659 struct regular_layout_run
*cur
= &cur_run
->u
.regular
;
3660 struct layout_run
*run
;
3662 if (cur_run
->kind
== LAYOUT_RUN_INLINE
)
3665 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
3666 if (position
< cur
->descr
.textPosition
|| position
>= cur
->descr
.textPosition
+ cur
->descr
.stringLength
)
3669 /* full hit - just set run level */
3670 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
== length
) {
3671 cur
->run
.bidiLevel
= resolvedLevel
;
3675 /* current run is fully covered, move to next one */
3676 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
< length
) {
3677 cur
->run
.bidiLevel
= resolvedLevel
;
3678 position
+= cur
->descr
.stringLength
;
3679 length
-= cur
->descr
.stringLength
;
3683 /* all fully covered runs are processed at this point, reuse existing run for remaining
3684 reported bidi range and add another run for the rest of original one */
3686 run
= alloc_layout_run(LAYOUT_RUN_REGULAR
);
3688 return E_OUTOFMEMORY
;
3691 run
->u
.regular
.descr
.textPosition
= position
+ length
;
3692 run
->u
.regular
.descr
.stringLength
= cur
->descr
.stringLength
- length
;
3693 run
->u
.regular
.descr
.string
= &layout
->str
[position
+ length
];
3695 /* reduce existing run */
3696 cur
->run
.bidiLevel
= resolvedLevel
;
3697 cur
->descr
.stringLength
= length
;
3699 list_add_after(&cur_run
->entry
, &run
->entry
);
3706 static HRESULT WINAPI
dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink
*iface
,
3707 UINT32 position
, UINT32 length
, IDWriteNumberSubstitution
* substitution
)
3712 static const IDWriteTextAnalysisSinkVtbl dwritetextlayoutsinkvtbl
= {
3713 dwritetextlayout_sink_QueryInterface
,
3714 dwritetextlayout_sink_AddRef
,
3715 dwritetextlayout_sink_Release
,
3716 dwritetextlayout_sink_SetScriptAnalysis
,
3717 dwritetextlayout_sink_SetLineBreakpoints
,
3718 dwritetextlayout_sink_SetBidiLevel
,
3719 dwritetextlayout_sink_SetNumberSubstitution
3722 static HRESULT WINAPI
dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource
*iface
,
3723 REFIID riid
, void **obj
)
3725 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSource
) ||
3726 IsEqualIID(riid
, &IID_IUnknown
))
3729 IDWriteTextAnalysisSource_AddRef(iface
);
3734 return E_NOINTERFACE
;
3737 static ULONG WINAPI
dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource
*iface
)
3742 static ULONG WINAPI
dwritetextlayout_source_Release(IDWriteTextAnalysisSource
*iface
)
3747 static HRESULT WINAPI
dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource
*iface
,
3748 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
3750 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource(iface
);
3752 TRACE("(%p)->(%u %p %p)\n", layout
, position
, text
, text_len
);
3754 if (position
< layout
->len
) {
3755 *text
= &layout
->str
[position
];
3756 *text_len
= layout
->len
- position
;
3766 static HRESULT WINAPI
dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource
*iface
,
3767 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
3769 FIXME("%u %p %p: stub\n", position
, text
, text_len
);
3773 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource
*iface
)
3775 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource(iface
);
3776 return IDWriteTextLayout2_GetReadingDirection(&layout
->IDWriteTextLayout2_iface
);
3779 static HRESULT WINAPI
dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource
*iface
,
3780 UINT32 position
, UINT32
* text_len
, WCHAR
const** locale
)
3782 FIXME("%u %p %p: stub\n", position
, text_len
, locale
);
3786 static HRESULT WINAPI
dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource
*iface
,
3787 UINT32 position
, UINT32
* text_len
, IDWriteNumberSubstitution
**substitution
)
3789 FIXME("%u %p %p: stub\n", position
, text_len
, substitution
);
3793 static const IDWriteTextAnalysisSourceVtbl dwritetextlayoutsourcevtbl
= {
3794 dwritetextlayout_source_QueryInterface
,
3795 dwritetextlayout_source_AddRef
,
3796 dwritetextlayout_source_Release
,
3797 dwritetextlayout_source_GetTextAtPosition
,
3798 dwritetextlayout_source_GetTextBeforePosition
,
3799 dwritetextlayout_source_GetParagraphReadingDirection
,
3800 dwritetextlayout_source_GetLocaleName
,
3801 dwritetextlayout_source_GetNumberSubstitution
3804 static HRESULT
layout_format_from_textformat(struct dwrite_textlayout
*layout
, IDWriteTextFormat
*format
)
3806 IDWriteTextFormat1
*format1
;
3810 layout
->format
.weight
= IDWriteTextFormat_GetFontWeight(format
);
3811 layout
->format
.style
= IDWriteTextFormat_GetFontStyle(format
);
3812 layout
->format
.stretch
= IDWriteTextFormat_GetFontStretch(format
);
3813 layout
->format
.fontsize
= IDWriteTextFormat_GetFontSize(format
);
3814 layout
->format
.textalignment
= IDWriteTextFormat_GetTextAlignment(format
);
3815 layout
->format
.paralign
= IDWriteTextFormat_GetParagraphAlignment(format
);
3816 layout
->format
.wrapping
= IDWriteTextFormat_GetWordWrapping(format
);
3817 layout
->format
.readingdir
= IDWriteTextFormat_GetReadingDirection(format
);
3818 layout
->format
.flow
= IDWriteTextFormat_GetFlowDirection(format
);
3819 layout
->format
.fallback
= NULL
;
3820 hr
= IDWriteTextFormat_GetLineSpacing(format
, &layout
->format
.spacingmethod
,
3821 &layout
->format
.spacing
, &layout
->format
.baseline
);
3825 hr
= IDWriteTextFormat_GetTrimming(format
, &layout
->format
.trimming
, &layout
->format
.trimmingsign
);
3829 /* locale name and length */
3830 len
= IDWriteTextFormat_GetLocaleNameLength(format
);
3831 layout
->format
.locale
= heap_alloc((len
+1)*sizeof(WCHAR
));
3832 if (!layout
->format
.locale
)
3833 return E_OUTOFMEMORY
;
3835 hr
= IDWriteTextFormat_GetLocaleName(format
, layout
->format
.locale
, len
+1);
3838 layout
->format
.locale_len
= len
;
3840 /* font family name and length */
3841 len
= IDWriteTextFormat_GetFontFamilyNameLength(format
);
3842 layout
->format
.family_name
= heap_alloc((len
+1)*sizeof(WCHAR
));
3843 if (!layout
->format
.family_name
)
3844 return E_OUTOFMEMORY
;
3846 hr
= IDWriteTextFormat_GetFontFamilyName(format
, layout
->format
.family_name
, len
+1);
3849 layout
->format
.family_len
= len
;
3851 hr
= IDWriteTextFormat_QueryInterface(format
, &IID_IDWriteTextFormat1
, (void**)&format1
);
3853 layout
->format
.vertical_orientation
= IDWriteTextFormat1_GetVerticalGlyphOrientation(format1
);
3854 IDWriteTextFormat1_GetFontFallback(format1
, &layout
->format
.fallback
);
3855 IDWriteTextFormat1_Release(format1
);
3858 layout
->format
.vertical_orientation
= DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
3860 return IDWriteTextFormat_GetFontCollection(format
, &layout
->format
.collection
);
3863 static HRESULT
init_textlayout(const WCHAR
*str
, UINT32 len
, IDWriteTextFormat
*format
, FLOAT maxwidth
, FLOAT maxheight
, struct dwrite_textlayout
*layout
)
3865 struct layout_range_header
*range
, *strike
, *effect
, *spacing
;
3866 DWRITE_TEXT_RANGE r
= { 0, ~0u };
3869 layout
->IDWriteTextLayout2_iface
.lpVtbl
= &dwritetextlayoutvtbl
;
3870 layout
->IDWriteTextFormat1_iface
.lpVtbl
= &dwritetextformat1_layout_vtbl
;
3871 layout
->IDWriteTextAnalysisSink_iface
.lpVtbl
= &dwritetextlayoutsinkvtbl
;
3872 layout
->IDWriteTextAnalysisSource_iface
.lpVtbl
= &dwritetextlayoutsourcevtbl
;
3875 layout
->recompute
= RECOMPUTE_EVERYTHING
;
3876 layout
->nominal_breakpoints
= NULL
;
3877 layout
->actual_breakpoints
= NULL
;
3878 layout
->cluster_count
= 0;
3879 layout
->clustermetrics
= NULL
;
3880 layout
->clusters
= NULL
;
3881 layout
->lines
= NULL
;
3882 layout
->line_alloc
= 0;
3883 layout
->minwidth
= 0.0;
3884 list_init(&layout
->eruns
);
3885 list_init(&layout
->inlineobjects
);
3886 list_init(&layout
->strikethrough
);
3887 list_init(&layout
->runs
);
3888 list_init(&layout
->ranges
);
3889 list_init(&layout
->strike_ranges
);
3890 list_init(&layout
->effects
);
3891 list_init(&layout
->spacing
);
3892 memset(&layout
->format
, 0, sizeof(layout
->format
));
3893 memset(&layout
->metrics
, 0, sizeof(layout
->metrics
));
3894 layout
->metrics
.layoutWidth
= maxwidth
;
3895 layout
->metrics
.layoutHeight
= maxheight
;
3897 layout
->gdicompatible
= FALSE
;
3898 layout
->pixels_per_dip
= 0.0;
3899 layout
->use_gdi_natural
= FALSE
;
3900 memset(&layout
->transform
, 0, sizeof(layout
->transform
));
3902 layout
->str
= heap_strdupnW(str
, len
);
3903 if (len
&& !layout
->str
) {
3908 hr
= layout_format_from_textformat(layout
, format
);
3912 range
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_REGULAR
);
3913 strike
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_STRIKETHROUGH
);
3914 effect
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_EFFECT
);
3915 spacing
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_SPACING
);
3916 if (!range
|| !strike
|| !effect
|| !spacing
) {
3917 free_layout_range(range
);
3918 free_layout_range(strike
);
3919 free_layout_range(effect
);
3920 free_layout_range(spacing
);
3925 list_add_head(&layout
->ranges
, &range
->entry
);
3926 list_add_head(&layout
->strike_ranges
, &strike
->entry
);
3927 list_add_head(&layout
->effects
, &effect
->entry
);
3928 list_add_head(&layout
->spacing
, &spacing
->entry
);
3932 IDWriteTextLayout2_Release(&layout
->IDWriteTextLayout2_iface
);
3936 HRESULT
create_textlayout(const WCHAR
*str
, UINT32 len
, IDWriteTextFormat
*format
, FLOAT maxwidth
, FLOAT maxheight
, IDWriteTextLayout
**ret
)
3938 struct dwrite_textlayout
*layout
;
3943 layout
= heap_alloc(sizeof(struct dwrite_textlayout
));
3944 if (!layout
) return E_OUTOFMEMORY
;
3946 hr
= init_textlayout(str
, len
, format
, maxwidth
, maxheight
, layout
);
3948 *ret
= (IDWriteTextLayout
*)&layout
->IDWriteTextLayout2_iface
;
3953 HRESULT
create_gdicompat_textlayout(const WCHAR
*str
, UINT32 len
, IDWriteTextFormat
*format
, FLOAT maxwidth
, FLOAT maxheight
,
3954 FLOAT pixels_per_dip
, const DWRITE_MATRIX
*transform
, BOOL use_gdi_natural
, IDWriteTextLayout
**ret
)
3956 struct dwrite_textlayout
*layout
;
3961 layout
= heap_alloc(sizeof(struct dwrite_textlayout
));
3962 if (!layout
) return E_OUTOFMEMORY
;
3964 hr
= init_textlayout(str
, len
, format
, maxwidth
, maxheight
, layout
);
3966 /* set gdi-specific properties */
3967 layout
->gdicompatible
= TRUE
;
3968 layout
->pixels_per_dip
= pixels_per_dip
;
3969 layout
->use_gdi_natural
= use_gdi_natural
;
3970 layout
->transform
= transform
? *transform
: identity
;
3972 *ret
= (IDWriteTextLayout
*)&layout
->IDWriteTextLayout2_iface
;
3978 static HRESULT WINAPI
dwritetrimmingsign_QueryInterface(IDWriteInlineObject
*iface
, REFIID riid
, void **obj
)
3980 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
3982 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
3984 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDWriteInlineObject
)) {
3986 IDWriteInlineObject_AddRef(iface
);
3991 return E_NOINTERFACE
;
3994 static ULONG WINAPI
dwritetrimmingsign_AddRef(IDWriteInlineObject
*iface
)
3996 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
3997 ULONG ref
= InterlockedIncrement(&This
->ref
);
3998 TRACE("(%p)->(%d)\n", This
, ref
);
4002 static ULONG WINAPI
dwritetrimmingsign_Release(IDWriteInlineObject
*iface
)
4004 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
4005 ULONG ref
= InterlockedDecrement(&This
->ref
);
4007 TRACE("(%p)->(%d)\n", This
, ref
);
4010 IDWriteTextLayout_Release(This
->layout
);
4017 static HRESULT WINAPI
dwritetrimmingsign_Draw(IDWriteInlineObject
*iface
, void *context
, IDWriteTextRenderer
*renderer
,
4018 FLOAT originX
, FLOAT originY
, BOOL is_sideways
, BOOL is_rtl
, IUnknown
*effect
)
4020 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
4021 DWRITE_TEXT_RANGE range
= { 0, ~0u };
4023 TRACE("(%p)->(%p %p %.2f %.2f %d %d %p)\n", This
, context
, renderer
, originX
, originY
, is_sideways
, is_rtl
, effect
);
4025 IDWriteTextLayout_SetDrawingEffect(This
->layout
, effect
, range
);
4026 return IDWriteTextLayout_Draw(This
->layout
, context
, renderer
, originX
, originY
);
4029 static HRESULT WINAPI
dwritetrimmingsign_GetMetrics(IDWriteInlineObject
*iface
, DWRITE_INLINE_OBJECT_METRICS
*ret
)
4031 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
4032 DWRITE_TEXT_METRICS metrics
;
4035 TRACE("(%p)->(%p)\n", This
, ret
);
4037 hr
= IDWriteTextLayout_GetMetrics(This
->layout
, &metrics
);
4039 memset(ret
, 0, sizeof(*ret
));
4043 ret
->width
= metrics
.width
;
4045 ret
->baseline
= 0.0;
4046 ret
->supportsSideways
= FALSE
;
4050 static HRESULT WINAPI
dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject
*iface
, DWRITE_OVERHANG_METRICS
*overhangs
)
4052 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
4053 FIXME("(%p)->(%p): stub\n", This
, overhangs
);
4057 static HRESULT WINAPI
dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject
*iface
, DWRITE_BREAK_CONDITION
*before
,
4058 DWRITE_BREAK_CONDITION
*after
)
4060 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
4062 TRACE("(%p)->(%p %p)\n", This
, before
, after
);
4064 *before
= *after
= DWRITE_BREAK_CONDITION_NEUTRAL
;
4068 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl
= {
4069 dwritetrimmingsign_QueryInterface
,
4070 dwritetrimmingsign_AddRef
,
4071 dwritetrimmingsign_Release
,
4072 dwritetrimmingsign_Draw
,
4073 dwritetrimmingsign_GetMetrics
,
4074 dwritetrimmingsign_GetOverhangMetrics
,
4075 dwritetrimmingsign_GetBreakConditions
4078 static inline BOOL
is_reading_direction_horz(DWRITE_READING_DIRECTION direction
)
4080 return (direction
== DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
) ||
4081 (direction
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
);
4084 static inline BOOL
is_reading_direction_vert(DWRITE_READING_DIRECTION direction
)
4086 return (direction
== DWRITE_READING_DIRECTION_TOP_TO_BOTTOM
) ||
4087 (direction
== DWRITE_READING_DIRECTION_BOTTOM_TO_TOP
);
4090 static inline BOOL
is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction
)
4092 return (direction
== DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT
) ||
4093 (direction
== DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT
);
4096 static inline BOOL
is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction
)
4098 return (direction
== DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM
) ||
4099 (direction
== DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP
);
4102 HRESULT
create_trimmingsign(IDWriteFactory2
*factory
, IDWriteTextFormat
*format
, IDWriteInlineObject
**sign
)
4104 static const WCHAR ellipsisW
= 0x2026;
4105 struct dwrite_trimmingsign
*This
;
4106 DWRITE_READING_DIRECTION reading
;
4107 DWRITE_FLOW_DIRECTION flow
;
4112 /* Validate reading/flow direction here, layout creation won't complain about
4113 invalid combinations. */
4114 reading
= IDWriteTextFormat_GetReadingDirection(format
);
4115 flow
= IDWriteTextFormat_GetFlowDirection(format
);
4117 if ((is_reading_direction_horz(reading
) && is_flow_direction_horz(flow
)) ||
4118 (is_reading_direction_vert(reading
) && is_flow_direction_vert(flow
)))
4119 return DWRITE_E_FLOWDIRECTIONCONFLICTS
;
4121 This
= heap_alloc(sizeof(*This
));
4123 return E_OUTOFMEMORY
;
4125 This
->IDWriteInlineObject_iface
.lpVtbl
= &dwritetrimmingsignvtbl
;
4128 hr
= IDWriteFactory2_CreateTextLayout(factory
, &ellipsisW
, 1, format
, 0.0, 0.0, &This
->layout
);
4134 IDWriteTextLayout_SetWordWrapping(This
->layout
, DWRITE_WORD_WRAPPING_NO_WRAP
);
4135 *sign
= &This
->IDWriteInlineObject_iface
;
4140 static HRESULT WINAPI
dwritetextformat_QueryInterface(IDWriteTextFormat1
*iface
, REFIID riid
, void **obj
)
4142 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4144 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
4146 if (IsEqualIID(riid
, &IID_IDWriteTextFormat1
) ||
4147 IsEqualIID(riid
, &IID_IDWriteTextFormat
) ||
4148 IsEqualIID(riid
, &IID_IUnknown
))
4151 IDWriteTextFormat1_AddRef(iface
);
4157 return E_NOINTERFACE
;
4160 static ULONG WINAPI
dwritetextformat_AddRef(IDWriteTextFormat1
*iface
)
4162 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4163 ULONG ref
= InterlockedIncrement(&This
->ref
);
4164 TRACE("(%p)->(%d)\n", This
, ref
);
4168 static ULONG WINAPI
dwritetextformat_Release(IDWriteTextFormat1
*iface
)
4170 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4171 ULONG ref
= InterlockedDecrement(&This
->ref
);
4173 TRACE("(%p)->(%d)\n", This
, ref
);
4177 release_format_data(&This
->format
);
4184 static HRESULT WINAPI
dwritetextformat_SetTextAlignment(IDWriteTextFormat1
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
4186 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4187 TRACE("(%p)->(%d)\n", This
, alignment
);
4188 return format_set_textalignment(&This
->format
, alignment
, NULL
);
4191 static HRESULT WINAPI
dwritetextformat_SetParagraphAlignment(IDWriteTextFormat1
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
4193 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4194 TRACE("(%p)->(%d)\n", This
, alignment
);
4195 return format_set_paralignment(&This
->format
, alignment
, NULL
);
4198 static HRESULT WINAPI
dwritetextformat_SetWordWrapping(IDWriteTextFormat1
*iface
, DWRITE_WORD_WRAPPING wrapping
)
4200 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4201 TRACE("(%p)->(%d)\n", This
, wrapping
);
4202 return format_set_wordwrapping(&This
->format
, wrapping
, NULL
);
4205 static HRESULT WINAPI
dwritetextformat_SetReadingDirection(IDWriteTextFormat1
*iface
, DWRITE_READING_DIRECTION direction
)
4207 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4208 TRACE("(%p)->(%d)\n", This
, direction
);
4209 return format_set_readingdirection(&This
->format
, direction
, NULL
);
4212 static HRESULT WINAPI
dwritetextformat_SetFlowDirection(IDWriteTextFormat1
*iface
, DWRITE_FLOW_DIRECTION direction
)
4214 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4216 TRACE("(%p)->(%d)\n", This
, direction
);
4218 if ((UINT32
)direction
> DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT
)
4219 return E_INVALIDARG
;
4221 This
->format
.flow
= direction
;
4225 static HRESULT WINAPI
dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat1
*iface
, FLOAT tabstop
)
4227 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4228 FIXME("(%p)->(%f): stub\n", This
, tabstop
);
4232 static HRESULT WINAPI
dwritetextformat_SetTrimming(IDWriteTextFormat1
*iface
, DWRITE_TRIMMING
const *trimming
,
4233 IDWriteInlineObject
*trimming_sign
)
4235 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4236 TRACE("(%p)->(%p %p)\n", This
, trimming
, trimming_sign
);
4238 This
->format
.trimming
= *trimming
;
4239 if (This
->format
.trimmingsign
)
4240 IDWriteInlineObject_Release(This
->format
.trimmingsign
);
4241 This
->format
.trimmingsign
= trimming_sign
;
4242 if (This
->format
.trimmingsign
)
4243 IDWriteInlineObject_AddRef(This
->format
.trimmingsign
);
4247 static HRESULT WINAPI
dwritetextformat_SetLineSpacing(IDWriteTextFormat1
*iface
, DWRITE_LINE_SPACING_METHOD method
,
4248 FLOAT spacing
, FLOAT baseline
)
4250 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4252 TRACE("(%p)->(%d %f %f)\n", This
, method
, spacing
, baseline
);
4254 if (spacing
< 0.0 || (UINT32
)method
> DWRITE_LINE_SPACING_METHOD_UNIFORM
)
4255 return E_INVALIDARG
;
4257 This
->format
.spacingmethod
= method
;
4258 This
->format
.spacing
= spacing
;
4259 This
->format
.baseline
= baseline
;
4263 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextformat_GetTextAlignment(IDWriteTextFormat1
*iface
)
4265 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4266 TRACE("(%p)\n", This
);
4267 return This
->format
.textalignment
;
4270 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextformat_GetParagraphAlignment(IDWriteTextFormat1
*iface
)
4272 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4273 TRACE("(%p)\n", This
);
4274 return This
->format
.paralign
;
4277 static DWRITE_WORD_WRAPPING WINAPI
dwritetextformat_GetWordWrapping(IDWriteTextFormat1
*iface
)
4279 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4280 TRACE("(%p)\n", This
);
4281 return This
->format
.wrapping
;
4284 static DWRITE_READING_DIRECTION WINAPI
dwritetextformat_GetReadingDirection(IDWriteTextFormat1
*iface
)
4286 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4287 TRACE("(%p)\n", This
);
4288 return This
->format
.readingdir
;
4291 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextformat_GetFlowDirection(IDWriteTextFormat1
*iface
)
4293 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4294 TRACE("(%p)\n", This
);
4295 return This
->format
.flow
;
4298 static FLOAT WINAPI
dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat1
*iface
)
4300 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4301 FIXME("(%p): stub\n", This
);
4305 static HRESULT WINAPI
dwritetextformat_GetTrimming(IDWriteTextFormat1
*iface
, DWRITE_TRIMMING
*options
,
4306 IDWriteInlineObject
**trimming_sign
)
4308 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4309 TRACE("(%p)->(%p %p)\n", This
, options
, trimming_sign
);
4311 *options
= This
->format
.trimming
;
4312 if ((*trimming_sign
= This
->format
.trimmingsign
))
4313 IDWriteInlineObject_AddRef(*trimming_sign
);
4318 static HRESULT WINAPI
dwritetextformat_GetLineSpacing(IDWriteTextFormat1
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
4319 FLOAT
*spacing
, FLOAT
*baseline
)
4321 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4322 TRACE("(%p)->(%p %p %p)\n", This
, method
, spacing
, baseline
);
4324 *method
= This
->format
.spacingmethod
;
4325 *spacing
= This
->format
.spacing
;
4326 *baseline
= This
->format
.baseline
;
4330 static HRESULT WINAPI
dwritetextformat_GetFontCollection(IDWriteTextFormat1
*iface
, IDWriteFontCollection
**collection
)
4332 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4334 TRACE("(%p)->(%p)\n", This
, collection
);
4336 *collection
= This
->format
.collection
;
4337 IDWriteFontCollection_AddRef(*collection
);
4342 static UINT32 WINAPI
dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat1
*iface
)
4344 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4345 TRACE("(%p)\n", This
);
4346 return This
->format
.family_len
;
4349 static HRESULT WINAPI
dwritetextformat_GetFontFamilyName(IDWriteTextFormat1
*iface
, WCHAR
*name
, UINT32 size
)
4351 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4353 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
4355 if (size
<= This
->format
.family_len
) return E_NOT_SUFFICIENT_BUFFER
;
4356 strcpyW(name
, This
->format
.family_name
);
4360 static DWRITE_FONT_WEIGHT WINAPI
dwritetextformat_GetFontWeight(IDWriteTextFormat1
*iface
)
4362 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4363 TRACE("(%p)\n", This
);
4364 return This
->format
.weight
;
4367 static DWRITE_FONT_STYLE WINAPI
dwritetextformat_GetFontStyle(IDWriteTextFormat1
*iface
)
4369 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4370 TRACE("(%p)\n", This
);
4371 return This
->format
.style
;
4374 static DWRITE_FONT_STRETCH WINAPI
dwritetextformat_GetFontStretch(IDWriteTextFormat1
*iface
)
4376 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4377 TRACE("(%p)\n", This
);
4378 return This
->format
.stretch
;
4381 static FLOAT WINAPI
dwritetextformat_GetFontSize(IDWriteTextFormat1
*iface
)
4383 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4384 TRACE("(%p)\n", This
);
4385 return This
->format
.fontsize
;
4388 static UINT32 WINAPI
dwritetextformat_GetLocaleNameLength(IDWriteTextFormat1
*iface
)
4390 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4391 TRACE("(%p)\n", This
);
4392 return This
->format
.locale_len
;
4395 static HRESULT WINAPI
dwritetextformat_GetLocaleName(IDWriteTextFormat1
*iface
, WCHAR
*name
, UINT32 size
)
4397 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4399 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
4401 if (size
<= This
->format
.locale_len
) return E_NOT_SUFFICIENT_BUFFER
;
4402 strcpyW(name
, This
->format
.locale
);
4406 static HRESULT WINAPI
dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat1
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
4408 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4410 TRACE("(%p)->(%d)\n", This
, orientation
);
4412 if ((UINT32
)orientation
> DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED
)
4413 return E_INVALIDARG
;
4415 This
->format
.vertical_orientation
= orientation
;
4419 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat1
*iface
)
4421 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4422 TRACE("(%p)\n", This
);
4423 return This
->format
.vertical_orientation
;
4426 static HRESULT WINAPI
dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat1
*iface
, BOOL lastline_wrapping_enabled
)
4428 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4429 FIXME("(%p)->(%d): stub\n", This
, lastline_wrapping_enabled
);
4433 static BOOL WINAPI
dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat1
*iface
)
4435 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4436 FIXME("(%p): stub\n", This
);
4440 static HRESULT WINAPI
dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat1
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
4442 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4443 FIXME("(%p)->(%d): stub\n", This
, alignment
);
4447 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat1
*iface
)
4449 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4450 FIXME("(%p): stub\n", This
);
4451 return DWRITE_OPTICAL_ALIGNMENT_NONE
;
4454 static HRESULT WINAPI
dwritetextformat1_SetFontFallback(IDWriteTextFormat1
*iface
, IDWriteFontFallback
*fallback
)
4456 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4457 TRACE("(%p)->(%p)\n", This
, fallback
);
4458 return set_fontfallback_for_format(&This
->format
, fallback
);
4461 static HRESULT WINAPI
dwritetextformat1_GetFontFallback(IDWriteTextFormat1
*iface
, IDWriteFontFallback
**fallback
)
4463 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat1(iface
);
4464 TRACE("(%p)->(%p)\n", This
, fallback
);
4465 return get_fontfallback_from_format(&This
->format
, fallback
);
4468 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl
= {
4469 dwritetextformat_QueryInterface
,
4470 dwritetextformat_AddRef
,
4471 dwritetextformat_Release
,
4472 dwritetextformat_SetTextAlignment
,
4473 dwritetextformat_SetParagraphAlignment
,
4474 dwritetextformat_SetWordWrapping
,
4475 dwritetextformat_SetReadingDirection
,
4476 dwritetextformat_SetFlowDirection
,
4477 dwritetextformat_SetIncrementalTabStop
,
4478 dwritetextformat_SetTrimming
,
4479 dwritetextformat_SetLineSpacing
,
4480 dwritetextformat_GetTextAlignment
,
4481 dwritetextformat_GetParagraphAlignment
,
4482 dwritetextformat_GetWordWrapping
,
4483 dwritetextformat_GetReadingDirection
,
4484 dwritetextformat_GetFlowDirection
,
4485 dwritetextformat_GetIncrementalTabStop
,
4486 dwritetextformat_GetTrimming
,
4487 dwritetextformat_GetLineSpacing
,
4488 dwritetextformat_GetFontCollection
,
4489 dwritetextformat_GetFontFamilyNameLength
,
4490 dwritetextformat_GetFontFamilyName
,
4491 dwritetextformat_GetFontWeight
,
4492 dwritetextformat_GetFontStyle
,
4493 dwritetextformat_GetFontStretch
,
4494 dwritetextformat_GetFontSize
,
4495 dwritetextformat_GetLocaleNameLength
,
4496 dwritetextformat_GetLocaleName
,
4497 dwritetextformat1_SetVerticalGlyphOrientation
,
4498 dwritetextformat1_GetVerticalGlyphOrientation
,
4499 dwritetextformat1_SetLastLineWrapping
,
4500 dwritetextformat1_GetLastLineWrapping
,
4501 dwritetextformat1_SetOpticalAlignment
,
4502 dwritetextformat1_GetOpticalAlignment
,
4503 dwritetextformat1_SetFontFallback
,
4504 dwritetextformat1_GetFontFallback
4507 HRESULT
create_textformat(const WCHAR
*family_name
, IDWriteFontCollection
*collection
, DWRITE_FONT_WEIGHT weight
, DWRITE_FONT_STYLE style
,
4508 DWRITE_FONT_STRETCH stretch
, FLOAT size
, const WCHAR
*locale
, IDWriteTextFormat
**format
)
4510 struct dwrite_textformat
*This
;
4514 This
= heap_alloc(sizeof(struct dwrite_textformat
));
4515 if (!This
) return E_OUTOFMEMORY
;
4517 This
->IDWriteTextFormat1_iface
.lpVtbl
= &dwritetextformatvtbl
;
4519 This
->format
.family_name
= heap_strdupW(family_name
);
4520 This
->format
.family_len
= strlenW(family_name
);
4521 This
->format
.locale
= heap_strdupW(locale
);
4522 This
->format
.locale_len
= strlenW(locale
);
4523 This
->format
.weight
= weight
;
4524 This
->format
.style
= style
;
4525 This
->format
.fontsize
= size
;
4526 This
->format
.stretch
= stretch
;
4527 This
->format
.textalignment
= DWRITE_TEXT_ALIGNMENT_LEADING
;
4528 This
->format
.paralign
= DWRITE_PARAGRAPH_ALIGNMENT_NEAR
;
4529 This
->format
.wrapping
= DWRITE_WORD_WRAPPING_WRAP
;
4530 This
->format
.readingdir
= DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
;
4531 This
->format
.flow
= DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM
;
4532 This
->format
.spacingmethod
= DWRITE_LINE_SPACING_METHOD_DEFAULT
;
4533 This
->format
.vertical_orientation
= DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
4534 This
->format
.spacing
= 0.0;
4535 This
->format
.baseline
= 0.0;
4536 This
->format
.trimming
.granularity
= DWRITE_TRIMMING_GRANULARITY_NONE
;
4537 This
->format
.trimming
.delimiter
= 0;
4538 This
->format
.trimming
.delimiterCount
= 0;
4539 This
->format
.trimmingsign
= NULL
;
4540 This
->format
.collection
= collection
;
4541 This
->format
.fallback
= NULL
;
4542 IDWriteFontCollection_AddRef(collection
);
4544 *format
= (IDWriteTextFormat
*)&This
->IDWriteTextFormat1_iface
;
4549 static HRESULT WINAPI
dwritetypography_QueryInterface(IDWriteTypography
*iface
, REFIID riid
, void **obj
)
4551 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
4553 TRACE("(%p)->(%s %p)\n", typography
, debugstr_guid(riid
), obj
);
4555 if (IsEqualIID(riid
, &IID_IDWriteTypography
) || IsEqualIID(riid
, &IID_IUnknown
)) {
4557 IDWriteTypography_AddRef(iface
);
4563 return E_NOINTERFACE
;
4566 static ULONG WINAPI
dwritetypography_AddRef(IDWriteTypography
*iface
)
4568 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
4569 ULONG ref
= InterlockedIncrement(&typography
->ref
);
4570 TRACE("(%p)->(%d)\n", typography
, ref
);
4574 static ULONG WINAPI
dwritetypography_Release(IDWriteTypography
*iface
)
4576 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
4577 ULONG ref
= InterlockedDecrement(&typography
->ref
);
4579 TRACE("(%p)->(%d)\n", typography
, ref
);
4582 heap_free(typography
->features
);
4583 heap_free(typography
);
4589 static HRESULT WINAPI
dwritetypography_AddFontFeature(IDWriteTypography
*iface
, DWRITE_FONT_FEATURE feature
)
4591 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
4593 TRACE("(%p)->(%x %u)\n", typography
, feature
.nameTag
, feature
.parameter
);
4595 if (typography
->count
== typography
->allocated
) {
4596 DWRITE_FONT_FEATURE
*ptr
= heap_realloc(typography
->features
, 2*typography
->allocated
*sizeof(DWRITE_FONT_FEATURE
));
4598 return E_OUTOFMEMORY
;
4600 typography
->features
= ptr
;
4601 typography
->allocated
*= 2;
4604 typography
->features
[typography
->count
++] = feature
;
4608 static UINT32 WINAPI
dwritetypography_GetFontFeatureCount(IDWriteTypography
*iface
)
4610 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
4611 TRACE("(%p)\n", typography
);
4612 return typography
->count
;
4615 static HRESULT WINAPI
dwritetypography_GetFontFeature(IDWriteTypography
*iface
, UINT32 index
, DWRITE_FONT_FEATURE
*feature
)
4617 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
4619 TRACE("(%p)->(%u %p)\n", typography
, index
, feature
);
4621 if (index
>= typography
->count
)
4622 return E_INVALIDARG
;
4624 *feature
= typography
->features
[index
];
4628 static const IDWriteTypographyVtbl dwritetypographyvtbl
= {
4629 dwritetypography_QueryInterface
,
4630 dwritetypography_AddRef
,
4631 dwritetypography_Release
,
4632 dwritetypography_AddFontFeature
,
4633 dwritetypography_GetFontFeatureCount
,
4634 dwritetypography_GetFontFeature
4637 HRESULT
create_typography(IDWriteTypography
**ret
)
4639 struct dwrite_typography
*typography
;
4643 typography
= heap_alloc(sizeof(*typography
));
4645 return E_OUTOFMEMORY
;
4647 typography
->IDWriteTypography_iface
.lpVtbl
= &dwritetypographyvtbl
;
4648 typography
->ref
= 1;
4649 typography
->allocated
= 2;
4650 typography
->count
= 0;
4652 typography
->features
= heap_alloc(typography
->allocated
*sizeof(DWRITE_FONT_FEATURE
));
4653 if (!typography
->features
) {
4654 heap_free(typography
);
4655 return E_OUTOFMEMORY
;
4658 *ret
= &typography
->IDWriteTypography_iface
;