ole32: Check buffer bounds when reading storage properties.
[wine.git] / dlls / dwrite / layout.c
blobb9321157a9184fe48585c187923ceb685c5fdd87
1 /*
2 * Text format and layout
4 * Copyright 2012, 2014-2017 Nikolay Sivov for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <math.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "dwrite_private.h"
31 #include "scripts.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
35 struct dwrite_textformat_data {
36 WCHAR *family_name;
37 UINT32 family_len;
38 WCHAR *locale;
39 UINT32 locale_len;
41 DWRITE_FONT_WEIGHT weight;
42 DWRITE_FONT_STYLE style;
43 DWRITE_FONT_STRETCH stretch;
45 DWRITE_PARAGRAPH_ALIGNMENT paralign;
46 DWRITE_READING_DIRECTION readingdir;
47 DWRITE_WORD_WRAPPING wrapping;
48 BOOL last_line_wrapping;
49 DWRITE_TEXT_ALIGNMENT textalignment;
50 DWRITE_FLOW_DIRECTION flow;
51 DWRITE_VERTICAL_GLYPH_ORIENTATION vertical_orientation;
52 DWRITE_OPTICAL_ALIGNMENT optical_alignment;
53 DWRITE_LINE_SPACING spacing;
55 FLOAT fontsize;
56 FLOAT tabstop;
58 DWRITE_TRIMMING trimming;
59 IDWriteInlineObject *trimmingsign;
61 IDWriteFontCollection *collection;
62 IDWriteFontFallback *fallback;
65 enum layout_range_attr_kind {
66 LAYOUT_RANGE_ATTR_WEIGHT,
67 LAYOUT_RANGE_ATTR_STYLE,
68 LAYOUT_RANGE_ATTR_STRETCH,
69 LAYOUT_RANGE_ATTR_FONTSIZE,
70 LAYOUT_RANGE_ATTR_EFFECT,
71 LAYOUT_RANGE_ATTR_INLINE,
72 LAYOUT_RANGE_ATTR_UNDERLINE,
73 LAYOUT_RANGE_ATTR_STRIKETHROUGH,
74 LAYOUT_RANGE_ATTR_PAIR_KERNING,
75 LAYOUT_RANGE_ATTR_FONTCOLL,
76 LAYOUT_RANGE_ATTR_LOCALE,
77 LAYOUT_RANGE_ATTR_FONTFAMILY,
78 LAYOUT_RANGE_ATTR_SPACING,
79 LAYOUT_RANGE_ATTR_TYPOGRAPHY
82 struct layout_range_attr_value {
83 DWRITE_TEXT_RANGE range;
84 union {
85 DWRITE_FONT_WEIGHT weight;
86 DWRITE_FONT_STYLE style;
87 DWRITE_FONT_STRETCH stretch;
88 FLOAT fontsize;
89 IDWriteInlineObject *object;
90 IUnknown *effect;
91 BOOL underline;
92 BOOL strikethrough;
93 BOOL pair_kerning;
94 IDWriteFontCollection *collection;
95 const WCHAR *locale;
96 const WCHAR *fontfamily;
97 struct {
98 FLOAT leading;
99 FLOAT trailing;
100 FLOAT min_advance;
101 } spacing;
102 IDWriteTypography *typography;
103 } u;
106 enum layout_range_kind {
107 LAYOUT_RANGE_REGULAR,
108 LAYOUT_RANGE_UNDERLINE,
109 LAYOUT_RANGE_STRIKETHROUGH,
110 LAYOUT_RANGE_EFFECT,
111 LAYOUT_RANGE_SPACING,
112 LAYOUT_RANGE_TYPOGRAPHY
115 struct layout_range_header {
116 struct list entry;
117 enum layout_range_kind kind;
118 DWRITE_TEXT_RANGE range;
121 struct layout_range {
122 struct layout_range_header h;
123 DWRITE_FONT_WEIGHT weight;
124 DWRITE_FONT_STYLE style;
125 FLOAT fontsize;
126 DWRITE_FONT_STRETCH stretch;
127 IDWriteInlineObject *object;
128 BOOL pair_kerning;
129 IDWriteFontCollection *collection;
130 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
131 WCHAR *fontfamily;
134 struct layout_range_bool {
135 struct layout_range_header h;
136 BOOL value;
139 struct layout_range_iface {
140 struct layout_range_header h;
141 IUnknown *iface;
144 struct layout_range_spacing {
145 struct layout_range_header h;
146 FLOAT leading;
147 FLOAT trailing;
148 FLOAT min_advance;
151 enum layout_run_kind {
152 LAYOUT_RUN_REGULAR,
153 LAYOUT_RUN_INLINE
156 struct inline_object_run {
157 IDWriteInlineObject *object;
158 UINT16 length;
161 struct regular_layout_run {
162 DWRITE_GLYPH_RUN_DESCRIPTION descr;
163 DWRITE_GLYPH_RUN run;
164 DWRITE_SCRIPT_ANALYSIS sa;
165 UINT16 *glyphs;
166 UINT16 *clustermap;
167 FLOAT *advances;
168 DWRITE_GLYPH_OFFSET *offsets;
169 UINT32 glyphcount; /* actual glyph count after shaping, not necessarily the same as reported to Draw() */
172 struct layout_run {
173 struct list entry;
174 enum layout_run_kind kind;
175 union {
176 struct inline_object_run object;
177 struct regular_layout_run regular;
178 } u;
179 FLOAT baseline;
180 FLOAT height;
181 UINT32 start_position; /* run text position in range [0, layout-text-length) */
184 struct layout_effective_run {
185 struct list entry;
186 const struct layout_run *run; /* nominal run this one is based on */
187 UINT32 start; /* relative text position, 0 means first text position of a nominal run */
188 UINT32 length; /* length in codepoints that this run covers */
189 UINT32 glyphcount; /* total glyph count in this run */
190 IUnknown *effect; /* original reference is kept only at range level */
191 D2D1_POINT_2F origin; /* baseline origin */
192 FLOAT align_dx; /* adjustment from text alignment */
193 FLOAT width; /* run width */
194 UINT16 *clustermap; /* effective clustermap, allocated separately, is not reused from nominal map */
195 UINT32 line; /* 0-based line index in line metrics array */
196 BOOL underlined; /* set if this run is underlined */
197 D2D1_RECT_F bbox; /* ink run box, top == bottom means it wasn't estimated yet */
200 struct layout_effective_inline {
201 struct list entry;
202 IDWriteInlineObject *object; /* inline object, set explicitly or added when trimming a line */
203 IUnknown *effect; /* original reference is kept only at range level */
204 FLOAT baseline;
205 D2D1_POINT_2F origin; /* left top corner */
206 FLOAT align_dx; /* adjustment from text alignment */
207 FLOAT width; /* object width as it's reported it */
208 BOOL is_sideways; /* vertical flow direction flag passed to Draw */
209 BOOL is_rtl; /* bidi flag passed to Draw */
210 UINT32 line; /* 0-based line index in line metrics array */
213 struct layout_underline {
214 struct list entry;
215 const struct layout_effective_run *run;
216 DWRITE_UNDERLINE u;
219 struct layout_strikethrough {
220 struct list entry;
221 const struct layout_effective_run *run;
222 DWRITE_STRIKETHROUGH s;
225 struct layout_cluster {
226 const struct layout_run *run; /* link to nominal run this cluster belongs to */
227 UINT32 position; /* relative to run, first cluster has 0 position */
230 struct layout_line
232 float height; /* height based on content */
233 float baseline; /* baseline based on content */
234 DWRITE_LINE_METRICS1 metrics;
237 enum layout_recompute_mask {
238 RECOMPUTE_CLUSTERS = 1 << 0,
239 RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
240 RECOMPUTE_LINES = 1 << 2,
241 RECOMPUTE_OVERHANGS = 1 << 3,
242 RECOMPUTE_LINES_AND_OVERHANGS = RECOMPUTE_LINES | RECOMPUTE_OVERHANGS,
243 RECOMPUTE_EVERYTHING = 0xffff
246 struct dwrite_textlayout
248 IDWriteTextLayout4 IDWriteTextLayout4_iface;
249 IDWriteTextFormat3 IDWriteTextFormat3_iface;
250 IDWriteTextAnalysisSink1 IDWriteTextAnalysisSink1_iface;
251 IDWriteTextAnalysisSource1 IDWriteTextAnalysisSource1_iface;
252 LONG refcount;
254 IDWriteFactory7 *factory;
256 WCHAR *str;
257 UINT32 len;
258 struct dwrite_textformat_data format;
259 struct list strike_ranges;
260 struct list underline_ranges;
261 struct list typographies;
262 struct list effects;
263 struct list spacing;
264 struct list ranges;
265 struct list runs;
266 /* lists ready to use by Draw() */
267 struct list eruns;
268 struct list inlineobjects;
269 struct list underlines;
270 struct list strikethrough;
271 USHORT recompute;
273 DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
274 DWRITE_LINE_BREAKPOINT *actual_breakpoints;
276 struct layout_cluster *clusters;
277 DWRITE_CLUSTER_METRICS *clustermetrics;
278 UINT32 cluster_count;
279 FLOAT minwidth;
281 struct layout_line *lines;
282 size_t lines_size;
284 DWRITE_TEXT_METRICS1 metrics;
285 DWRITE_OVERHANG_METRICS overhangs;
287 DWRITE_MEASURING_MODE measuringmode;
289 /* gdi-compatible layout specifics */
290 FLOAT ppdip;
291 DWRITE_MATRIX transform;
294 struct dwrite_textformat
296 IDWriteTextFormat3 IDWriteTextFormat3_iface;
297 LONG refcount;
298 struct dwrite_textformat_data format;
301 struct dwrite_trimmingsign {
302 IDWriteInlineObject IDWriteInlineObject_iface;
303 LONG ref;
305 IDWriteTextLayout *layout;
308 struct dwrite_typography {
309 IDWriteTypography IDWriteTypography_iface;
310 LONG refcount;
312 DWRITE_FONT_FEATURE *features;
313 size_t capacity;
314 size_t count;
317 static const IDWriteTextFormat3Vtbl dwritetextformatvtbl;
319 static void release_format_data(struct dwrite_textformat_data *data)
321 if (data->collection) IDWriteFontCollection_Release(data->collection);
322 if (data->fallback) IDWriteFontFallback_Release(data->fallback);
323 if (data->trimmingsign) IDWriteInlineObject_Release(data->trimmingsign);
324 heap_free(data->family_name);
325 heap_free(data->locale);
328 static inline struct dwrite_textlayout *impl_from_IDWriteTextLayout4(IDWriteTextLayout4 *iface)
330 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextLayout4_iface);
333 static inline struct dwrite_textlayout *impl_layout_from_IDWriteTextFormat3(IDWriteTextFormat3 *iface)
335 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextFormat3_iface);
338 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSink1(IDWriteTextAnalysisSink1 *iface)
340 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSink1_iface);
343 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSource1(IDWriteTextAnalysisSource1 *iface)
345 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSource1_iface);
348 static inline struct dwrite_textformat *impl_from_IDWriteTextFormat3(IDWriteTextFormat3 *iface)
350 return CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat3_iface);
353 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat*);
355 static inline struct dwrite_trimmingsign *impl_from_IDWriteInlineObject(IDWriteInlineObject *iface)
357 return CONTAINING_RECORD(iface, struct dwrite_trimmingsign, IDWriteInlineObject_iface);
360 static inline struct dwrite_typography *impl_from_IDWriteTypography(IDWriteTypography *iface)
362 return CONTAINING_RECORD(iface, struct dwrite_typography, IDWriteTypography_iface);
365 static inline const char *debugstr_rundescr(const DWRITE_GLYPH_RUN_DESCRIPTION *descr)
367 return wine_dbg_sprintf("[%u,%u)", descr->textPosition, descr->textPosition + descr->stringLength);
370 static inline BOOL is_layout_gdi_compatible(struct dwrite_textlayout *layout)
372 return layout->measuringmode != DWRITE_MEASURING_MODE_NATURAL;
375 static inline HRESULT format_set_textalignment(struct dwrite_textformat_data *format, DWRITE_TEXT_ALIGNMENT alignment,
376 BOOL *changed)
378 if ((UINT32)alignment > DWRITE_TEXT_ALIGNMENT_JUSTIFIED)
379 return E_INVALIDARG;
380 if (changed) *changed = format->textalignment != alignment;
381 format->textalignment = alignment;
382 return S_OK;
385 static inline HRESULT format_set_paralignment(struct dwrite_textformat_data *format,
386 DWRITE_PARAGRAPH_ALIGNMENT alignment, BOOL *changed)
388 if ((UINT32)alignment > DWRITE_PARAGRAPH_ALIGNMENT_CENTER)
389 return E_INVALIDARG;
390 if (changed) *changed = format->paralign != alignment;
391 format->paralign = alignment;
392 return S_OK;
395 static inline HRESULT format_set_readingdirection(struct dwrite_textformat_data *format,
396 DWRITE_READING_DIRECTION direction, BOOL *changed)
398 if ((UINT32)direction > DWRITE_READING_DIRECTION_BOTTOM_TO_TOP)
399 return E_INVALIDARG;
400 if (changed) *changed = format->readingdir != direction;
401 format->readingdir = direction;
402 return S_OK;
405 static inline HRESULT format_set_wordwrapping(struct dwrite_textformat_data *format,
406 DWRITE_WORD_WRAPPING wrapping, BOOL *changed)
408 if ((UINT32)wrapping > DWRITE_WORD_WRAPPING_CHARACTER)
409 return E_INVALIDARG;
410 if (changed) *changed = format->wrapping != wrapping;
411 format->wrapping = wrapping;
412 return S_OK;
415 static inline HRESULT format_set_flowdirection(struct dwrite_textformat_data *format,
416 DWRITE_FLOW_DIRECTION direction, BOOL *changed)
418 if ((UINT32)direction > DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT)
419 return E_INVALIDARG;
420 if (changed) *changed = format->flow != direction;
421 format->flow = direction;
422 return S_OK;
425 static inline HRESULT format_set_trimming(struct dwrite_textformat_data *format,
426 DWRITE_TRIMMING const *trimming, IDWriteInlineObject *trimming_sign, BOOL *changed)
428 if (changed)
429 *changed = FALSE;
431 if ((UINT32)trimming->granularity > DWRITE_TRIMMING_GRANULARITY_WORD)
432 return E_INVALIDARG;
434 if (changed) {
435 *changed = !!memcmp(&format->trimming, trimming, sizeof(*trimming));
436 if (format->trimmingsign != trimming_sign)
437 *changed = TRUE;
440 format->trimming = *trimming;
441 if (format->trimmingsign)
442 IDWriteInlineObject_Release(format->trimmingsign);
443 format->trimmingsign = trimming_sign;
444 if (format->trimmingsign)
445 IDWriteInlineObject_AddRef(format->trimmingsign);
446 return S_OK;
449 static inline HRESULT format_set_linespacing(struct dwrite_textformat_data *format,
450 DWRITE_LINE_SPACING const *spacing, BOOL *changed)
452 if (spacing->height < 0.0f || spacing->leadingBefore < 0.0f || spacing->leadingBefore > 1.0f ||
453 (UINT32)spacing->method > DWRITE_LINE_SPACING_METHOD_PROPORTIONAL)
454 return E_INVALIDARG;
456 if (changed)
457 *changed = memcmp(spacing, &format->spacing, sizeof(*spacing));
459 format->spacing = *spacing;
460 return S_OK;
463 static HRESULT get_fontfallback_from_format(const struct dwrite_textformat_data *format, IDWriteFontFallback **fallback)
465 *fallback = format->fallback;
466 if (*fallback)
467 IDWriteFontFallback_AddRef(*fallback);
468 return S_OK;
471 static HRESULT set_fontfallback_for_format(struct dwrite_textformat_data *format, IDWriteFontFallback *fallback)
473 if (format->fallback)
474 IDWriteFontFallback_Release(format->fallback);
475 format->fallback = fallback;
476 if (fallback)
477 IDWriteFontFallback_AddRef(fallback);
478 return S_OK;
481 static HRESULT format_set_optical_alignment(struct dwrite_textformat_data *format,
482 DWRITE_OPTICAL_ALIGNMENT alignment)
484 if ((UINT32)alignment > DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS)
485 return E_INVALIDARG;
486 format->optical_alignment = alignment;
487 return S_OK;
490 static BOOL is_run_rtl(const struct layout_effective_run *run)
492 return run->run->u.regular.run.bidiLevel & 1;
495 static struct layout_run *alloc_layout_run(enum layout_run_kind kind, UINT32 start_position)
497 struct layout_run *ret;
499 ret = heap_alloc(sizeof(*ret));
500 if (!ret) return NULL;
502 memset(ret, 0, sizeof(*ret));
503 ret->kind = kind;
504 if (kind == LAYOUT_RUN_REGULAR) {
505 ret->u.regular.sa.script = Script_Unknown;
506 ret->u.regular.sa.shapes = DWRITE_SCRIPT_SHAPES_DEFAULT;
508 ret->start_position = start_position;
510 return ret;
513 static void free_layout_runs(struct dwrite_textlayout *layout)
515 struct layout_run *cur, *cur2;
516 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->runs, struct layout_run, entry) {
517 list_remove(&cur->entry);
518 if (cur->kind == LAYOUT_RUN_REGULAR) {
519 if (cur->u.regular.run.fontFace)
520 IDWriteFontFace_Release(cur->u.regular.run.fontFace);
521 heap_free(cur->u.regular.glyphs);
522 heap_free(cur->u.regular.clustermap);
523 heap_free(cur->u.regular.advances);
524 heap_free(cur->u.regular.offsets);
526 heap_free(cur);
530 static void free_layout_eruns(struct dwrite_textlayout *layout)
532 struct layout_effective_inline *in, *in2;
533 struct layout_effective_run *cur, *cur2;
534 struct layout_strikethrough *s, *s2;
535 struct layout_underline *u, *u2;
537 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->eruns, struct layout_effective_run, entry) {
538 list_remove(&cur->entry);
539 heap_free(cur->clustermap);
540 heap_free(cur);
543 LIST_FOR_EACH_ENTRY_SAFE(in, in2, &layout->inlineobjects, struct layout_effective_inline, entry) {
544 list_remove(&in->entry);
545 heap_free(in);
548 LIST_FOR_EACH_ENTRY_SAFE(u, u2, &layout->underlines, struct layout_underline, entry) {
549 list_remove(&u->entry);
550 heap_free(u);
553 LIST_FOR_EACH_ENTRY_SAFE(s, s2, &layout->strikethrough, struct layout_strikethrough, entry) {
554 list_remove(&s->entry);
555 heap_free(s);
559 /* Used to resolve break condition by forcing stronger condition over weaker. */
560 static inline DWRITE_BREAK_CONDITION override_break_condition(DWRITE_BREAK_CONDITION existingbreak, DWRITE_BREAK_CONDITION newbreak)
562 switch (existingbreak) {
563 case DWRITE_BREAK_CONDITION_NEUTRAL:
564 return newbreak;
565 case DWRITE_BREAK_CONDITION_CAN_BREAK:
566 return newbreak == DWRITE_BREAK_CONDITION_NEUTRAL ? existingbreak : newbreak;
567 /* let's keep stronger conditions as is */
568 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK:
569 case DWRITE_BREAK_CONDITION_MUST_BREAK:
570 break;
571 default:
572 ERR("unknown break condition %d\n", existingbreak);
575 return existingbreak;
578 /* This helper should be used to get effective range length, in other words it returns number of text
579 positions from range starting point to the end of the range, limited by layout text length */
580 static inline UINT32 get_clipped_range_length(const struct dwrite_textlayout *layout, const struct layout_range *range)
582 if (range->h.range.startPosition + range->h.range.length <= layout->len)
583 return range->h.range.length;
584 return layout->len - range->h.range.startPosition;
587 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
588 static HRESULT layout_update_breakpoints_range(struct dwrite_textlayout *layout, const struct layout_range *cur)
590 DWRITE_BREAK_CONDITION before, after;
591 UINT32 i, length;
592 HRESULT hr;
594 /* ignore returned conditions if failed */
595 hr = IDWriteInlineObject_GetBreakConditions(cur->object, &before, &after);
596 if (FAILED(hr))
597 after = before = DWRITE_BREAK_CONDITION_NEUTRAL;
599 if (!layout->actual_breakpoints) {
600 layout->actual_breakpoints = heap_calloc(layout->len, sizeof(*layout->actual_breakpoints));
601 if (!layout->actual_breakpoints)
602 return E_OUTOFMEMORY;
603 memcpy(layout->actual_breakpoints, layout->nominal_breakpoints, sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
606 length = get_clipped_range_length(layout, cur);
607 for (i = cur->h.range.startPosition; i < length + cur->h.range.startPosition; i++) {
608 /* for first codepoint check if there's anything before it and update accordingly */
609 if (i == cur->h.range.startPosition) {
610 if (i > 0)
611 layout->actual_breakpoints[i].breakConditionBefore = layout->actual_breakpoints[i-1].breakConditionAfter =
612 override_break_condition(layout->actual_breakpoints[i-1].breakConditionAfter, before);
613 else
614 layout->actual_breakpoints[i].breakConditionBefore = before;
615 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
617 /* similar check for last codepoint */
618 else if (i == cur->h.range.startPosition + length - 1) {
619 if (i == layout->len - 1)
620 layout->actual_breakpoints[i].breakConditionAfter = after;
621 else
622 layout->actual_breakpoints[i].breakConditionAfter = layout->actual_breakpoints[i+1].breakConditionBefore =
623 override_break_condition(layout->actual_breakpoints[i+1].breakConditionBefore, after);
624 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
626 /* for all positions within a range disable breaks */
627 else {
628 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
629 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
632 layout->actual_breakpoints[i].isWhitespace = 0;
633 layout->actual_breakpoints[i].isSoftHyphen = 0;
636 return S_OK;
639 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos);
641 static inline DWRITE_LINE_BREAKPOINT get_effective_breakpoint(const struct dwrite_textlayout *layout, UINT32 pos)
643 if (layout->actual_breakpoints)
644 return layout->actual_breakpoints[pos];
645 return layout->nominal_breakpoints[pos];
648 static inline void init_cluster_metrics(const struct dwrite_textlayout *layout, const struct regular_layout_run *run,
649 UINT16 start_glyph, UINT16 stop_glyph, UINT32 stop_position, UINT16 length, DWRITE_CLUSTER_METRICS *metrics)
651 UINT8 breakcondition;
652 UINT32 position;
653 UINT16 j;
655 /* For clusters made of control chars we report zero glyphs, and we need zero cluster
656 width as well; advances are already computed at this point and are not necessary zero. */
657 metrics->width = 0.0f;
658 if (run->run.glyphCount) {
659 for (j = start_glyph; j < stop_glyph; j++)
660 metrics->width += run->run.glyphAdvances[j];
662 metrics->length = length;
664 position = run->descr.textPosition + stop_position;
665 if (stop_glyph == run->glyphcount)
666 breakcondition = get_effective_breakpoint(layout, position).breakConditionAfter;
667 else {
668 breakcondition = get_effective_breakpoint(layout, position).breakConditionBefore;
669 if (stop_position) position -= 1;
672 metrics->canWrapLineAfter = breakcondition == DWRITE_BREAK_CONDITION_CAN_BREAK ||
673 breakcondition == DWRITE_BREAK_CONDITION_MUST_BREAK;
674 if (metrics->length == 1) {
675 DWRITE_LINE_BREAKPOINT bp = get_effective_breakpoint(layout, position);
676 metrics->isWhitespace = bp.isWhitespace;
677 metrics->isNewline = metrics->canWrapLineAfter && lb_is_newline_char(layout->str[position]);
678 metrics->isSoftHyphen = bp.isSoftHyphen;
680 else {
681 metrics->isWhitespace = 0;
682 metrics->isNewline = 0;
683 metrics->isSoftHyphen = 0;
685 metrics->isRightToLeft = run->run.bidiLevel & 1;
686 metrics->padding = 0;
691 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
692 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
693 Note that there's no need to reallocate anything at this point as we allocate one cluster per
694 codepoint initially.
697 static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 *cluster)
699 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[*cluster];
700 struct layout_cluster *c = &layout->clusters[*cluster];
701 const struct regular_layout_run *run = &r->u.regular;
702 UINT32 i, start = 0;
704 assert(r->kind == LAYOUT_RUN_REGULAR);
706 for (i = 0; i < run->descr.stringLength; i++) {
707 BOOL end = i == run->descr.stringLength - 1;
709 if (run->descr.clusterMap[start] != run->descr.clusterMap[i]) {
710 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->descr.clusterMap[i], i,
711 i - start, metrics);
712 c->position = start;
713 c->run = r;
715 *cluster += 1;
716 metrics++;
717 c++;
718 start = i;
721 if (end) {
722 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->glyphcount, i,
723 i - start + 1, metrics);
724 c->position = start;
725 c->run = r;
727 *cluster += 1;
728 return;
733 #define SCALE_FONT_METRIC(metric, emSize, metrics) ((FLOAT)(metric) * (emSize) / (FLOAT)(metrics)->designUnitsPerEm)
735 static void layout_get_font_metrics(struct dwrite_textlayout *layout, IDWriteFontFace *fontface, FLOAT emsize,
736 DWRITE_FONT_METRICS *fontmetrics)
738 if (is_layout_gdi_compatible(layout)) {
739 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(fontface, emsize, layout->ppdip, &layout->transform, fontmetrics);
740 if (FAILED(hr))
741 WARN("failed to get compat metrics, 0x%08x\n", hr);
743 else
744 IDWriteFontFace_GetMetrics(fontface, fontmetrics);
747 static void layout_get_font_height(FLOAT emsize, DWRITE_FONT_METRICS *fontmetrics, FLOAT *baseline, FLOAT *height)
749 *baseline = SCALE_FONT_METRIC(fontmetrics->ascent + fontmetrics->lineGap, emsize, fontmetrics);
750 *height = SCALE_FONT_METRIC(fontmetrics->ascent + fontmetrics->descent + fontmetrics->lineGap, emsize, fontmetrics);
753 static HRESULT layout_itemize(struct dwrite_textlayout *layout)
755 IDWriteTextAnalyzer *analyzer;
756 struct layout_range *range;
757 struct layout_run *r;
758 HRESULT hr = S_OK;
760 analyzer = get_text_analyzer();
762 LIST_FOR_EACH_ENTRY(range, &layout->ranges, struct layout_range, h.entry) {
763 /* We don't care about ranges that don't contain any text. */
764 if (range->h.range.startPosition >= layout->len)
765 break;
767 /* Inline objects override actual text in range. */
768 if (range->object) {
769 hr = layout_update_breakpoints_range(layout, range);
770 if (FAILED(hr))
771 return hr;
773 r = alloc_layout_run(LAYOUT_RUN_INLINE, range->h.range.startPosition);
774 if (!r)
775 return E_OUTOFMEMORY;
777 r->u.object.object = range->object;
778 r->u.object.length = get_clipped_range_length(layout, range);
779 list_add_tail(&layout->runs, &r->entry);
780 continue;
783 /* Initial splitting by script. */
784 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, (IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
785 range->h.range.startPosition, get_clipped_range_length(layout, range),
786 (IDWriteTextAnalysisSink *)&layout->IDWriteTextAnalysisSink1_iface);
787 if (FAILED(hr))
788 break;
790 /* Splitting further by bidi levels. */
791 hr = IDWriteTextAnalyzer_AnalyzeBidi(analyzer, (IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
792 range->h.range.startPosition, get_clipped_range_length(layout, range),
793 (IDWriteTextAnalysisSink *)&layout->IDWriteTextAnalysisSink1_iface);
794 if (FAILED(hr))
795 break;
798 return hr;
801 static HRESULT layout_resolve_fonts(struct dwrite_textlayout *layout)
803 IDWriteFontCollection *sys_collection;
804 IDWriteFontFallback *fallback = NULL;
805 struct layout_range *range;
806 struct layout_run *r;
807 HRESULT hr;
809 if (FAILED(hr = IDWriteFactory5_GetSystemFontCollection((IDWriteFactory5 *)layout->factory, FALSE,
810 (IDWriteFontCollection1 **)&sys_collection, FALSE))) {
811 WARN("Failed to get system collection, hr %#x.\n", hr);
812 return hr;
815 if (layout->format.fallback) {
816 fallback = layout->format.fallback;
817 IDWriteFontFallback_AddRef(fallback);
819 else {
820 if (FAILED(hr = IDWriteFactory7_GetSystemFontFallback(layout->factory, &fallback))) {
821 WARN("Failed to get system fallback, hr %#x.\n", hr);
822 goto fatal;
826 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
827 struct regular_layout_run *run = &r->u.regular;
828 IDWriteFont *font;
829 UINT32 length;
831 if (r->kind == LAYOUT_RUN_INLINE)
832 continue;
834 range = get_layout_range_by_pos(layout, run->descr.textPosition);
836 if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL) {
837 IDWriteFontCollection *collection;
839 collection = range->collection ? range->collection : sys_collection;
841 if (FAILED(hr = create_matching_font(collection, range->fontfamily, range->weight, range->style,
842 range->stretch, &font))) {
843 WARN("%s: failed to create matching font for non visual run, family %s, collection %p\n",
844 debugstr_rundescr(&run->descr), debugstr_w(range->fontfamily), range->collection);
845 break;
848 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
849 IDWriteFont_Release(font);
850 if (FAILED(hr)) {
851 WARN("Failed to create font face, hr %#x.\n", hr);
852 break;
855 run->run.fontEmSize = range->fontsize;
856 continue;
859 length = run->descr.stringLength;
861 while (length) {
862 UINT32 mapped_length;
863 FLOAT scale;
865 run = &r->u.regular;
867 hr = IDWriteFontFallback_MapCharacters(fallback,
868 (IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
869 run->descr.textPosition,
870 run->descr.stringLength,
871 range->collection,
872 range->fontfamily,
873 range->weight,
874 range->style,
875 range->stretch,
876 &mapped_length,
877 &font,
878 &scale);
879 if (FAILED(hr)) {
880 WARN("%s: failed to map family %s, collection %p, hr %#x.\n", debugstr_rundescr(&run->descr),
881 debugstr_w(range->fontfamily), range->collection, hr);
882 goto fatal;
885 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
886 IDWriteFont_Release(font);
887 if (FAILED(hr)) {
888 WARN("Failed to create font face, hr %#x.\n", hr);
889 goto fatal;
892 run->run.fontEmSize = range->fontsize * scale;
894 if (mapped_length < length) {
895 struct regular_layout_run *nextrun;
896 struct layout_run *nextr;
898 /* keep mapped part for current run, add another run for the rest */
899 nextr = alloc_layout_run(LAYOUT_RUN_REGULAR, 0);
900 if (!nextr) {
901 hr = E_OUTOFMEMORY;
902 goto fatal;
905 *nextr = *r;
906 nextr->start_position = run->descr.textPosition + mapped_length;
907 nextrun = &nextr->u.regular;
908 nextrun->descr.textPosition = nextr->start_position;
909 nextrun->descr.stringLength = run->descr.stringLength - mapped_length;
910 nextrun->descr.string = &layout->str[nextrun->descr.textPosition];
911 run->descr.stringLength = mapped_length;
912 list_add_after(&r->entry, &nextr->entry);
913 r = nextr;
916 length -= mapped_length;
920 fatal:
921 IDWriteFontCollection_Release(sys_collection);
922 if (fallback)
923 IDWriteFontFallback_Release(fallback);
925 return hr;
928 static HRESULT layout_shape_run(struct dwrite_textlayout *layout, struct regular_layout_run *run)
930 DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props;
931 DWRITE_SHAPING_TEXT_PROPERTIES *text_props;
932 IDWriteTextAnalyzer *analyzer;
933 struct layout_range *range;
934 UINT32 max_count;
935 HRESULT hr;
937 range = get_layout_range_by_pos(layout, run->descr.textPosition);
938 run->descr.localeName = range->locale;
939 run->clustermap = heap_calloc(run->descr.stringLength, sizeof(*run->clustermap));
941 max_count = 3 * run->descr.stringLength / 2 + 16;
942 run->glyphs = heap_calloc(max_count, sizeof(*run->glyphs));
943 if (!run->clustermap || !run->glyphs)
944 return E_OUTOFMEMORY;
946 text_props = heap_calloc(run->descr.stringLength, sizeof(*text_props));
947 glyph_props = heap_calloc(max_count, sizeof(*glyph_props));
948 if (!text_props || !glyph_props) {
949 heap_free(text_props);
950 heap_free(glyph_props);
951 return E_OUTOFMEMORY;
954 analyzer = get_text_analyzer();
956 for (;;) {
957 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, run->descr.string, run->descr.stringLength, run->run.fontFace,
958 run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL /* FIXME */, NULL,
959 NULL, 0, max_count, run->clustermap, text_props, run->glyphs, glyph_props, &run->glyphcount);
960 if (hr == E_NOT_SUFFICIENT_BUFFER) {
961 heap_free(run->glyphs);
962 heap_free(glyph_props);
964 max_count = run->glyphcount;
966 run->glyphs = heap_calloc(max_count, sizeof(*run->glyphs));
967 glyph_props = heap_calloc(max_count, sizeof(*glyph_props));
968 if (!run->glyphs || !glyph_props) {
969 hr = E_OUTOFMEMORY;
970 break;
973 continue;
976 break;
979 if (FAILED(hr)) {
980 heap_free(text_props);
981 heap_free(glyph_props);
982 WARN("%s: shaping failed, hr %#x.\n", debugstr_rundescr(&run->descr), hr);
983 return hr;
986 run->run.glyphIndices = run->glyphs;
987 run->descr.clusterMap = run->clustermap;
989 run->advances = heap_calloc(run->glyphcount, sizeof(*run->advances));
990 run->offsets = heap_calloc(run->glyphcount, sizeof(*run->offsets));
991 if (!run->advances || !run->offsets)
992 return E_OUTOFMEMORY;
994 /* Get advances and offsets. */
995 if (is_layout_gdi_compatible(layout))
996 hr = IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap,
997 text_props, run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount,
998 run->run.fontFace, run->run.fontEmSize, layout->ppdip, &layout->transform,
999 layout->measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->run.isSideways, run->run.bidiLevel & 1,
1000 &run->sa, run->descr.localeName, NULL, NULL, 0, run->advances, run->offsets);
1001 else
1002 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap, text_props,
1003 run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount, run->run.fontFace,
1004 run->run.fontEmSize, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
1005 NULL, NULL, 0, run->advances, run->offsets);
1007 heap_free(text_props);
1008 heap_free(glyph_props);
1009 if (FAILED(hr)) {
1010 memset(run->advances, 0, run->glyphcount * sizeof(*run->advances));
1011 memset(run->offsets, 0, run->glyphcount * sizeof(*run->offsets));
1012 WARN("%s: failed to get glyph placement info, hr %#x.\n", debugstr_rundescr(&run->descr), hr);
1015 run->run.glyphAdvances = run->advances;
1016 run->run.glyphOffsets = run->offsets;
1018 /* Special treatment for runs that don't produce visual output, shaping code adds normal glyphs for them,
1019 with valid cluster map and potentially with non-zero advances; layout code exposes those as zero
1020 width clusters. */
1021 if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL)
1022 run->run.glyphCount = 0;
1023 else
1024 run->run.glyphCount = run->glyphcount;
1026 return S_OK;
1029 static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
1031 struct layout_run *r;
1032 UINT32 cluster = 0;
1033 HRESULT hr;
1035 free_layout_eruns(layout);
1036 free_layout_runs(layout);
1038 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
1039 if (!layout->clustermetrics && layout->len) {
1040 layout->clustermetrics = heap_calloc(layout->len, sizeof(*layout->clustermetrics));
1041 layout->clusters = heap_calloc(layout->len, sizeof(*layout->clusters));
1042 if (!layout->clustermetrics || !layout->clusters) {
1043 heap_free(layout->clustermetrics);
1044 heap_free(layout->clusters);
1045 return E_OUTOFMEMORY;
1048 layout->cluster_count = 0;
1050 if (FAILED(hr = layout_itemize(layout))) {
1051 WARN("Itemization failed, hr %#x.\n", hr);
1052 return hr;
1055 if (FAILED(hr = layout_resolve_fonts(layout))) {
1056 WARN("Failed to resolve layout fonts, hr %#x.\n", hr);
1057 return hr;
1060 /* fill run info */
1061 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
1062 struct regular_layout_run *run = &r->u.regular;
1063 DWRITE_FONT_METRICS fontmetrics = { 0 };
1065 /* we need to do very little in case of inline objects */
1066 if (r->kind == LAYOUT_RUN_INLINE) {
1067 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[cluster];
1068 struct layout_cluster *c = &layout->clusters[cluster];
1069 DWRITE_INLINE_OBJECT_METRICS inlinemetrics;
1071 metrics->width = 0.0f;
1072 metrics->length = r->u.object.length;
1073 metrics->canWrapLineAfter = 0;
1074 metrics->isWhitespace = 0;
1075 metrics->isNewline = 0;
1076 metrics->isSoftHyphen = 0;
1077 metrics->isRightToLeft = 0;
1078 metrics->padding = 0;
1079 c->run = r;
1080 c->position = 0; /* there's always one cluster per inline object, so 0 is valid value */
1081 cluster++;
1083 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
1084 hr = IDWriteInlineObject_GetMetrics(r->u.object.object, &inlinemetrics);
1085 if (FAILED(hr)) {
1086 memset(&inlinemetrics, 0, sizeof(inlinemetrics));
1087 hr = S_OK;
1089 metrics->width = inlinemetrics.width;
1090 r->baseline = inlinemetrics.baseline;
1091 r->height = inlinemetrics.height;
1093 /* FIXME: use resolved breakpoints in this case too */
1095 continue;
1098 if (FAILED(hr = layout_shape_run(layout, run)))
1099 WARN("%s: shaping failed, hr %#x.\n", debugstr_rundescr(&run->descr), hr);
1101 /* baseline derived from font metrics */
1102 layout_get_font_metrics(layout, run->run.fontFace, run->run.fontEmSize, &fontmetrics);
1103 layout_get_font_height(run->run.fontEmSize, &fontmetrics, &r->baseline, &r->height);
1105 layout_set_cluster_metrics(layout, r, &cluster);
1108 if (hr == S_OK) {
1109 layout->cluster_count = cluster;
1110 if (cluster)
1111 layout->clustermetrics[cluster-1].canWrapLineAfter = 1;
1114 return hr;
1117 static HRESULT layout_compute(struct dwrite_textlayout *layout)
1119 HRESULT hr;
1121 if (!(layout->recompute & RECOMPUTE_CLUSTERS))
1122 return S_OK;
1124 /* nominal breakpoints are evaluated only once, because string never changes */
1125 if (!layout->nominal_breakpoints) {
1126 IDWriteTextAnalyzer *analyzer;
1128 layout->nominal_breakpoints = heap_calloc(layout->len, sizeof(*layout->nominal_breakpoints));
1129 if (!layout->nominal_breakpoints)
1130 return E_OUTOFMEMORY;
1132 analyzer = get_text_analyzer();
1134 if (FAILED(hr = IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer,
1135 (IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
1136 0, layout->len, (IDWriteTextAnalysisSink *)&layout->IDWriteTextAnalysisSink1_iface)))
1137 WARN("Line breakpoints analysis failed, hr %#x.\n", hr);
1140 heap_free(layout->actual_breakpoints);
1141 layout->actual_breakpoints = NULL;
1143 hr = layout_compute_runs(layout);
1145 if (TRACE_ON(dwrite)) {
1146 struct layout_run *cur;
1148 LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
1149 if (cur->kind == LAYOUT_RUN_INLINE)
1150 TRACE("run inline object %p, len %u\n", cur->u.object.object, cur->u.object.length);
1151 else
1152 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur->u.regular.descr.textPosition, cur->u.regular.descr.textPosition +
1153 cur->u.regular.descr.stringLength-1, cur->u.regular.descr.stringLength, cur->u.regular.run.bidiLevel);
1157 layout->recompute &= ~RECOMPUTE_CLUSTERS;
1158 return hr;
1161 static inline FLOAT get_cluster_range_width(struct dwrite_textlayout *layout, UINT32 start, UINT32 end)
1163 FLOAT width = 0.0f;
1164 for (; start < end; start++)
1165 width += layout->clustermetrics[start].width;
1166 return width;
1169 static struct layout_range_header *get_layout_range_header_by_pos(struct list *ranges, UINT32 pos)
1171 struct layout_range_header *cur;
1173 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
1174 DWRITE_TEXT_RANGE *r = &cur->range;
1175 if (r->startPosition <= pos && pos < r->startPosition + r->length)
1176 return cur;
1179 return NULL;
1182 static inline IUnknown *layout_get_effect_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1184 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->effects, pos);
1185 return ((struct layout_range_iface*)h)->iface;
1188 static inline BOOL layout_is_erun_rtl(const struct layout_effective_run *erun)
1190 return erun->run->u.regular.run.bidiLevel & 1;
1193 /* A set of parameters that additionally splits resulting runs. It happens after shaping and all text processing,
1194 no glyph changes are possible. It's understandable for drawing effects, because DrawGlyphRun() reports them as
1195 one of the arguments, but it also happens for decorations, so every effective run has uniform
1196 underline/strikethough/effect tuple. */
1197 struct layout_final_splitting_params {
1198 BOOL strikethrough;
1199 BOOL underline;
1200 IUnknown *effect;
1203 static inline BOOL layout_get_strikethrough_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1205 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->strike_ranges, pos);
1206 return ((struct layout_range_bool*)h)->value;
1209 static inline BOOL layout_get_underline_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1211 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->underline_ranges, pos);
1212 return ((struct layout_range_bool*)h)->value;
1215 static void layout_splitting_params_from_pos(struct dwrite_textlayout *layout, UINT32 pos,
1216 struct layout_final_splitting_params *params)
1218 params->strikethrough = layout_get_strikethrough_from_pos(layout, pos);
1219 params->underline = layout_get_underline_from_pos(layout, pos);
1220 params->effect = layout_get_effect_from_pos(layout, pos);
1223 static BOOL is_same_splitting_params(const struct layout_final_splitting_params *left,
1224 const struct layout_final_splitting_params *right)
1226 return left->strikethrough == right->strikethrough &&
1227 left->underline == right->underline &&
1228 left->effect == right->effect;
1231 static void layout_get_erun_font_metrics(struct dwrite_textlayout *layout, struct layout_effective_run *erun,
1232 DWRITE_FONT_METRICS *metrics)
1234 memset(metrics, 0, sizeof(*metrics));
1235 if (is_layout_gdi_compatible(layout)) {
1236 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(
1237 erun->run->u.regular.run.fontFace,
1238 erun->run->u.regular.run.fontEmSize,
1239 layout->ppdip,
1240 &layout->transform,
1241 metrics);
1242 if (FAILED(hr))
1243 WARN("failed to get font metrics, 0x%08x\n", hr);
1245 else
1246 IDWriteFontFace_GetMetrics(erun->run->u.regular.run.fontFace, metrics);
1249 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
1250 'cluster_count' indicates how many clusters to add, including first one. */
1251 static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 first_cluster,
1252 UINT32 cluster_count, UINT32 line, FLOAT origin_x, struct layout_final_splitting_params *params)
1254 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1255 UINT32 i, start, length, last_cluster;
1256 struct layout_effective_run *run;
1258 if (r->kind == LAYOUT_RUN_INLINE) {
1259 struct layout_effective_inline *inlineobject;
1261 inlineobject = heap_alloc(sizeof(*inlineobject));
1262 if (!inlineobject)
1263 return E_OUTOFMEMORY;
1265 inlineobject->object = r->u.object.object;
1266 inlineobject->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1267 inlineobject->origin.x = is_rtl ? origin_x - inlineobject->width : origin_x;
1268 inlineobject->origin.y = 0.0f; /* set after line is built */
1269 inlineobject->align_dx = 0.0f;
1270 inlineobject->baseline = r->baseline;
1272 /* It's not clear how these two are set, possibly directionality
1273 is derived from surrounding text (replaced text could have
1274 different ranges which differ in reading direction). */
1275 inlineobject->is_sideways = FALSE;
1276 inlineobject->is_rtl = FALSE;
1277 inlineobject->line = line;
1279 /* effect assigned from start position and on is used for inline objects */
1280 inlineobject->effect = layout_get_effect_from_pos(layout, layout->clusters[first_cluster].position +
1281 layout->clusters[first_cluster].run->start_position);
1283 list_add_tail(&layout->inlineobjects, &inlineobject->entry);
1284 return S_OK;
1287 run = heap_alloc(sizeof(*run));
1288 if (!run)
1289 return E_OUTOFMEMORY;
1291 /* No need to iterate for that, use simple fact that:
1292 <last cluster position> = <first cluster position> + <sum of cluster lengths not including last one> */
1293 last_cluster = first_cluster + cluster_count - 1;
1294 length = layout->clusters[last_cluster].position - layout->clusters[first_cluster].position +
1295 layout->clustermetrics[last_cluster].length;
1297 run->clustermap = heap_calloc(length, sizeof(*run->clustermap));
1298 if (!run->clustermap) {
1299 heap_free(run);
1300 return E_OUTOFMEMORY;
1303 run->run = r;
1304 run->start = start = layout->clusters[first_cluster].position;
1305 run->length = length;
1306 run->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1307 memset(&run->bbox, 0, sizeof(run->bbox));
1309 /* Check if run direction matches paragraph direction, if it doesn't adjust by
1310 run width */
1311 if (layout_is_erun_rtl(run) ^ is_rtl)
1312 run->origin.x = is_rtl ? origin_x - run->width : origin_x + run->width;
1313 else
1314 run->origin.x = origin_x;
1316 run->origin.y = 0.0f; /* set after line is built */
1317 run->align_dx = 0.0f;
1318 run->line = line;
1320 if (r->u.regular.run.glyphCount) {
1321 /* Trim leading and trailing clusters. */
1322 run->glyphcount = r->u.regular.run.glyphCount - r->u.regular.clustermap[start];
1323 if (start + length < r->u.regular.descr.stringLength)
1324 run->glyphcount -= r->u.regular.run.glyphCount - r->u.regular.clustermap[start + length];
1326 else
1327 run->glyphcount = 0;
1329 /* cluster map needs to be shifted */
1330 for (i = 0; i < length; i++)
1331 run->clustermap[i] = r->u.regular.clustermap[start + i] - r->u.regular.clustermap[start];
1333 run->effect = params->effect;
1334 run->underlined = params->underline;
1335 list_add_tail(&layout->eruns, &run->entry);
1337 /* Strikethrough style is guaranteed to be consistent within effective run,
1338 its width equals to run width, thickness and offset are derived from
1339 font metrics, rest of the values are from layout or run itself */
1340 if (params->strikethrough) {
1341 struct layout_strikethrough *s;
1342 DWRITE_FONT_METRICS metrics;
1344 s = heap_alloc(sizeof(*s));
1345 if (!s)
1346 return E_OUTOFMEMORY;
1348 layout_get_erun_font_metrics(layout, run, &metrics);
1349 s->s.width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1350 s->s.thickness = SCALE_FONT_METRIC(metrics.strikethroughThickness, r->u.regular.run.fontEmSize, &metrics);
1351 /* Negative offset moves it above baseline as Y coordinate grows downward. */
1352 s->s.offset = -SCALE_FONT_METRIC(metrics.strikethroughPosition, r->u.regular.run.fontEmSize, &metrics);
1353 s->s.readingDirection = layout->format.readingdir;
1354 s->s.flowDirection = layout->format.flow;
1355 s->s.localeName = r->u.regular.descr.localeName;
1356 s->s.measuringMode = layout->measuringmode;
1357 s->run = run;
1359 list_add_tail(&layout->strikethrough, &s->entry);
1362 return S_OK;
1365 static void layout_apply_line_spacing(struct dwrite_textlayout *layout, UINT32 line)
1367 switch (layout->format.spacing.method)
1369 case DWRITE_LINE_SPACING_METHOD_DEFAULT:
1370 layout->lines[line].metrics.height = layout->lines[line].height;
1371 layout->lines[line].metrics.baseline = layout->lines[line].baseline;
1372 break;
1373 case DWRITE_LINE_SPACING_METHOD_UNIFORM:
1374 layout->lines[line].metrics.height = layout->format.spacing.height;
1375 layout->lines[line].metrics.baseline = layout->format.spacing.baseline;
1376 break;
1377 case DWRITE_LINE_SPACING_METHOD_PROPORTIONAL:
1378 layout->lines[line].metrics.height = layout->lines[line].height * layout->format.spacing.height;
1379 layout->lines[line].metrics.baseline = layout->lines[line].baseline * layout->format.spacing.baseline;
1380 break;
1381 default:
1382 ERR("Unknown spacing method %u\n", layout->format.spacing.method);
1386 static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_LINE_METRICS1 *metrics)
1388 size_t i = layout->metrics.lineCount;
1390 if (!dwrite_array_reserve((void **)&layout->lines, &layout->lines_size, layout->metrics.lineCount + 1,
1391 sizeof(*layout->lines)))
1393 return E_OUTOFMEMORY;
1396 layout->lines[i].metrics = *metrics;
1397 layout->lines[i].height = metrics->height;
1398 layout->lines[i].baseline = metrics->baseline;
1400 if (layout->format.spacing.method != DWRITE_LINE_SPACING_METHOD_DEFAULT)
1401 layout_apply_line_spacing(layout, i);
1403 layout->metrics.lineCount++;
1404 return S_OK;
1407 static inline struct layout_effective_run *layout_get_next_erun(struct dwrite_textlayout *layout,
1408 const struct layout_effective_run *cur)
1410 struct list *e;
1412 if (!cur)
1413 e = list_head(&layout->eruns);
1414 else
1415 e = list_next(&layout->eruns, &cur->entry);
1416 if (!e)
1417 return NULL;
1418 return LIST_ENTRY(e, struct layout_effective_run, entry);
1421 static inline struct layout_effective_run *layout_get_prev_erun(struct dwrite_textlayout *layout,
1422 const struct layout_effective_run *cur)
1424 struct list *e;
1426 if (!cur)
1427 e = list_tail(&layout->eruns);
1428 else
1429 e = list_prev(&layout->eruns, &cur->entry);
1430 if (!e)
1431 return NULL;
1432 return LIST_ENTRY(e, struct layout_effective_run, entry);
1435 static inline struct layout_effective_inline *layout_get_next_inline_run(struct dwrite_textlayout *layout,
1436 const struct layout_effective_inline *cur)
1438 struct list *e;
1440 if (!cur)
1441 e = list_head(&layout->inlineobjects);
1442 else
1443 e = list_next(&layout->inlineobjects, &cur->entry);
1444 if (!e)
1445 return NULL;
1446 return LIST_ENTRY(e, struct layout_effective_inline, entry);
1449 static FLOAT layout_get_line_width(struct dwrite_textlayout *layout,
1450 struct layout_effective_run *erun, struct layout_effective_inline *inrun, UINT32 line)
1452 FLOAT width = 0.0f;
1454 while (erun && erun->line == line) {
1455 width += erun->width;
1456 erun = layout_get_next_erun(layout, erun);
1457 if (!erun)
1458 break;
1461 while (inrun && inrun->line == line) {
1462 width += inrun->width;
1463 inrun = layout_get_next_inline_run(layout, inrun);
1464 if (!inrun)
1465 break;
1468 return width;
1471 static inline BOOL should_skip_transform(const DWRITE_MATRIX *m, FLOAT *det)
1473 *det = m->m11 * m->m22 - m->m12 * m->m21;
1474 /* on certain conditions we can skip transform */
1475 return (!memcmp(m, &identity, sizeof(*m)) || fabsf(*det) <= 1e-10f);
1478 static inline void layout_apply_snapping(D2D1_POINT_2F *vec, BOOL skiptransform, FLOAT ppdip,
1479 const DWRITE_MATRIX *m, FLOAT det)
1481 if (!skiptransform) {
1482 D2D1_POINT_2F vec2;
1484 /* apply transform */
1485 vec->x *= ppdip;
1486 vec->y *= ppdip;
1488 vec2.x = m->m11 * vec->x + m->m21 * vec->y + m->dx;
1489 vec2.y = m->m12 * vec->x + m->m22 * vec->y + m->dy;
1491 /* snap */
1492 vec2.x = floorf(vec2.x + 0.5f);
1493 vec2.y = floorf(vec2.y + 0.5f);
1495 /* apply inverted transform, we don't care about X component at this point */
1496 vec->x = (m->m22 * vec2.x - m->m21 * vec2.y + m->m21 * m->dy - m->m22 * m->dx) / det;
1497 vec->x /= ppdip;
1499 vec->y = (-m->m12 * vec2.x + m->m11 * vec2.y - (m->m11 * m->dy - m->m12 * m->dx)) / det;
1500 vec->y /= ppdip;
1502 else {
1503 vec->x = floorf(vec->x * ppdip + 0.5f) / ppdip;
1504 vec->y = floorf(vec->y * ppdip + 0.5f) / ppdip;
1508 static void layout_apply_leading_alignment(struct dwrite_textlayout *layout)
1510 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1511 struct layout_effective_inline *inrun;
1512 struct layout_effective_run *erun;
1514 erun = layout_get_next_erun(layout, NULL);
1515 inrun = layout_get_next_inline_run(layout, NULL);
1517 while (erun) {
1518 erun->align_dx = 0.0f;
1519 erun = layout_get_next_erun(layout, erun);
1522 while (inrun) {
1523 inrun->align_dx = 0.0f;
1524 inrun = layout_get_next_inline_run(layout, inrun);
1527 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
1530 static void layout_apply_trailing_alignment(struct dwrite_textlayout *layout)
1532 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1533 struct layout_effective_inline *inrun;
1534 struct layout_effective_run *erun;
1535 UINT32 line;
1537 erun = layout_get_next_erun(layout, NULL);
1538 inrun = layout_get_next_inline_run(layout, NULL);
1540 for (line = 0; line < layout->metrics.lineCount; line++) {
1541 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1542 FLOAT shift = layout->metrics.layoutWidth - width;
1544 if (is_rtl)
1545 shift *= -1.0f;
1547 while (erun && erun->line == line) {
1548 erun->align_dx = shift;
1549 erun = layout_get_next_erun(layout, erun);
1552 while (inrun && inrun->line == line) {
1553 inrun->align_dx = shift;
1554 inrun = layout_get_next_inline_run(layout, inrun);
1558 layout->metrics.left = is_rtl ? 0.0f : layout->metrics.layoutWidth - layout->metrics.width;
1561 static inline FLOAT layout_get_centered_shift(struct dwrite_textlayout *layout, BOOL skiptransform,
1562 FLOAT width, FLOAT det)
1564 if (is_layout_gdi_compatible(layout)) {
1565 D2D1_POINT_2F vec = { layout->metrics.layoutWidth - width, 0.0f};
1566 layout_apply_snapping(&vec, skiptransform, layout->ppdip, &layout->transform, det);
1567 return floorf(vec.x / 2.0f);
1569 else
1570 return (layout->metrics.layoutWidth - width) / 2.0f;
1573 static void layout_apply_centered_alignment(struct dwrite_textlayout *layout)
1575 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1576 struct layout_effective_inline *inrun;
1577 struct layout_effective_run *erun;
1578 BOOL skiptransform;
1579 UINT32 line;
1580 FLOAT det;
1582 erun = layout_get_next_erun(layout, NULL);
1583 inrun = layout_get_next_inline_run(layout, NULL);
1585 skiptransform = should_skip_transform(&layout->transform, &det);
1587 for (line = 0; line < layout->metrics.lineCount; line++) {
1588 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1589 FLOAT shift = layout_get_centered_shift(layout, skiptransform, width, det);
1591 if (is_rtl)
1592 shift *= -1.0f;
1594 while (erun && erun->line == line) {
1595 erun->align_dx = shift;
1596 erun = layout_get_next_erun(layout, erun);
1599 while (inrun && inrun->line == line) {
1600 inrun->align_dx = shift;
1601 inrun = layout_get_next_inline_run(layout, inrun);
1605 layout->metrics.left = (layout->metrics.layoutWidth - layout->metrics.width) / 2.0f;
1608 static void layout_apply_text_alignment(struct dwrite_textlayout *layout)
1610 switch (layout->format.textalignment)
1612 case DWRITE_TEXT_ALIGNMENT_LEADING:
1613 layout_apply_leading_alignment(layout);
1614 break;
1615 case DWRITE_TEXT_ALIGNMENT_TRAILING:
1616 layout_apply_trailing_alignment(layout);
1617 break;
1618 case DWRITE_TEXT_ALIGNMENT_CENTER:
1619 layout_apply_centered_alignment(layout);
1620 break;
1621 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED:
1622 FIXME("alignment %d not implemented\n", layout->format.textalignment);
1623 break;
1624 default:
1629 static void layout_apply_par_alignment(struct dwrite_textlayout *layout)
1631 struct layout_effective_inline *inrun;
1632 struct layout_effective_run *erun;
1633 FLOAT origin_y = 0.0f;
1634 UINT32 line;
1636 /* alignment mode defines origin, after that all run origins are updated
1637 the same way */
1639 switch (layout->format.paralign)
1641 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR:
1642 origin_y = 0.0f;
1643 break;
1644 case DWRITE_PARAGRAPH_ALIGNMENT_FAR:
1645 origin_y = layout->metrics.layoutHeight - layout->metrics.height;
1646 break;
1647 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER:
1648 origin_y = (layout->metrics.layoutHeight - layout->metrics.height) / 2.0f;
1649 break;
1650 default:
1654 layout->metrics.top = origin_y;
1656 erun = layout_get_next_erun(layout, NULL);
1657 inrun = layout_get_next_inline_run(layout, NULL);
1658 for (line = 0; line < layout->metrics.lineCount; line++)
1660 float pos_y = origin_y + layout->lines[line].metrics.baseline;
1662 while (erun && erun->line == line) {
1663 erun->origin.y = pos_y;
1664 erun = layout_get_next_erun(layout, erun);
1667 while (inrun && inrun->line == line) {
1668 inrun->origin.y = pos_y - inrun->baseline;
1669 inrun = layout_get_next_inline_run(layout, inrun);
1672 origin_y += layout->lines[line].metrics.height;
1676 struct layout_underline_splitting_params {
1677 const WCHAR *locale; /* points to range data, no additional allocation */
1678 IUnknown *effect; /* does not hold another reference */
1681 static void init_u_splitting_params_from_erun(struct layout_effective_run *erun,
1682 struct layout_underline_splitting_params *params)
1684 params->locale = erun->run->u.regular.descr.localeName;
1685 params->effect = erun->effect;
1688 static BOOL is_same_u_splitting(struct layout_underline_splitting_params *left,
1689 struct layout_underline_splitting_params *right)
1691 return left->effect == right->effect && !strcmpiW(left->locale, right->locale);
1694 static HRESULT layout_add_underline(struct dwrite_textlayout *layout, struct layout_effective_run *first,
1695 struct layout_effective_run *last)
1697 FLOAT thickness, offset, runheight;
1698 struct layout_effective_run *cur;
1699 DWRITE_FONT_METRICS metrics;
1701 if (first == layout_get_prev_erun(layout, last)) {
1702 layout_get_erun_font_metrics(layout, first, &metrics);
1703 thickness = SCALE_FONT_METRIC(metrics.underlineThickness, first->run->u.regular.run.fontEmSize, &metrics);
1704 offset = SCALE_FONT_METRIC(metrics.underlinePosition, first->run->u.regular.run.fontEmSize, &metrics);
1705 runheight = SCALE_FONT_METRIC(metrics.capHeight, first->run->u.regular.run.fontEmSize, &metrics);
1707 else {
1708 FLOAT width = 0.0f;
1710 /* Single underline is added for consecutive underlined runs. In this case underline parameters are
1711 calculated as weighted average, where run width acts as a weight. */
1712 thickness = offset = runheight = 0.0f;
1713 cur = first;
1714 do {
1715 layout_get_erun_font_metrics(layout, cur, &metrics);
1717 thickness += SCALE_FONT_METRIC(metrics.underlineThickness, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
1718 offset += SCALE_FONT_METRIC(metrics.underlinePosition, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
1719 runheight = max(SCALE_FONT_METRIC(metrics.capHeight, cur->run->u.regular.run.fontEmSize, &metrics), runheight);
1720 width += cur->width;
1722 cur = layout_get_next_erun(layout, cur);
1723 } while (cur != last);
1725 thickness /= width;
1726 offset /= width;
1729 cur = first;
1730 do {
1731 struct layout_underline_splitting_params params, prev_params;
1732 struct layout_effective_run *next, *w;
1733 struct layout_underline *u;
1735 init_u_splitting_params_from_erun(cur, &prev_params);
1736 while ((next = layout_get_next_erun(layout, cur)) != last) {
1737 init_u_splitting_params_from_erun(next, &params);
1738 if (!is_same_u_splitting(&prev_params, &params))
1739 break;
1740 cur = next;
1743 u = heap_alloc(sizeof(*u));
1744 if (!u)
1745 return E_OUTOFMEMORY;
1747 w = cur;
1748 u->u.width = 0.0f;
1749 while (w != next) {
1750 u->u.width += w->width;
1751 w = layout_get_next_erun(layout, w);
1754 u->u.thickness = thickness;
1755 /* Font metrics convention is to have it negative when below baseline, for rendering
1756 however Y grows from baseline down for horizontal baseline. */
1757 u->u.offset = -offset;
1758 u->u.runHeight = runheight;
1759 u->u.readingDirection = is_run_rtl(cur) ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
1760 DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
1761 u->u.flowDirection = layout->format.flow;
1762 u->u.localeName = cur->run->u.regular.descr.localeName;
1763 u->u.measuringMode = layout->measuringmode;
1764 u->run = cur;
1765 list_add_tail(&layout->underlines, &u->entry);
1767 cur = next;
1768 } while (cur != last);
1770 return S_OK;
1773 /* Adds zero width line, metrics are derived from font at specified text position. */
1774 static HRESULT layout_set_dummy_line_metrics(struct dwrite_textlayout *layout, UINT32 pos)
1776 DWRITE_LINE_METRICS1 metrics = { 0 };
1777 DWRITE_FONT_METRICS fontmetrics;
1778 struct layout_range *range;
1779 IDWriteFontFace *fontface;
1780 IDWriteFont *font;
1781 HRESULT hr;
1783 range = get_layout_range_by_pos(layout, pos);
1784 hr = create_matching_font(range->collection,
1785 range->fontfamily,
1786 range->weight,
1787 range->style,
1788 range->stretch,
1789 &font);
1790 if (FAILED(hr))
1791 return hr;
1792 hr = IDWriteFont_CreateFontFace(font, &fontface);
1793 IDWriteFont_Release(font);
1794 if (FAILED(hr))
1795 return hr;
1797 layout_get_font_metrics(layout, fontface, range->fontsize, &fontmetrics);
1798 layout_get_font_height(range->fontsize, &fontmetrics, &metrics.baseline, &metrics.height);
1799 IDWriteFontFace_Release(fontface);
1801 return layout_set_line_metrics(layout, &metrics);
1804 static void layout_add_line(struct dwrite_textlayout *layout, UINT32 first_cluster, UINT32 last_cluster,
1805 UINT32 *textpos)
1807 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1808 struct layout_final_splitting_params params, prev_params;
1809 DWRITE_INLINE_OBJECT_METRICS sign_metrics = { 0 };
1810 UINT32 line = layout->metrics.lineCount, i;
1811 DWRITE_LINE_METRICS1 metrics = { 0 };
1812 UINT32 index, start, pos = *textpos;
1813 FLOAT descent, trailingspacewidth;
1814 BOOL append_trimming_run = FALSE;
1815 const struct layout_run *run;
1816 float width = 0.0f, origin_x;
1817 HRESULT hr;
1819 /* Take a look at clusters we got for this line in reverse order to set trailing properties for current line */
1820 for (index = last_cluster, trailingspacewidth = 0.0f; index >= first_cluster; index--) {
1821 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1822 struct layout_cluster *lc = &layout->clusters[index];
1823 WCHAR ch;
1825 /* This also filters out clusters added from inline objects, those are never
1826 treated as a white space. */
1827 if (!cluster->isWhitespace)
1828 break;
1830 /* Every isNewline cluster is also isWhitespace, but not every
1831 newline character cluster has isNewline set, so go back to original string. */
1832 ch = lc->run->u.regular.descr.string[lc->position];
1833 if (cluster->length == 1 && lb_is_newline_char(ch))
1834 metrics.newlineLength += cluster->length;
1836 metrics.trailingWhitespaceLength += cluster->length;
1837 trailingspacewidth += cluster->width;
1839 if (index == 0)
1840 break;
1843 /* Line metrics length includes trailing whitespace length too */
1844 for (i = first_cluster; i <= last_cluster; i++)
1845 metrics.length += layout->clustermetrics[i].length;
1847 /* Ignore trailing whitespaces */
1848 while (last_cluster > first_cluster) {
1849 if (!layout->clustermetrics[last_cluster].isWhitespace)
1850 break;
1852 last_cluster--;
1855 /* Does not include trailing space width */
1856 if (!layout->clustermetrics[last_cluster].isWhitespace)
1857 width = get_cluster_range_width(layout, first_cluster, last_cluster + 1);
1859 /* Append trimming run if necessary */
1860 if (width > layout->metrics.layoutWidth && layout->format.trimmingsign != NULL &&
1861 layout->format.trimming.granularity != DWRITE_TRIMMING_GRANULARITY_NONE) {
1862 FLOAT trimmed_width = width;
1864 hr = IDWriteInlineObject_GetMetrics(layout->format.trimmingsign, &sign_metrics);
1865 if (SUCCEEDED(hr)) {
1866 while (last_cluster > first_cluster) {
1867 if (trimmed_width + sign_metrics.width <= layout->metrics.layoutWidth)
1868 break;
1869 if (layout->format.trimming.granularity == DWRITE_TRIMMING_GRANULARITY_CHARACTER)
1870 trimmed_width -= layout->clustermetrics[last_cluster--].width;
1871 else {
1872 while (last_cluster > first_cluster) {
1873 trimmed_width -= layout->clustermetrics[last_cluster].width;
1874 if (layout->clustermetrics[last_cluster--].canWrapLineAfter)
1875 break;
1879 append_trimming_run = TRUE;
1881 else
1882 WARN("Failed to get trimming sign metrics, lines won't be trimmed, hr %#x.\n", hr);
1884 width = trimmed_width + sign_metrics.width;
1887 layout_splitting_params_from_pos(layout, pos, &params);
1888 prev_params = params;
1889 run = layout->clusters[first_cluster].run;
1891 /* Form runs from a range of clusters; this is what will be reported with DrawGlyphRun() */
1892 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0f;
1893 for (start = first_cluster, i = first_cluster; i <= last_cluster; i++) {
1894 layout_splitting_params_from_pos(layout, pos, &params);
1896 if (run != layout->clusters[i].run || !is_same_splitting_params(&prev_params, &params)) {
1897 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, &prev_params);
1898 if (FAILED(hr))
1899 return;
1901 origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) :
1902 get_cluster_range_width(layout, start, i);
1903 run = layout->clusters[i].run;
1904 start = i;
1907 prev_params = params;
1908 pos += layout->clustermetrics[i].length;
1911 /* Final run from what's left from cluster range */
1912 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, &prev_params);
1913 if (FAILED(hr))
1914 return;
1916 if (get_cluster_range_width(layout, start, i) + sign_metrics.width > layout->metrics.layoutWidth)
1917 append_trimming_run = FALSE;
1919 if (append_trimming_run) {
1920 struct layout_effective_inline *trimming_sign;
1922 trimming_sign = heap_alloc(sizeof(*trimming_sign));
1923 if (!trimming_sign)
1924 return;
1926 trimming_sign->object = layout->format.trimmingsign;
1927 trimming_sign->width = sign_metrics.width;
1928 origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) : get_cluster_range_width(layout, start, i);
1929 trimming_sign->origin.x = is_rtl ? origin_x - trimming_sign->width : origin_x;
1930 trimming_sign->origin.y = 0.0f; /* set after line is built */
1931 trimming_sign->align_dx = 0.0f;
1932 trimming_sign->baseline = sign_metrics.baseline;
1934 trimming_sign->is_sideways = FALSE;
1935 trimming_sign->is_rtl = FALSE;
1936 trimming_sign->line = line;
1938 trimming_sign->effect = layout_get_effect_from_pos(layout, layout->clusters[i].position +
1939 layout->clusters[i].run->start_position);
1941 list_add_tail(&layout->inlineobjects, &trimming_sign->entry);
1944 /* Look for max baseline and descent for this line */
1945 for (index = first_cluster, metrics.baseline = 0.0f, descent = 0.0f; index <= last_cluster; index++) {
1946 const struct layout_run *cur = layout->clusters[index].run;
1947 FLOAT cur_descent = cur->height - cur->baseline;
1949 if (cur->baseline > metrics.baseline)
1950 metrics.baseline = cur->baseline;
1951 if (cur_descent > descent)
1952 descent = cur_descent;
1955 layout->metrics.width = max(width, layout->metrics.width);
1956 layout->metrics.widthIncludingTrailingWhitespace = max(width + trailingspacewidth,
1957 layout->metrics.widthIncludingTrailingWhitespace);
1959 metrics.height = descent + metrics.baseline;
1960 metrics.isTrimmed = append_trimming_run || width > layout->metrics.layoutWidth;
1961 layout_set_line_metrics(layout, &metrics);
1963 *textpos += metrics.length;
1966 static void layout_set_line_positions(struct dwrite_textlayout *layout)
1968 struct layout_effective_inline *inrun;
1969 struct layout_effective_run *erun;
1970 FLOAT origin_y;
1971 UINT32 line;
1973 /* Now all line info is here, update effective runs positions in flow direction */
1974 erun = layout_get_next_erun(layout, NULL);
1975 inrun = layout_get_next_inline_run(layout, NULL);
1977 for (line = 0, origin_y = 0.0f; line < layout->metrics.lineCount; line++)
1979 float pos_y = origin_y + layout->lines[line].metrics.baseline;
1981 /* For all runs on this line */
1982 while (erun && erun->line == line) {
1983 erun->origin.y = pos_y;
1984 erun = layout_get_next_erun(layout, erun);
1987 /* Same for inline runs */
1988 while (inrun && inrun->line == line) {
1989 inrun->origin.y = pos_y - inrun->baseline;
1990 inrun = layout_get_next_inline_run(layout, inrun);
1993 origin_y += layout->lines[line].metrics.height;
1996 layout->metrics.height = origin_y;
1998 /* Initial paragraph alignment is always near */
1999 if (layout->format.paralign != DWRITE_PARAGRAPH_ALIGNMENT_NEAR)
2000 layout_apply_par_alignment(layout);
2003 static BOOL layout_can_wrap_after(const struct dwrite_textlayout *layout, UINT32 cluster)
2005 if (layout->format.wrapping == DWRITE_WORD_WRAPPING_CHARACTER)
2006 return TRUE;
2008 return layout->clustermetrics[cluster].canWrapLineAfter;
2011 static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
2013 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
2014 struct layout_effective_run *erun, *first_underlined;
2015 UINT32 i, start, textpos, last_breaking_point;
2016 DWRITE_LINE_METRICS1 metrics;
2017 FLOAT width;
2018 UINT32 line;
2019 HRESULT hr;
2021 if (!(layout->recompute & RECOMPUTE_LINES))
2022 return S_OK;
2024 free_layout_eruns(layout);
2026 hr = layout_compute(layout);
2027 if (FAILED(hr))
2028 return hr;
2030 layout->metrics.lineCount = 0;
2031 memset(&metrics, 0, sizeof(metrics));
2033 layout->metrics.height = 0.0f;
2034 layout->metrics.width = 0.0f;
2035 layout->metrics.widthIncludingTrailingWhitespace = 0.0f;
2037 last_breaking_point = ~0u;
2039 for (i = 0, start = 0, width = 0.0f, textpos = 0; i < layout->cluster_count; i++) {
2040 BOOL overflow = FALSE;
2042 while (i < layout->cluster_count && !layout->clustermetrics[i].isNewline) {
2043 /* Check for overflow */
2044 overflow = ((width + layout->clustermetrics[i].width > layout->metrics.layoutWidth) &&
2045 (layout->format.wrapping != DWRITE_WORD_WRAPPING_NO_WRAP));
2046 if (overflow)
2047 break;
2049 if (layout_can_wrap_after(layout, i))
2050 last_breaking_point = i;
2051 width += layout->clustermetrics[i].width;
2052 i++;
2054 i = min(i, layout->cluster_count - 1);
2056 /* Ignore if overflown on whitespace */
2057 if (overflow && !(layout->clustermetrics[i].isWhitespace && layout_can_wrap_after(layout, i))) {
2058 /* Use most recently found breaking point */
2059 if (last_breaking_point != ~0u) {
2060 i = last_breaking_point;
2061 last_breaking_point = ~0u;
2063 else {
2064 /* Otherwise proceed forward to next newline or breaking point */
2065 for (; i < layout->cluster_count; i++)
2066 if (layout_can_wrap_after(layout, i) || layout->clustermetrics[i].isNewline)
2067 break;
2070 i = min(i, layout->cluster_count - 1);
2072 layout_add_line(layout, start, i, &textpos);
2073 start = i + 1;
2074 width = 0.0f;
2077 /* Add dummy line if:
2078 - there's no text, metrics come from first range in this case;
2079 - last ended with a mandatory break, metrics come from last text position.
2081 if (layout->len == 0)
2082 hr = layout_set_dummy_line_metrics(layout, 0);
2083 else if (layout->cluster_count && layout->clustermetrics[layout->cluster_count - 1].isNewline)
2084 hr = layout_set_dummy_line_metrics(layout, layout->len - 1);
2085 if (FAILED(hr))
2086 return hr;
2088 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
2089 layout->metrics.top = 0.0f;
2090 layout->metrics.maxBidiReorderingDepth = 1; /* FIXME */
2092 /* Add explicit underlined runs */
2093 erun = layout_get_next_erun(layout, NULL);
2094 first_underlined = erun && erun->underlined ? erun : NULL;
2095 for (line = 0; line < layout->metrics.lineCount; line++) {
2096 while (erun && erun->line == line) {
2097 erun = layout_get_next_erun(layout, erun);
2099 if (first_underlined && (!erun || !erun->underlined)) {
2100 layout_add_underline(layout, first_underlined, erun);
2101 first_underlined = NULL;
2103 else if (!first_underlined && erun && erun->underlined)
2104 first_underlined = erun;
2108 /* Position runs in flow direction */
2109 layout_set_line_positions(layout);
2111 /* Initial alignment is always leading */
2112 if (layout->format.textalignment != DWRITE_TEXT_ALIGNMENT_LEADING)
2113 layout_apply_text_alignment(layout);
2115 layout->recompute &= ~RECOMPUTE_LINES;
2116 return hr;
2119 static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum layout_range_attr_kind attr,
2120 struct layout_range_attr_value *value)
2122 struct layout_range_spacing const *range_spacing = (struct layout_range_spacing*)h;
2123 struct layout_range_iface const *range_iface = (struct layout_range_iface*)h;
2124 struct layout_range_bool const *range_bool = (struct layout_range_bool*)h;
2125 struct layout_range const *range = (struct layout_range*)h;
2127 switch (attr) {
2128 case LAYOUT_RANGE_ATTR_WEIGHT:
2129 return range->weight == value->u.weight;
2130 case LAYOUT_RANGE_ATTR_STYLE:
2131 return range->style == value->u.style;
2132 case LAYOUT_RANGE_ATTR_STRETCH:
2133 return range->stretch == value->u.stretch;
2134 case LAYOUT_RANGE_ATTR_FONTSIZE:
2135 return range->fontsize == value->u.fontsize;
2136 case LAYOUT_RANGE_ATTR_INLINE:
2137 return range->object == value->u.object;
2138 case LAYOUT_RANGE_ATTR_EFFECT:
2139 return range_iface->iface == value->u.effect;
2140 case LAYOUT_RANGE_ATTR_UNDERLINE:
2141 return range_bool->value == value->u.underline;
2142 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2143 return range_bool->value == value->u.strikethrough;
2144 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2145 return range->pair_kerning == value->u.pair_kerning;
2146 case LAYOUT_RANGE_ATTR_FONTCOLL:
2147 return range->collection == value->u.collection;
2148 case LAYOUT_RANGE_ATTR_LOCALE:
2149 return strcmpiW(range->locale, value->u.locale) == 0;
2150 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2151 return strcmpW(range->fontfamily, value->u.fontfamily) == 0;
2152 case LAYOUT_RANGE_ATTR_SPACING:
2153 return range_spacing->leading == value->u.spacing.leading &&
2154 range_spacing->trailing == value->u.spacing.trailing &&
2155 range_spacing->min_advance == value->u.spacing.min_advance;
2156 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2157 return range_iface->iface == (IUnknown*)value->u.typography;
2158 default:
2162 return FALSE;
2165 static inline BOOL is_same_layout_attributes(struct layout_range_header const *hleft, struct layout_range_header const *hright)
2167 switch (hleft->kind)
2169 case LAYOUT_RANGE_REGULAR:
2171 struct layout_range const *left = (struct layout_range const*)hleft;
2172 struct layout_range const *right = (struct layout_range const*)hright;
2173 return left->weight == right->weight &&
2174 left->style == right->style &&
2175 left->stretch == right->stretch &&
2176 left->fontsize == right->fontsize &&
2177 left->object == right->object &&
2178 left->pair_kerning == right->pair_kerning &&
2179 left->collection == right->collection &&
2180 !strcmpiW(left->locale, right->locale) &&
2181 !strcmpW(left->fontfamily, right->fontfamily);
2183 case LAYOUT_RANGE_UNDERLINE:
2184 case LAYOUT_RANGE_STRIKETHROUGH:
2186 struct layout_range_bool const *left = (struct layout_range_bool const*)hleft;
2187 struct layout_range_bool const *right = (struct layout_range_bool const*)hright;
2188 return left->value == right->value;
2190 case LAYOUT_RANGE_EFFECT:
2191 case LAYOUT_RANGE_TYPOGRAPHY:
2193 struct layout_range_iface const *left = (struct layout_range_iface const*)hleft;
2194 struct layout_range_iface const *right = (struct layout_range_iface const*)hright;
2195 return left->iface == right->iface;
2197 case LAYOUT_RANGE_SPACING:
2199 struct layout_range_spacing const *left = (struct layout_range_spacing const*)hleft;
2200 struct layout_range_spacing const *right = (struct layout_range_spacing const*)hright;
2201 return left->leading == right->leading &&
2202 left->trailing == right->trailing &&
2203 left->min_advance == right->min_advance;
2205 default:
2206 FIXME("unknown range kind %d\n", hleft->kind);
2207 return FALSE;
2211 static inline BOOL is_same_text_range(const DWRITE_TEXT_RANGE *left, const DWRITE_TEXT_RANGE *right)
2213 return left->startPosition == right->startPosition && left->length == right->length;
2216 /* Allocates range and inits it with default values from text format. */
2217 static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout *layout, const DWRITE_TEXT_RANGE *r,
2218 enum layout_range_kind kind)
2220 struct layout_range_header *h;
2222 switch (kind)
2224 case LAYOUT_RANGE_REGULAR:
2226 struct layout_range *range;
2228 range = heap_alloc(sizeof(*range));
2229 if (!range) return NULL;
2231 range->weight = layout->format.weight;
2232 range->style = layout->format.style;
2233 range->stretch = layout->format.stretch;
2234 range->fontsize = layout->format.fontsize;
2235 range->object = NULL;
2236 range->pair_kerning = FALSE;
2238 range->fontfamily = heap_strdupW(layout->format.family_name);
2239 if (!range->fontfamily) {
2240 heap_free(range);
2241 return NULL;
2244 range->collection = layout->format.collection;
2245 if (range->collection)
2246 IDWriteFontCollection_AddRef(range->collection);
2247 strcpyW(range->locale, layout->format.locale);
2249 h = &range->h;
2250 break;
2252 case LAYOUT_RANGE_UNDERLINE:
2253 case LAYOUT_RANGE_STRIKETHROUGH:
2255 struct layout_range_bool *range;
2257 range = heap_alloc(sizeof(*range));
2258 if (!range) return NULL;
2260 range->value = FALSE;
2261 h = &range->h;
2262 break;
2264 case LAYOUT_RANGE_EFFECT:
2265 case LAYOUT_RANGE_TYPOGRAPHY:
2267 struct layout_range_iface *range;
2269 range = heap_alloc(sizeof(*range));
2270 if (!range) return NULL;
2272 range->iface = NULL;
2273 h = &range->h;
2274 break;
2276 case LAYOUT_RANGE_SPACING:
2278 struct layout_range_spacing *range;
2280 range = heap_alloc(sizeof(*range));
2281 if (!range) return NULL;
2283 range->leading = 0.0f;
2284 range->trailing = 0.0f;
2285 range->min_advance = 0.0f;
2286 h = &range->h;
2287 break;
2289 default:
2290 FIXME("unknown range kind %d\n", kind);
2291 return NULL;
2294 h->kind = kind;
2295 h->range = *r;
2296 return h;
2299 static struct layout_range_header *alloc_layout_range_from(struct layout_range_header *h, const DWRITE_TEXT_RANGE *r)
2301 struct layout_range_header *ret;
2303 switch (h->kind)
2305 case LAYOUT_RANGE_REGULAR:
2307 struct layout_range *from = (struct layout_range*)h;
2309 struct layout_range *range = heap_alloc(sizeof(*range));
2310 if (!range) return NULL;
2312 *range = *from;
2313 range->fontfamily = heap_strdupW(from->fontfamily);
2314 if (!range->fontfamily) {
2315 heap_free(range);
2316 return NULL;
2319 /* update refcounts */
2320 if (range->object)
2321 IDWriteInlineObject_AddRef(range->object);
2322 if (range->collection)
2323 IDWriteFontCollection_AddRef(range->collection);
2324 ret = &range->h;
2325 break;
2327 case LAYOUT_RANGE_UNDERLINE:
2328 case LAYOUT_RANGE_STRIKETHROUGH:
2330 struct layout_range_bool *strike = heap_alloc(sizeof(*strike));
2331 if (!strike) return NULL;
2333 *strike = *(struct layout_range_bool*)h;
2334 ret = &strike->h;
2335 break;
2337 case LAYOUT_RANGE_EFFECT:
2338 case LAYOUT_RANGE_TYPOGRAPHY:
2340 struct layout_range_iface *effect = heap_alloc(sizeof(*effect));
2341 if (!effect) return NULL;
2343 *effect = *(struct layout_range_iface*)h;
2344 if (effect->iface)
2345 IUnknown_AddRef(effect->iface);
2346 ret = &effect->h;
2347 break;
2349 case LAYOUT_RANGE_SPACING:
2351 struct layout_range_spacing *spacing = heap_alloc(sizeof(*spacing));
2352 if (!spacing) return NULL;
2354 *spacing = *(struct layout_range_spacing*)h;
2355 ret = &spacing->h;
2356 break;
2358 default:
2359 FIXME("unknown range kind %d\n", h->kind);
2360 return NULL;
2363 ret->range = *r;
2364 return ret;
2367 static void free_layout_range(struct layout_range_header *h)
2369 if (!h)
2370 return;
2372 switch (h->kind)
2374 case LAYOUT_RANGE_REGULAR:
2376 struct layout_range *range = (struct layout_range*)h;
2378 if (range->object)
2379 IDWriteInlineObject_Release(range->object);
2380 if (range->collection)
2381 IDWriteFontCollection_Release(range->collection);
2382 heap_free(range->fontfamily);
2383 break;
2385 case LAYOUT_RANGE_EFFECT:
2386 case LAYOUT_RANGE_TYPOGRAPHY:
2388 struct layout_range_iface *range = (struct layout_range_iface*)h;
2389 if (range->iface)
2390 IUnknown_Release(range->iface);
2391 break;
2393 default:
2397 heap_free(h);
2400 static void free_layout_ranges_list(struct dwrite_textlayout *layout)
2402 struct layout_range_header *cur, *cur2;
2404 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->ranges, struct layout_range_header, entry) {
2405 list_remove(&cur->entry);
2406 free_layout_range(cur);
2409 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->underline_ranges, struct layout_range_header, entry) {
2410 list_remove(&cur->entry);
2411 free_layout_range(cur);
2414 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->strike_ranges, struct layout_range_header, entry) {
2415 list_remove(&cur->entry);
2416 free_layout_range(cur);
2419 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->effects, struct layout_range_header, entry) {
2420 list_remove(&cur->entry);
2421 free_layout_range(cur);
2424 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->spacing, struct layout_range_header, entry) {
2425 list_remove(&cur->entry);
2426 free_layout_range(cur);
2429 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->typographies, struct layout_range_header, entry) {
2430 list_remove(&cur->entry);
2431 free_layout_range(cur);
2435 static struct layout_range_header *find_outer_range(struct list *ranges, const DWRITE_TEXT_RANGE *range)
2437 struct layout_range_header *cur;
2439 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
2441 if (cur->range.startPosition > range->startPosition)
2442 return NULL;
2444 if ((cur->range.startPosition + cur->range.length < range->startPosition + range->length) &&
2445 (range->startPosition < cur->range.startPosition + cur->range.length))
2446 return NULL;
2447 if (cur->range.startPosition + cur->range.length >= range->startPosition + range->length)
2448 return cur;
2451 return NULL;
2454 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos)
2456 struct layout_range *cur;
2458 LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, h.entry) {
2459 DWRITE_TEXT_RANGE *r = &cur->h.range;
2460 if (r->startPosition <= pos && pos < r->startPosition + r->length)
2461 return cur;
2464 return NULL;
2467 static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
2469 if (*dest == value) return FALSE;
2471 if (*dest)
2472 IUnknown_Release(*dest);
2473 *dest = value;
2474 if (*dest)
2475 IUnknown_AddRef(*dest);
2477 return TRUE;
2480 static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2482 struct layout_range_spacing *dest_spacing = (struct layout_range_spacing*)h;
2483 struct layout_range_iface *dest_iface = (struct layout_range_iface*)h;
2484 struct layout_range_bool *dest_bool = (struct layout_range_bool*)h;
2485 struct layout_range *dest = (struct layout_range*)h;
2487 BOOL changed = FALSE;
2489 switch (attr) {
2490 case LAYOUT_RANGE_ATTR_WEIGHT:
2491 changed = dest->weight != value->u.weight;
2492 dest->weight = value->u.weight;
2493 break;
2494 case LAYOUT_RANGE_ATTR_STYLE:
2495 changed = dest->style != value->u.style;
2496 dest->style = value->u.style;
2497 break;
2498 case LAYOUT_RANGE_ATTR_STRETCH:
2499 changed = dest->stretch != value->u.stretch;
2500 dest->stretch = value->u.stretch;
2501 break;
2502 case LAYOUT_RANGE_ATTR_FONTSIZE:
2503 changed = dest->fontsize != value->u.fontsize;
2504 dest->fontsize = value->u.fontsize;
2505 break;
2506 case LAYOUT_RANGE_ATTR_INLINE:
2507 changed = set_layout_range_iface_attr((IUnknown**)&dest->object, (IUnknown*)value->u.object);
2508 break;
2509 case LAYOUT_RANGE_ATTR_EFFECT:
2510 changed = set_layout_range_iface_attr(&dest_iface->iface, value->u.effect);
2511 break;
2512 case LAYOUT_RANGE_ATTR_UNDERLINE:
2513 changed = dest_bool->value != value->u.underline;
2514 dest_bool->value = value->u.underline;
2515 break;
2516 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2517 changed = dest_bool->value != value->u.strikethrough;
2518 dest_bool->value = value->u.strikethrough;
2519 break;
2520 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2521 changed = dest->pair_kerning != value->u.pair_kerning;
2522 dest->pair_kerning = value->u.pair_kerning;
2523 break;
2524 case LAYOUT_RANGE_ATTR_FONTCOLL:
2525 changed = set_layout_range_iface_attr((IUnknown**)&dest->collection, (IUnknown*)value->u.collection);
2526 break;
2527 case LAYOUT_RANGE_ATTR_LOCALE:
2528 changed = strcmpiW(dest->locale, value->u.locale) != 0;
2529 if (changed) {
2530 strcpyW(dest->locale, value->u.locale);
2531 strlwrW(dest->locale);
2533 break;
2534 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2535 changed = strcmpW(dest->fontfamily, value->u.fontfamily) != 0;
2536 if (changed) {
2537 heap_free(dest->fontfamily);
2538 dest->fontfamily = heap_strdupW(value->u.fontfamily);
2540 break;
2541 case LAYOUT_RANGE_ATTR_SPACING:
2542 changed = dest_spacing->leading != value->u.spacing.leading ||
2543 dest_spacing->trailing != value->u.spacing.trailing ||
2544 dest_spacing->min_advance != value->u.spacing.min_advance;
2545 dest_spacing->leading = value->u.spacing.leading;
2546 dest_spacing->trailing = value->u.spacing.trailing;
2547 dest_spacing->min_advance = value->u.spacing.min_advance;
2548 break;
2549 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2550 changed = set_layout_range_iface_attr(&dest_iface->iface, (IUnknown*)value->u.typography);
2551 break;
2552 default:
2556 return changed;
2559 static inline BOOL is_in_layout_range(const DWRITE_TEXT_RANGE *outer, const DWRITE_TEXT_RANGE *inner)
2561 return (inner->startPosition >= outer->startPosition) &&
2562 (inner->startPosition + inner->length <= outer->startPosition + outer->length);
2565 static inline HRESULT return_range(const struct layout_range_header *h, DWRITE_TEXT_RANGE *r)
2567 if (r) *r = h->range;
2568 return S_OK;
2571 /* Sets attribute value for given range, does all needed splitting/merging of existing ranges. */
2572 static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2574 struct layout_range_header *cur, *right, *left, *outer;
2575 BOOL changed = FALSE;
2576 struct list *ranges;
2577 DWRITE_TEXT_RANGE r;
2579 /* ignore zero length ranges */
2580 if (value->range.length == 0)
2581 return S_OK;
2583 /* select from ranges lists */
2584 switch (attr)
2586 case LAYOUT_RANGE_ATTR_WEIGHT:
2587 case LAYOUT_RANGE_ATTR_STYLE:
2588 case LAYOUT_RANGE_ATTR_STRETCH:
2589 case LAYOUT_RANGE_ATTR_FONTSIZE:
2590 case LAYOUT_RANGE_ATTR_INLINE:
2591 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2592 case LAYOUT_RANGE_ATTR_FONTCOLL:
2593 case LAYOUT_RANGE_ATTR_LOCALE:
2594 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2595 ranges = &layout->ranges;
2596 break;
2597 case LAYOUT_RANGE_ATTR_UNDERLINE:
2598 ranges = &layout->underline_ranges;
2599 break;
2600 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2601 ranges = &layout->strike_ranges;
2602 break;
2603 case LAYOUT_RANGE_ATTR_EFFECT:
2604 ranges = &layout->effects;
2605 break;
2606 case LAYOUT_RANGE_ATTR_SPACING:
2607 ranges = &layout->spacing;
2608 break;
2609 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2610 ranges = &layout->typographies;
2611 break;
2612 default:
2613 FIXME("unknown attr kind %d\n", attr);
2614 return E_FAIL;
2617 /* If new range is completely within existing range, split existing range in two */
2618 if ((outer = find_outer_range(ranges, &value->range))) {
2620 /* no need to add same range */
2621 if (is_same_layout_attrvalue(outer, attr, value))
2622 return S_OK;
2624 /* for matching range bounds just replace data */
2625 if (is_same_text_range(&outer->range, &value->range)) {
2626 changed = set_layout_range_attrval(outer, attr, value);
2627 goto done;
2630 /* add new range to the left */
2631 if (value->range.startPosition == outer->range.startPosition) {
2632 left = alloc_layout_range_from(outer, &value->range);
2633 if (!left) return E_OUTOFMEMORY;
2635 changed = set_layout_range_attrval(left, attr, value);
2636 list_add_before(&outer->entry, &left->entry);
2637 outer->range.startPosition += value->range.length;
2638 outer->range.length -= value->range.length;
2639 goto done;
2642 /* add new range to the right */
2643 if (value->range.startPosition + value->range.length == outer->range.startPosition + outer->range.length) {
2644 right = alloc_layout_range_from(outer, &value->range);
2645 if (!right) return E_OUTOFMEMORY;
2647 changed = set_layout_range_attrval(right, attr, value);
2648 list_add_after(&outer->entry, &right->entry);
2649 outer->range.length -= value->range.length;
2650 goto done;
2653 r.startPosition = value->range.startPosition + value->range.length;
2654 r.length = outer->range.length + outer->range.startPosition - r.startPosition;
2656 /* right part */
2657 right = alloc_layout_range_from(outer, &r);
2658 /* new range in the middle */
2659 cur = alloc_layout_range_from(outer, &value->range);
2660 if (!right || !cur) {
2661 free_layout_range(right);
2662 free_layout_range(cur);
2663 return E_OUTOFMEMORY;
2666 /* reuse container range as a left part */
2667 outer->range.length = value->range.startPosition - outer->range.startPosition;
2669 /* new part */
2670 set_layout_range_attrval(cur, attr, value);
2672 list_add_after(&outer->entry, &cur->entry);
2673 list_add_after(&cur->entry, &right->entry);
2675 layout->recompute = RECOMPUTE_EVERYTHING;
2676 return S_OK;
2679 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2680 Update all of them. */
2681 left = get_layout_range_header_by_pos(ranges, value->range.startPosition);
2682 if (left->range.startPosition == value->range.startPosition)
2683 changed = set_layout_range_attrval(left, attr, value);
2684 else /* need to split */ {
2685 r.startPosition = value->range.startPosition;
2686 r.length = left->range.length - value->range.startPosition + left->range.startPosition;
2687 left->range.length -= r.length;
2688 cur = alloc_layout_range_from(left, &r);
2689 changed = set_layout_range_attrval(cur, attr, value);
2690 list_add_after(&left->entry, &cur->entry);
2692 cur = LIST_ENTRY(list_next(ranges, &left->entry), struct layout_range_header, entry);
2694 /* for all existing ranges covered by new one update value */
2695 while (cur && is_in_layout_range(&value->range, &cur->range)) {
2696 changed |= set_layout_range_attrval(cur, attr, value);
2697 cur = LIST_ENTRY(list_next(ranges, &cur->entry), struct layout_range_header, entry);
2700 /* it's possible rightmost range intersects */
2701 if (cur && (cur->range.startPosition < value->range.startPosition + value->range.length)) {
2702 r.startPosition = cur->range.startPosition;
2703 r.length = value->range.startPosition + value->range.length - cur->range.startPosition;
2704 left = alloc_layout_range_from(cur, &r);
2705 changed |= set_layout_range_attrval(left, attr, value);
2706 cur->range.startPosition += left->range.length;
2707 cur->range.length -= left->range.length;
2708 list_add_before(&cur->entry, &left->entry);
2711 done:
2712 if (changed) {
2713 struct list *next, *i;
2715 layout->recompute = RECOMPUTE_EVERYTHING;
2716 i = list_head(ranges);
2717 while ((next = list_next(ranges, i))) {
2718 struct layout_range_header *next_range = LIST_ENTRY(next, struct layout_range_header, entry);
2720 cur = LIST_ENTRY(i, struct layout_range_header, entry);
2721 if (is_same_layout_attributes(cur, next_range)) {
2722 /* remove similar range */
2723 cur->range.length += next_range->range.length;
2724 list_remove(next);
2725 free_layout_range(next_range);
2727 else
2728 i = list_next(ranges, i);
2732 return S_OK;
2735 static inline const WCHAR *get_string_attribute_ptr(struct layout_range *range, enum layout_range_attr_kind kind)
2737 const WCHAR *str;
2739 switch (kind) {
2740 case LAYOUT_RANGE_ATTR_LOCALE:
2741 str = range->locale;
2742 break;
2743 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2744 str = range->fontfamily;
2745 break;
2746 default:
2747 str = NULL;
2750 return str;
2753 static HRESULT get_string_attribute_length(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2754 UINT32 *length, DWRITE_TEXT_RANGE *r)
2756 struct layout_range *range;
2757 const WCHAR *str;
2759 range = get_layout_range_by_pos(layout, position);
2760 if (!range) {
2761 *length = 0;
2762 return S_OK;
2765 str = get_string_attribute_ptr(range, kind);
2766 *length = strlenW(str);
2767 return return_range(&range->h, r);
2770 static HRESULT get_string_attribute_value(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2771 WCHAR *ret, UINT32 length, DWRITE_TEXT_RANGE *r)
2773 struct layout_range *range;
2774 const WCHAR *str;
2776 if (length == 0)
2777 return E_INVALIDARG;
2779 ret[0] = 0;
2780 range = get_layout_range_by_pos(layout, position);
2781 if (!range)
2782 return E_INVALIDARG;
2784 str = get_string_attribute_ptr(range, kind);
2785 if (length < strlenW(str) + 1)
2786 return E_NOT_SUFFICIENT_BUFFER;
2788 strcpyW(ret, str);
2789 return return_range(&range->h, r);
2792 static HRESULT WINAPI dwritetextlayout_QueryInterface(IDWriteTextLayout4 *iface, REFIID riid, void **obj)
2794 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2796 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2798 *obj = NULL;
2800 if (IsEqualIID(riid, &IID_IDWriteTextLayout4) ||
2801 IsEqualIID(riid, &IID_IDWriteTextLayout3) ||
2802 IsEqualIID(riid, &IID_IDWriteTextLayout2) ||
2803 IsEqualIID(riid, &IID_IDWriteTextLayout1) ||
2804 IsEqualIID(riid, &IID_IDWriteTextLayout) ||
2805 IsEqualIID(riid, &IID_IUnknown))
2807 *obj = iface;
2809 else if (IsEqualIID(riid, &IID_IDWriteTextFormat3) ||
2810 IsEqualIID(riid, &IID_IDWriteTextFormat2) ||
2811 IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
2812 IsEqualIID(riid, &IID_IDWriteTextFormat))
2814 *obj = &layout->IDWriteTextFormat3_iface;
2817 if (*obj) {
2818 IDWriteTextLayout4_AddRef(iface);
2819 return S_OK;
2822 WARN("%s not implemented.\n", debugstr_guid(riid));
2824 return E_NOINTERFACE;
2827 static ULONG WINAPI dwritetextlayout_AddRef(IDWriteTextLayout4 *iface)
2829 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2830 ULONG refcount = InterlockedIncrement(&layout->refcount);
2832 TRACE("%p, refcount %u.\n", iface, refcount);
2834 return refcount;
2837 static ULONG WINAPI dwritetextlayout_Release(IDWriteTextLayout4 *iface)
2839 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2840 ULONG refcount = InterlockedDecrement(&layout->refcount);
2842 TRACE("%p, refcount %u.\n", iface, refcount);
2844 if (!refcount)
2846 IDWriteFactory7_Release(layout->factory);
2847 free_layout_ranges_list(layout);
2848 free_layout_eruns(layout);
2849 free_layout_runs(layout);
2850 release_format_data(&layout->format);
2851 heap_free(layout->nominal_breakpoints);
2852 heap_free(layout->actual_breakpoints);
2853 heap_free(layout->clustermetrics);
2854 heap_free(layout->clusters);
2855 heap_free(layout->lines);
2856 heap_free(layout->str);
2857 heap_free(layout);
2860 return refcount;
2863 static HRESULT WINAPI dwritetextlayout_SetTextAlignment(IDWriteTextLayout4 *iface, DWRITE_TEXT_ALIGNMENT alignment)
2865 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2866 return IDWriteTextFormat3_SetTextAlignment(&layout->IDWriteTextFormat3_iface, alignment);
2869 static HRESULT WINAPI dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout4 *iface,
2870 DWRITE_PARAGRAPH_ALIGNMENT alignment)
2872 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2873 return IDWriteTextFormat3_SetParagraphAlignment(&layout->IDWriteTextFormat3_iface, alignment);
2876 static HRESULT WINAPI dwritetextlayout_SetWordWrapping(IDWriteTextLayout4 *iface, DWRITE_WORD_WRAPPING wrapping)
2878 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2879 return IDWriteTextFormat3_SetWordWrapping(&layout->IDWriteTextFormat3_iface, wrapping);
2882 static HRESULT WINAPI dwritetextlayout_SetReadingDirection(IDWriteTextLayout4 *iface,
2883 DWRITE_READING_DIRECTION direction)
2885 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2886 return IDWriteTextFormat3_SetReadingDirection(&layout->IDWriteTextFormat3_iface, direction);
2889 static HRESULT WINAPI dwritetextlayout_SetFlowDirection(IDWriteTextLayout4 *iface, DWRITE_FLOW_DIRECTION direction)
2891 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2892 return IDWriteTextFormat3_SetFlowDirection(&layout->IDWriteTextFormat3_iface, direction);
2895 static HRESULT WINAPI dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout4 *iface, FLOAT tabstop)
2897 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2898 return IDWriteTextFormat3_SetIncrementalTabStop(&layout->IDWriteTextFormat3_iface, tabstop);
2901 static HRESULT WINAPI dwritetextlayout_SetTrimming(IDWriteTextLayout4 *iface, DWRITE_TRIMMING const *trimming,
2902 IDWriteInlineObject *trimming_sign)
2904 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2905 return IDWriteTextFormat3_SetTrimming(&layout->IDWriteTextFormat3_iface, trimming, trimming_sign);
2908 static HRESULT WINAPI dwritetextlayout_SetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING_METHOD spacing,
2909 FLOAT line_spacing, FLOAT baseline)
2911 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2912 return IDWriteTextFormat1_SetLineSpacing((IDWriteTextFormat1 *)&layout->IDWriteTextFormat3_iface, spacing,
2913 line_spacing, baseline);
2916 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextlayout_GetTextAlignment(IDWriteTextLayout4 *iface)
2918 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2919 return IDWriteTextFormat3_GetTextAlignment(&layout->IDWriteTextFormat3_iface);
2922 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout4 *iface)
2924 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2925 return IDWriteTextFormat3_GetParagraphAlignment(&layout->IDWriteTextFormat3_iface);
2928 static DWRITE_WORD_WRAPPING WINAPI dwritetextlayout_GetWordWrapping(IDWriteTextLayout4 *iface)
2930 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2931 return IDWriteTextFormat3_GetWordWrapping(&layout->IDWriteTextFormat3_iface);
2934 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_GetReadingDirection(IDWriteTextLayout4 *iface)
2936 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2937 return IDWriteTextFormat3_GetReadingDirection(&layout->IDWriteTextFormat3_iface);
2940 static DWRITE_FLOW_DIRECTION WINAPI dwritetextlayout_GetFlowDirection(IDWriteTextLayout4 *iface)
2942 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2943 return IDWriteTextFormat3_GetFlowDirection(&layout->IDWriteTextFormat3_iface);
2946 static FLOAT WINAPI dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout4 *iface)
2948 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2949 return IDWriteTextFormat3_GetIncrementalTabStop(&layout->IDWriteTextFormat3_iface);
2952 static HRESULT WINAPI dwritetextlayout_GetTrimming(IDWriteTextLayout4 *iface, DWRITE_TRIMMING *options,
2953 IDWriteInlineObject **trimming_sign)
2955 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2956 return IDWriteTextFormat3_GetTrimming(&layout->IDWriteTextFormat3_iface, options, trimming_sign);
2959 static HRESULT WINAPI dwritetextlayout_GetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING_METHOD *method,
2960 FLOAT *spacing, FLOAT *baseline)
2962 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2963 return IDWriteTextFormat_GetLineSpacing((IDWriteTextFormat *)&layout->IDWriteTextFormat3_iface, method,
2964 spacing, baseline);
2967 static HRESULT WINAPI dwritetextlayout_GetFontCollection(IDWriteTextLayout4 *iface, IDWriteFontCollection **collection)
2969 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2970 return IDWriteTextFormat3_GetFontCollection(&layout->IDWriteTextFormat3_iface, collection);
2973 static UINT32 WINAPI dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout4 *iface)
2975 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2976 return IDWriteTextFormat3_GetFontFamilyNameLength(&layout->IDWriteTextFormat3_iface);
2979 static HRESULT WINAPI dwritetextlayout_GetFontFamilyName(IDWriteTextLayout4 *iface, WCHAR *name, UINT32 size)
2981 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2982 return IDWriteTextFormat3_GetFontFamilyName(&layout->IDWriteTextFormat3_iface, name, size);
2985 static DWRITE_FONT_WEIGHT WINAPI dwritetextlayout_GetFontWeight(IDWriteTextLayout4 *iface)
2987 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2988 return IDWriteTextFormat3_GetFontWeight(&layout->IDWriteTextFormat3_iface);
2991 static DWRITE_FONT_STYLE WINAPI dwritetextlayout_GetFontStyle(IDWriteTextLayout4 *iface)
2993 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2994 return IDWriteTextFormat3_GetFontStyle(&layout->IDWriteTextFormat3_iface);
2997 static DWRITE_FONT_STRETCH WINAPI dwritetextlayout_GetFontStretch(IDWriteTextLayout4 *iface)
2999 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3000 return IDWriteTextFormat3_GetFontStretch(&layout->IDWriteTextFormat3_iface);
3003 static FLOAT WINAPI dwritetextlayout_GetFontSize(IDWriteTextLayout4 *iface)
3005 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3006 return IDWriteTextFormat3_GetFontSize(&layout->IDWriteTextFormat3_iface);
3009 static UINT32 WINAPI dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout4 *iface)
3011 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3012 return IDWriteTextFormat3_GetLocaleNameLength(&layout->IDWriteTextFormat3_iface);
3015 static HRESULT WINAPI dwritetextlayout_GetLocaleName(IDWriteTextLayout4 *iface, WCHAR *name, UINT32 size)
3017 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3018 return IDWriteTextFormat3_GetLocaleName(&layout->IDWriteTextFormat3_iface, name, size);
3021 static HRESULT WINAPI dwritetextlayout_SetMaxWidth(IDWriteTextLayout4 *iface, FLOAT maxWidth)
3023 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3024 BOOL changed;
3026 TRACE("%p, %.8e.\n", iface, maxWidth);
3028 if (maxWidth < 0.0f)
3029 return E_INVALIDARG;
3031 changed = layout->metrics.layoutWidth != maxWidth;
3032 layout->metrics.layoutWidth = maxWidth;
3034 if (changed)
3035 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
3036 return S_OK;
3039 static HRESULT WINAPI dwritetextlayout_SetMaxHeight(IDWriteTextLayout4 *iface, FLOAT maxHeight)
3041 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3042 BOOL changed;
3044 TRACE("%p, %.8e.\n", iface, maxHeight);
3046 if (maxHeight < 0.0f)
3047 return E_INVALIDARG;
3049 changed = layout->metrics.layoutHeight != maxHeight;
3050 layout->metrics.layoutHeight = maxHeight;
3052 if (changed)
3053 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
3054 return S_OK;
3057 static HRESULT WINAPI dwritetextlayout_SetFontCollection(IDWriteTextLayout4 *iface, IDWriteFontCollection *collection,
3058 DWRITE_TEXT_RANGE range)
3060 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3061 struct layout_range_attr_value value;
3063 TRACE("%p, %p, %s.\n", iface, collection, debugstr_range(&range));
3065 value.range = range;
3066 value.u.collection = collection;
3067 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_FONTCOLL, &value);
3070 static HRESULT WINAPI dwritetextlayout_SetFontFamilyName(IDWriteTextLayout4 *iface, WCHAR const *name,
3071 DWRITE_TEXT_RANGE range)
3073 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3074 struct layout_range_attr_value value;
3076 TRACE("%p, %s, %s.\n", iface, debugstr_w(name), debugstr_range(&range));
3078 if (!name)
3079 return E_INVALIDARG;
3081 value.range = range;
3082 value.u.fontfamily = name;
3083 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_FONTFAMILY, &value);
3086 static HRESULT WINAPI dwritetextlayout_SetFontWeight(IDWriteTextLayout4 *iface, DWRITE_FONT_WEIGHT weight,
3087 DWRITE_TEXT_RANGE range)
3089 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3090 struct layout_range_attr_value value;
3092 TRACE("%p, %d, %s.\n", iface, weight, debugstr_range(&range));
3094 if ((UINT32)weight > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
3095 return E_INVALIDARG;
3097 value.range = range;
3098 value.u.weight = weight;
3099 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_WEIGHT, &value);
3102 static HRESULT WINAPI dwritetextlayout_SetFontStyle(IDWriteTextLayout4 *iface, DWRITE_FONT_STYLE style,
3103 DWRITE_TEXT_RANGE range)
3105 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3106 struct layout_range_attr_value value;
3108 TRACE("%p, %d, %s.\n", iface, style, debugstr_range(&range));
3110 if ((UINT32)style > DWRITE_FONT_STYLE_ITALIC)
3111 return E_INVALIDARG;
3113 value.range = range;
3114 value.u.style = style;
3115 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_STYLE, &value);
3118 static HRESULT WINAPI dwritetextlayout_SetFontStretch(IDWriteTextLayout4 *iface, DWRITE_FONT_STRETCH stretch,
3119 DWRITE_TEXT_RANGE range)
3121 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3122 struct layout_range_attr_value value;
3124 TRACE("%p, %d, %s.\n", iface, stretch, debugstr_range(&range));
3126 if (stretch == DWRITE_FONT_STRETCH_UNDEFINED || (UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
3127 return E_INVALIDARG;
3129 value.range = range;
3130 value.u.stretch = stretch;
3131 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_STRETCH, &value);
3134 static HRESULT WINAPI dwritetextlayout_SetFontSize(IDWriteTextLayout4 *iface, FLOAT size, DWRITE_TEXT_RANGE range)
3136 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3137 struct layout_range_attr_value value;
3139 TRACE("%p, %.8e, %s.\n", iface, size, debugstr_range(&range));
3141 if (size <= 0.0f)
3142 return E_INVALIDARG;
3144 value.range = range;
3145 value.u.fontsize = size;
3146 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_FONTSIZE, &value);
3149 static HRESULT WINAPI dwritetextlayout_SetUnderline(IDWriteTextLayout4 *iface, BOOL underline, DWRITE_TEXT_RANGE range)
3151 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3152 struct layout_range_attr_value value;
3154 TRACE("%p, %d, %s.\n", iface, underline, debugstr_range(&range));
3156 value.range = range;
3157 value.u.underline = underline;
3158 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_UNDERLINE, &value);
3161 static HRESULT WINAPI dwritetextlayout_SetStrikethrough(IDWriteTextLayout4 *iface, BOOL strikethrough,
3162 DWRITE_TEXT_RANGE range)
3164 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3165 struct layout_range_attr_value value;
3167 TRACE("%p, %d, %s.\n", iface, strikethrough, debugstr_range(&range));
3169 value.range = range;
3170 value.u.strikethrough = strikethrough;
3171 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_STRIKETHROUGH, &value);
3174 static HRESULT WINAPI dwritetextlayout_SetDrawingEffect(IDWriteTextLayout4 *iface, IUnknown* effect,
3175 DWRITE_TEXT_RANGE range)
3177 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3178 struct layout_range_attr_value value;
3180 TRACE("%p, %p, %s.\n", iface, effect, debugstr_range(&range));
3182 value.range = range;
3183 value.u.effect = effect;
3184 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_EFFECT, &value);
3187 static HRESULT WINAPI dwritetextlayout_SetInlineObject(IDWriteTextLayout4 *iface, IDWriteInlineObject *object,
3188 DWRITE_TEXT_RANGE range)
3190 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3191 struct layout_range_attr_value value;
3193 TRACE("%p, %p, %s.\n", iface, object, debugstr_range(&range));
3195 value.range = range;
3196 value.u.object = object;
3197 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_INLINE, &value);
3200 static HRESULT WINAPI dwritetextlayout_SetTypography(IDWriteTextLayout4 *iface, IDWriteTypography *typography,
3201 DWRITE_TEXT_RANGE range)
3203 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3204 struct layout_range_attr_value value;
3206 TRACE("%p, %p, %s.\n", iface, typography, debugstr_range(&range));
3208 value.range = range;
3209 value.u.typography = typography;
3210 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_TYPOGRAPHY, &value);
3213 static HRESULT WINAPI dwritetextlayout_SetLocaleName(IDWriteTextLayout4 *iface, WCHAR const* locale,
3214 DWRITE_TEXT_RANGE range)
3216 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3217 struct layout_range_attr_value value;
3219 TRACE("%p, %s, %s.\n", iface, debugstr_w(locale), debugstr_range(&range));
3221 if (!locale || strlenW(locale) > LOCALE_NAME_MAX_LENGTH-1)
3222 return E_INVALIDARG;
3224 value.range = range;
3225 value.u.locale = locale;
3226 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_LOCALE, &value);
3229 static FLOAT WINAPI dwritetextlayout_GetMaxWidth(IDWriteTextLayout4 *iface)
3231 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3233 TRACE("%p.\n", iface);
3235 return layout->metrics.layoutWidth;
3238 static FLOAT WINAPI dwritetextlayout_GetMaxHeight(IDWriteTextLayout4 *iface)
3240 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3242 TRACE("%p.\n", iface);
3244 return layout->metrics.layoutHeight;
3247 static HRESULT WINAPI dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout4 *iface, UINT32 position,
3248 IDWriteFontCollection **collection, DWRITE_TEXT_RANGE *r)
3250 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3251 struct layout_range *range;
3253 TRACE("%p, %u, %p, %p.\n", iface, position, collection, r);
3255 if (position >= layout->len)
3256 return S_OK;
3258 range = get_layout_range_by_pos(layout, position);
3259 *collection = range->collection;
3260 if (*collection)
3261 IDWriteFontCollection_AddRef(*collection);
3263 return return_range(&range->h, r);
3266 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout4 *iface,
3267 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
3269 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3271 TRACE("%p, %d, %p, %p.\n", iface, position, length, r);
3273 return get_string_attribute_length(layout, LAYOUT_RANGE_ATTR_FONTFAMILY, position, length, r);
3276 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout4 *iface,
3277 UINT32 position, WCHAR *name, UINT32 length, DWRITE_TEXT_RANGE *r)
3279 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3281 TRACE("%p, %u, %p, %u, %p.\n", iface, position, name, length, r);
3283 return get_string_attribute_value(layout, LAYOUT_RANGE_ATTR_FONTFAMILY, position, name, length, r);
3286 static HRESULT WINAPI dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout4 *iface,
3287 UINT32 position, DWRITE_FONT_WEIGHT *weight, DWRITE_TEXT_RANGE *r)
3289 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3290 struct layout_range *range;
3292 TRACE("%p, %u, %p, %p.\n", iface, position, weight, r);
3294 if (position >= layout->len)
3295 return S_OK;
3297 range = get_layout_range_by_pos(layout, position);
3298 *weight = range->weight;
3300 return return_range(&range->h, r);
3303 static HRESULT WINAPI dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout4 *iface,
3304 UINT32 position, DWRITE_FONT_STYLE *style, DWRITE_TEXT_RANGE *r)
3306 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3307 struct layout_range *range;
3309 TRACE("%p, %u, %p, %p.\n", iface, position, style, r);
3311 range = get_layout_range_by_pos(layout, position);
3312 *style = range->style;
3313 return return_range(&range->h, r);
3316 static HRESULT WINAPI dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout4 *iface,
3317 UINT32 position, DWRITE_FONT_STRETCH *stretch, DWRITE_TEXT_RANGE *r)
3319 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3320 struct layout_range *range;
3322 TRACE("%p, %u, %p, %p.\n", iface, position, stretch, r);
3324 range = get_layout_range_by_pos(layout, position);
3325 *stretch = range->stretch;
3326 return return_range(&range->h, r);
3329 static HRESULT WINAPI dwritetextlayout_layout_GetFontSize(IDWriteTextLayout4 *iface,
3330 UINT32 position, FLOAT *size, DWRITE_TEXT_RANGE *r)
3332 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3333 struct layout_range *range;
3335 TRACE("%p, %u, %p, %p.\n", iface, position, size, r);
3337 range = get_layout_range_by_pos(layout, position);
3338 *size = range->fontsize;
3339 return return_range(&range->h, r);
3342 static HRESULT WINAPI dwritetextlayout_GetUnderline(IDWriteTextLayout4 *iface,
3343 UINT32 position, BOOL *underline, DWRITE_TEXT_RANGE *r)
3345 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3346 struct layout_range_bool *range;
3348 TRACE("%p, %u, %p, %p.\n", iface, position, underline, r);
3350 range = (struct layout_range_bool *)get_layout_range_header_by_pos(&layout->underline_ranges, position);
3351 *underline = range->value;
3353 return return_range(&range->h, r);
3356 static HRESULT WINAPI dwritetextlayout_GetStrikethrough(IDWriteTextLayout4 *iface,
3357 UINT32 position, BOOL *strikethrough, DWRITE_TEXT_RANGE *r)
3359 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3360 struct layout_range_bool *range;
3362 TRACE("%p, %u, %p, %p.\n", iface, position, strikethrough, r);
3364 range = (struct layout_range_bool *)get_layout_range_header_by_pos(&layout->strike_ranges, position);
3365 *strikethrough = range->value;
3367 return return_range(&range->h, r);
3370 static HRESULT WINAPI dwritetextlayout_GetDrawingEffect(IDWriteTextLayout4 *iface,
3371 UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r)
3373 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3374 struct layout_range_iface *range;
3376 TRACE("%p, %u, %p, %p.\n", iface, position, effect, r);
3378 range = (struct layout_range_iface *)get_layout_range_header_by_pos(&layout->effects, position);
3379 *effect = range->iface;
3380 if (*effect)
3381 IUnknown_AddRef(*effect);
3383 return return_range(&range->h, r);
3386 static HRESULT WINAPI dwritetextlayout_GetInlineObject(IDWriteTextLayout4 *iface,
3387 UINT32 position, IDWriteInlineObject **object, DWRITE_TEXT_RANGE *r)
3389 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3390 struct layout_range *range;
3392 TRACE("%p, %u, %p, %p.\n", iface, position, object, r);
3394 if (position >= layout->len)
3395 return S_OK;
3397 range = get_layout_range_by_pos(layout, position);
3398 *object = range->object;
3399 if (*object)
3400 IDWriteInlineObject_AddRef(*object);
3402 return return_range(&range->h, r);
3405 static HRESULT WINAPI dwritetextlayout_GetTypography(IDWriteTextLayout4 *iface,
3406 UINT32 position, IDWriteTypography** typography, DWRITE_TEXT_RANGE *r)
3408 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3409 struct layout_range_iface *range;
3411 TRACE("%p, %u, %p, %p.\n", iface, position, typography, r);
3413 range = (struct layout_range_iface *)get_layout_range_header_by_pos(&layout->typographies, position);
3414 *typography = (IDWriteTypography *)range->iface;
3415 if (*typography)
3416 IDWriteTypography_AddRef(*typography);
3418 return return_range(&range->h, r);
3421 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout4 *iface,
3422 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
3424 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3426 TRACE("%p, %u, %p, %p.\n", iface, position, length, r);
3428 return get_string_attribute_length(layout, LAYOUT_RANGE_ATTR_LOCALE, position, length, r);
3431 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout4 *iface,
3432 UINT32 position, WCHAR *locale, UINT32 length, DWRITE_TEXT_RANGE *r)
3434 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3436 TRACE("%p, %u, %p, %u, %p.\n", iface, position, locale, length, r);
3438 return get_string_attribute_value(layout, LAYOUT_RANGE_ATTR_LOCALE, position, locale, length, r);
3441 static inline FLOAT renderer_apply_snapping(FLOAT coord, BOOL skiptransform, FLOAT ppdip, FLOAT det,
3442 const DWRITE_MATRIX *m)
3444 D2D1_POINT_2F vec, vec2;
3446 if (!skiptransform) {
3447 /* apply transform */
3448 vec.x = 0.0f;
3449 vec.y = coord * ppdip;
3451 vec2.x = m->m11 * vec.x + m->m21 * vec.y + m->dx;
3452 vec2.y = m->m12 * vec.x + m->m22 * vec.y + m->dy;
3454 /* snap */
3455 vec2.x = floorf(vec2.x + 0.5f);
3456 vec2.y = floorf(vec2.y + 0.5f);
3458 /* apply inverted transform, we don't care about X component at this point */
3459 vec.y = (-m->m12 * vec2.x + m->m11 * vec2.y - (m->m11 * m->dy - m->m12 * m->dx)) / det;
3460 vec.y /= ppdip;
3462 else
3463 vec.y = floorf(coord * ppdip + 0.5f) / ppdip;
3465 return vec.y;
3468 static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout4 *iface,
3469 void *context, IDWriteTextRenderer* renderer, FLOAT origin_x, FLOAT origin_y)
3471 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3472 BOOL disabled = FALSE, skiptransform = FALSE;
3473 struct layout_effective_inline *inlineobject;
3474 struct layout_effective_run *run;
3475 struct layout_strikethrough *s;
3476 struct layout_underline *u;
3477 FLOAT det = 0.0f, ppdip = 0.0f;
3478 DWRITE_MATRIX m = { 0 };
3479 HRESULT hr;
3481 TRACE("%p, %p, %p, %.8e, %.8e.\n", iface, context, renderer, origin_x, origin_y);
3483 hr = layout_compute_effective_runs(layout);
3484 if (FAILED(hr))
3485 return hr;
3487 hr = IDWriteTextRenderer_IsPixelSnappingDisabled(renderer, context, &disabled);
3488 if (FAILED(hr))
3489 return hr;
3491 if (!disabled) {
3492 hr = IDWriteTextRenderer_GetPixelsPerDip(renderer, context, &ppdip);
3493 if (FAILED(hr))
3494 return hr;
3496 hr = IDWriteTextRenderer_GetCurrentTransform(renderer, context, &m);
3497 if (FAILED(hr))
3498 return hr;
3500 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
3501 if (ppdip <= 0.0f ||
3502 (m.m11 * m.m22 != 0.0f && (m.m12 != 0.0f || m.m21 != 0.0f)) ||
3503 (m.m12 * m.m21 != 0.0f && (m.m11 != 0.0f || m.m22 != 0.0f)))
3504 disabled = TRUE;
3505 else
3506 skiptransform = should_skip_transform(&m, &det);
3509 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
3510 /* 1. Regular runs */
3511 LIST_FOR_EACH_ENTRY(run, &layout->eruns, struct layout_effective_run, entry)
3513 const struct regular_layout_run *regular = &run->run->u.regular;
3514 UINT32 start_glyph = regular->clustermap[run->start];
3515 DWRITE_GLYPH_RUN_DESCRIPTION descr;
3516 DWRITE_GLYPH_RUN glyph_run;
3518 /* Everything but cluster map will be reused from nominal run, as we only need
3519 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
3520 it can't be reused because it has to start with 0 index for each reported run. */
3521 glyph_run = regular->run;
3522 glyph_run.glyphCount = run->glyphcount;
3524 /* fixup glyph data arrays */
3525 glyph_run.glyphIndices += start_glyph;
3526 glyph_run.glyphAdvances += start_glyph;
3527 glyph_run.glyphOffsets += start_glyph;
3529 /* description */
3530 descr = regular->descr;
3531 descr.stringLength = run->length;
3532 descr.string += run->start;
3533 descr.clusterMap = run->clustermap;
3534 descr.textPosition += run->start;
3536 /* return value is ignored */
3537 IDWriteTextRenderer_DrawGlyphRun(renderer,
3538 context,
3539 run->origin.x + run->align_dx + origin_x,
3540 SNAP_COORD(run->origin.y + origin_y),
3541 layout->measuringmode,
3542 &glyph_run,
3543 &descr,
3544 run->effect);
3547 /* 2. Inline objects */
3548 LIST_FOR_EACH_ENTRY(inlineobject, &layout->inlineobjects, struct layout_effective_inline, entry)
3550 IDWriteTextRenderer_DrawInlineObject(renderer,
3551 context,
3552 inlineobject->origin.x + inlineobject->align_dx + origin_x,
3553 SNAP_COORD(inlineobject->origin.y + origin_y),
3554 inlineobject->object,
3555 inlineobject->is_sideways,
3556 inlineobject->is_rtl,
3557 inlineobject->effect);
3560 /* 3. Underlines */
3561 LIST_FOR_EACH_ENTRY(u, &layout->underlines, struct layout_underline, entry)
3563 IDWriteTextRenderer_DrawUnderline(renderer,
3564 context,
3565 /* horizontal underline always grows from left to right, width is always added to origin regardless of run direction */
3566 (is_run_rtl(u->run) ? u->run->origin.x - u->run->width : u->run->origin.x) + u->run->align_dx + origin_x,
3567 SNAP_COORD(u->run->origin.y + origin_y),
3568 &u->u,
3569 u->run->effect);
3572 /* 4. Strikethrough */
3573 LIST_FOR_EACH_ENTRY(s, &layout->strikethrough, struct layout_strikethrough, entry)
3575 IDWriteTextRenderer_DrawStrikethrough(renderer,
3576 context,
3577 s->run->origin.x + s->run->align_dx + origin_x,
3578 SNAP_COORD(s->run->origin.y + origin_y),
3579 &s->s,
3580 s->run->effect);
3582 #undef SNAP_COORD
3584 return S_OK;
3587 static HRESULT WINAPI dwritetextlayout_GetLineMetrics(IDWriteTextLayout4 *iface,
3588 DWRITE_LINE_METRICS *metrics, UINT32 max_count, UINT32 *count)
3590 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3591 unsigned int line_count;
3592 HRESULT hr;
3593 size_t i;
3595 TRACE("%p, %p, %u, %p.\n", iface, metrics, max_count, count);
3597 if (FAILED(hr = layout_compute_effective_runs(layout)))
3598 return hr;
3600 if (metrics)
3602 line_count = min(max_count, layout->metrics.lineCount);
3603 for (i = 0; i < line_count; ++i)
3604 memcpy(&metrics[i], &layout->lines[i].metrics, sizeof(*metrics));
3607 *count = layout->metrics.lineCount;
3608 return max_count >= layout->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3611 static HRESULT layout_update_metrics(struct dwrite_textlayout *layout)
3613 return layout_compute_effective_runs(layout);
3616 static HRESULT WINAPI dwritetextlayout_GetMetrics(IDWriteTextLayout4 *iface, DWRITE_TEXT_METRICS *metrics)
3618 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3619 HRESULT hr;
3621 TRACE("%p, %p.\n", iface, metrics);
3623 hr = layout_update_metrics(layout);
3624 if (hr == S_OK)
3625 memcpy(metrics, &layout->metrics, sizeof(*metrics));
3627 return hr;
3630 static void d2d_rect_offset(D2D1_RECT_F *rect, FLOAT x, FLOAT y)
3632 rect->left += x;
3633 rect->right += x;
3634 rect->top += y;
3635 rect->bottom += y;
3638 static BOOL d2d_rect_is_empty(const D2D1_RECT_F *rect)
3640 return ((rect->left >= rect->right) || (rect->top >= rect->bottom));
3643 static void d2d_rect_union(D2D1_RECT_F *dst, const D2D1_RECT_F *src)
3645 if (d2d_rect_is_empty(dst)) {
3646 if (d2d_rect_is_empty(src)) {
3647 dst->left = dst->right = dst->top = dst->bottom = 0.0f;
3648 return;
3650 else
3651 *dst = *src;
3653 else {
3654 if (!d2d_rect_is_empty(src)) {
3655 dst->left = min(dst->left, src->left);
3656 dst->right = max(dst->right, src->right);
3657 dst->top = min(dst->top, src->top);
3658 dst->bottom = max(dst->bottom, src->bottom);
3663 static void layout_get_erun_bbox(struct dwrite_textlayout *layout, struct layout_effective_run *run, D2D1_RECT_F *bbox)
3665 const struct regular_layout_run *regular = &run->run->u.regular;
3666 UINT32 start_glyph = regular->clustermap[run->start];
3667 const DWRITE_GLYPH_RUN *glyph_run = &regular->run;
3668 D2D1_POINT_2F origin = { 0 };
3669 float rtl_factor;
3670 UINT32 i;
3672 if (run->bbox.top == run->bbox.bottom)
3674 struct dwrite_glyphbitmap glyph_bitmap;
3675 RECT *bbox;
3677 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
3678 glyph_bitmap.fontface = (IDWriteFontFace4 *)glyph_run->fontFace;
3679 glyph_bitmap.simulations = IDWriteFontFace_GetSimulations(glyph_run->fontFace);
3680 glyph_bitmap.emsize = glyph_run->fontEmSize;
3681 glyph_bitmap.nohint = layout->measuringmode == DWRITE_MEASURING_MODE_NATURAL;
3683 bbox = &glyph_bitmap.bbox;
3685 rtl_factor = glyph_run->bidiLevel & 1 ? -1.0f : 1.0f;
3686 for (i = 0; i < run->glyphcount; i++) {
3687 D2D1_RECT_F glyph_bbox;
3689 /* FIXME: take care of vertical/rtl */
3690 if (glyph_run->bidiLevel & 1)
3691 origin.x -= glyph_run->glyphAdvances[i + start_glyph];
3693 glyph_bitmap.glyph = glyph_run->glyphIndices[i + start_glyph];
3694 freetype_get_glyph_bbox(&glyph_bitmap);
3696 glyph_bbox.left = bbox->left;
3697 glyph_bbox.top = bbox->top;
3698 glyph_bbox.right = bbox->right;
3699 glyph_bbox.bottom = bbox->bottom;
3701 d2d_rect_offset(&glyph_bbox, origin.x + rtl_factor * glyph_run->glyphOffsets[i + start_glyph].advanceOffset,
3702 origin.y - glyph_run->glyphOffsets[i + start_glyph].ascenderOffset);
3704 d2d_rect_union(&run->bbox, &glyph_bbox);
3706 if (!(glyph_run->bidiLevel & 1))
3707 origin.x += glyph_run->glyphAdvances[i + start_glyph];
3711 *bbox = run->bbox;
3712 d2d_rect_offset(bbox, run->origin.x + run->align_dx, run->origin.y);
3715 static void layout_get_inlineobj_bbox(struct dwrite_textlayout *layout, struct layout_effective_inline *run,
3716 D2D1_RECT_F *bbox)
3718 DWRITE_OVERHANG_METRICS overhang_metrics = { 0 };
3719 DWRITE_INLINE_OBJECT_METRICS metrics = { 0 };
3720 HRESULT hr;
3722 if (FAILED(hr = IDWriteInlineObject_GetMetrics(run->object, &metrics))) {
3723 WARN("Failed to get inline object metrics, hr %#x.\n", hr);
3724 memset(bbox, 0, sizeof(*bbox));
3725 return;
3728 bbox->left = run->origin.x + run->align_dx;
3729 bbox->right = bbox->left + metrics.width;
3730 bbox->top = run->origin.y;
3731 bbox->bottom = bbox->top + metrics.height;
3733 IDWriteInlineObject_GetOverhangMetrics(run->object, &overhang_metrics);
3735 bbox->left -= overhang_metrics.left;
3736 bbox->right += overhang_metrics.right;
3737 bbox->top -= overhang_metrics.top;
3738 bbox->bottom += overhang_metrics.bottom;
3741 static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout4 *iface,
3742 DWRITE_OVERHANG_METRICS *overhangs)
3744 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3745 struct layout_effective_inline *inline_run;
3746 struct layout_effective_run *run;
3747 D2D1_RECT_F bbox = { 0 };
3748 HRESULT hr;
3750 TRACE("%p, %p.\n", iface, overhangs);
3752 memset(overhangs, 0, sizeof(*overhangs));
3754 if (!(layout->recompute & RECOMPUTE_OVERHANGS))
3756 *overhangs = layout->overhangs;
3757 return S_OK;
3760 hr = layout_compute_effective_runs(layout);
3761 if (FAILED(hr))
3762 return hr;
3764 LIST_FOR_EACH_ENTRY(run, &layout->eruns, struct layout_effective_run, entry)
3766 D2D1_RECT_F run_bbox;
3768 layout_get_erun_bbox(layout, run, &run_bbox);
3769 d2d_rect_union(&bbox, &run_bbox);
3772 LIST_FOR_EACH_ENTRY(inline_run, &layout->inlineobjects, struct layout_effective_inline, entry)
3774 D2D1_RECT_F object_bbox;
3776 layout_get_inlineobj_bbox(layout, inline_run, &object_bbox);
3777 d2d_rect_union(&bbox, &object_bbox);
3780 /* Deltas from layout box. */
3781 layout->overhangs.left = -bbox.left;
3782 layout->overhangs.top = -bbox.top;
3783 layout->overhangs.right = bbox.right - layout->metrics.layoutWidth;
3784 layout->overhangs.bottom = bbox.bottom - layout->metrics.layoutHeight;
3785 layout->recompute &= ~RECOMPUTE_OVERHANGS;
3787 *overhangs = layout->overhangs;
3789 return S_OK;
3792 static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout4 *iface,
3793 DWRITE_CLUSTER_METRICS *metrics, UINT32 max_count, UINT32 *count)
3795 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3796 HRESULT hr;
3798 TRACE("%p, %p, %u, %p.\n", iface, metrics, max_count, count);
3800 hr = layout_compute(layout);
3801 if (FAILED(hr))
3802 return hr;
3804 if (metrics)
3805 memcpy(metrics, layout->clustermetrics, sizeof(DWRITE_CLUSTER_METRICS) * min(max_count, layout->cluster_count));
3807 *count = layout->cluster_count;
3808 return max_count >= layout->cluster_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3811 static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout4 *iface, FLOAT* min_width)
3813 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3814 UINT32 start;
3815 FLOAT width;
3816 HRESULT hr;
3818 TRACE("%p, %p.\n", iface, min_width);
3820 if (!min_width)
3821 return E_INVALIDARG;
3823 if (!(layout->recompute & RECOMPUTE_MINIMAL_WIDTH))
3824 goto width_done;
3826 *min_width = 0.0f;
3827 hr = layout_compute(layout);
3828 if (FAILED(hr))
3829 return hr;
3831 /* Find widest word without emergency breaking between clusters, trailing whitespaces
3832 preceding breaking point do not contribute to word width. */
3833 for (start = 0; start < layout->cluster_count;)
3835 UINT32 end = start, j, next;
3837 /* Last cluster always could be wrapped after. */
3838 while (!layout->clustermetrics[end].canWrapLineAfter)
3839 end++;
3840 /* make is so current cluster range that we can wrap after is [start,end) */
3841 end++;
3843 next = end;
3845 /* Ignore trailing whitespace clusters, in case of single space range will
3846 be reduced to empty range, or [start,start+1). */
3847 while (end > start && layout->clustermetrics[end-1].isWhitespace)
3848 end--;
3850 /* check if cluster range exceeds last minimal width */
3851 width = 0.0f;
3852 for (j = start; j < end; j++)
3853 width += layout->clustermetrics[j].width;
3855 start = next;
3857 if (width > layout->minwidth)
3858 layout->minwidth = width;
3860 layout->recompute &= ~RECOMPUTE_MINIMAL_WIDTH;
3862 width_done:
3863 *min_width = layout->minwidth;
3864 return S_OK;
3867 static HRESULT WINAPI dwritetextlayout_HitTestPoint(IDWriteTextLayout4 *iface,
3868 FLOAT pointX, FLOAT pointY, BOOL* is_trailinghit, BOOL* is_inside, DWRITE_HIT_TEST_METRICS *metrics)
3870 FIXME("%p, %.8e, %.8e, %p, %p, %p): stub\n", iface, pointX, pointY, is_trailinghit, is_inside, metrics);
3872 return E_NOTIMPL;
3875 static HRESULT WINAPI dwritetextlayout_HitTestTextPosition(IDWriteTextLayout4 *iface,
3876 UINT32 textPosition, BOOL is_trailinghit, FLOAT *pointX, FLOAT *pointY, DWRITE_HIT_TEST_METRICS *metrics)
3878 FIXME("%p, %u, %d, %p, %p, %p): stub\n", iface, textPosition, is_trailinghit, pointX, pointY, metrics);
3880 return E_NOTIMPL;
3883 static HRESULT WINAPI dwritetextlayout_HitTestTextRange(IDWriteTextLayout4 *iface,
3884 UINT32 textPosition, UINT32 textLength, FLOAT originX, FLOAT originY,
3885 DWRITE_HIT_TEST_METRICS *metrics, UINT32 max_metricscount, UINT32* actual_metricscount)
3887 FIXME("%p, %u, %u, %f, %f, %p, %u, %p): stub\n", iface, textPosition, textLength, originX, originY, metrics,
3888 max_metricscount, actual_metricscount);
3890 return E_NOTIMPL;
3893 static HRESULT WINAPI dwritetextlayout1_SetPairKerning(IDWriteTextLayout4 *iface, BOOL is_pairkerning_enabled,
3894 DWRITE_TEXT_RANGE range)
3896 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3897 struct layout_range_attr_value value;
3899 TRACE("%p, %d, %s.\n", iface, is_pairkerning_enabled, debugstr_range(&range));
3901 value.range = range;
3902 value.u.pair_kerning = !!is_pairkerning_enabled;
3903 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_PAIR_KERNING, &value);
3906 static HRESULT WINAPI dwritetextlayout1_GetPairKerning(IDWriteTextLayout4 *iface, UINT32 position,
3907 BOOL *is_pairkerning_enabled, DWRITE_TEXT_RANGE *r)
3909 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3910 struct layout_range *range;
3912 TRACE("%p, %u, %p, %p.\n", iface, position, is_pairkerning_enabled, r);
3914 if (position >= layout->len)
3915 return S_OK;
3917 range = get_layout_range_by_pos(layout, position);
3918 *is_pairkerning_enabled = range->pair_kerning;
3920 return return_range(&range->h, r);
3923 static HRESULT WINAPI dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout4 *iface, FLOAT leading, FLOAT trailing,
3924 FLOAT min_advance, DWRITE_TEXT_RANGE range)
3926 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3927 struct layout_range_attr_value value;
3929 TRACE("%p, %.8e, %.8e, %.8e, %s.\n", iface, leading, trailing, min_advance, debugstr_range(&range));
3931 if (min_advance < 0.0f)
3932 return E_INVALIDARG;
3934 value.range = range;
3935 value.u.spacing.leading = leading;
3936 value.u.spacing.trailing = trailing;
3937 value.u.spacing.min_advance = min_advance;
3938 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_SPACING, &value);
3941 static HRESULT WINAPI dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout4 *iface, UINT32 position, FLOAT *leading,
3942 FLOAT *trailing, FLOAT *min_advance, DWRITE_TEXT_RANGE *r)
3944 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3945 struct layout_range_spacing *range;
3947 TRACE("%p, %u, %p, %p, %p, %p.\n", iface, position, leading, trailing, min_advance, r);
3949 range = (struct layout_range_spacing *)get_layout_range_header_by_pos(&layout->spacing, position);
3950 *leading = range->leading;
3951 *trailing = range->trailing;
3952 *min_advance = range->min_advance;
3954 return return_range(&range->h, r);
3957 static HRESULT WINAPI dwritetextlayout2_GetMetrics(IDWriteTextLayout4 *iface, DWRITE_TEXT_METRICS1 *metrics)
3959 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3960 HRESULT hr;
3962 TRACE("%p, %p.\n", iface, metrics);
3964 if (SUCCEEDED(hr = layout_update_metrics(layout)))
3965 *metrics = layout->metrics;
3967 return hr;
3970 static HRESULT WINAPI dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout4 *iface,
3971 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
3973 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3975 TRACE("%p, %d.\n", iface, orientation);
3977 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
3978 return E_INVALIDARG;
3980 layout->format.vertical_orientation = orientation;
3981 return S_OK;
3984 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout4 *iface)
3986 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3988 TRACE("%p.\n", iface);
3990 return layout->format.vertical_orientation;
3993 static HRESULT WINAPI dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout4 *iface, BOOL lastline_wrapping_enabled)
3995 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3997 TRACE("%p, %d.\n", iface, lastline_wrapping_enabled);
3999 return IDWriteTextFormat3_SetLastLineWrapping(&layout->IDWriteTextFormat3_iface, lastline_wrapping_enabled);
4002 static BOOL WINAPI dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout4 *iface)
4004 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4006 TRACE("%p.\n", iface);
4008 return IDWriteTextFormat3_GetLastLineWrapping(&layout->IDWriteTextFormat3_iface);
4011 static HRESULT WINAPI dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout4 *iface,
4012 DWRITE_OPTICAL_ALIGNMENT alignment)
4014 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4016 TRACE("%p, %d.\n", iface, alignment);
4018 return IDWriteTextFormat3_SetOpticalAlignment(&layout->IDWriteTextFormat3_iface, alignment);
4021 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout4 *iface)
4023 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4025 TRACE("%p.\n", iface);
4027 return IDWriteTextFormat3_GetOpticalAlignment(&layout->IDWriteTextFormat3_iface);
4030 static HRESULT WINAPI dwritetextlayout2_SetFontFallback(IDWriteTextLayout4 *iface, IDWriteFontFallback *fallback)
4032 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4034 TRACE("%p, %p.\n", iface, fallback);
4036 return set_fontfallback_for_format(&layout->format, fallback);
4039 static HRESULT WINAPI dwritetextlayout2_GetFontFallback(IDWriteTextLayout4 *iface, IDWriteFontFallback **fallback)
4041 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4043 TRACE("%p, %p.\n", iface, fallback);
4045 return get_fontfallback_from_format(&layout->format, fallback);
4048 static HRESULT WINAPI dwritetextlayout3_InvalidateLayout(IDWriteTextLayout4 *iface)
4050 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4052 TRACE("%p.\n", iface);
4054 layout->recompute = RECOMPUTE_EVERYTHING;
4055 return S_OK;
4058 static HRESULT WINAPI dwritetextlayout3_SetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING const *spacing)
4060 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4061 BOOL changed;
4062 HRESULT hr;
4064 TRACE("%p, %p.\n", iface, spacing);
4066 hr = format_set_linespacing(&layout->format, spacing, &changed);
4067 if (FAILED(hr))
4068 return hr;
4070 if (changed)
4072 if (!(layout->recompute & RECOMPUTE_LINES))
4074 UINT32 line;
4076 for (line = 0; line < layout->metrics.lineCount; line++)
4077 layout_apply_line_spacing(layout, line);
4079 layout_set_line_positions(layout);
4082 layout->recompute |= RECOMPUTE_OVERHANGS;
4085 return S_OK;
4088 static HRESULT WINAPI dwritetextlayout3_GetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING *spacing)
4090 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4092 TRACE("%p, %p.\n", iface, spacing);
4094 *spacing = layout->format.spacing;
4095 return S_OK;
4098 static HRESULT WINAPI dwritetextlayout3_GetLineMetrics(IDWriteTextLayout4 *iface, DWRITE_LINE_METRICS1 *metrics,
4099 UINT32 max_count, UINT32 *count)
4101 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4102 unsigned int line_count;
4103 HRESULT hr;
4104 size_t i;
4106 TRACE("%p, %p, %u, %p.\n", iface, metrics, max_count, count);
4108 if (FAILED(hr = layout_compute_effective_runs(layout)))
4109 return hr;
4111 if (metrics)
4113 line_count = min(max_count, layout->metrics.lineCount);
4114 for (i = 0; i < line_count; ++i)
4115 metrics[i] = layout->lines[i].metrics;
4118 *count = layout->metrics.lineCount;
4119 return max_count >= layout->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
4122 static HRESULT WINAPI dwritetextlayout4_SetFontAxisValues(IDWriteTextLayout4 *iface,
4123 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, DWRITE_TEXT_RANGE range)
4125 FIXME("%p, %p, %u, %s.\n", iface, axis_values, num_values, debugstr_range(&range));
4127 return E_NOTIMPL;
4130 static UINT32 WINAPI dwritetextlayout4_GetFontAxisValueCount(IDWriteTextLayout4 *iface, UINT32 pos)
4132 FIXME("%p, %u.\n", iface, pos);
4134 return 0;
4137 static HRESULT WINAPI dwritetextlayout4_GetFontAxisValues(IDWriteTextLayout4 *iface, UINT32 pos,
4138 DWRITE_FONT_AXIS_VALUE *values, UINT32 num_values, DWRITE_TEXT_RANGE *range)
4140 FIXME("%p, %u, %p, %u, %p.\n", iface, pos, values, num_values, range);
4142 return E_NOTIMPL;
4145 static DWRITE_AUTOMATIC_FONT_AXES WINAPI dwritetextlayout4_GetAutomaticFontAxes(IDWriteTextLayout4 *iface)
4147 FIXME("%p.\n", iface);
4149 return DWRITE_AUTOMATIC_FONT_AXES_NONE;
4152 static HRESULT WINAPI dwritetextlayout4_SetAutomaticFontAxes(IDWriteTextLayout4 *iface,
4153 DWRITE_AUTOMATIC_FONT_AXES axes)
4155 FIXME("%p, %d.\n", iface, axes);
4157 return E_NOTIMPL;
4160 static const IDWriteTextLayout4Vtbl dwritetextlayoutvtbl =
4162 dwritetextlayout_QueryInterface,
4163 dwritetextlayout_AddRef,
4164 dwritetextlayout_Release,
4165 dwritetextlayout_SetTextAlignment,
4166 dwritetextlayout_SetParagraphAlignment,
4167 dwritetextlayout_SetWordWrapping,
4168 dwritetextlayout_SetReadingDirection,
4169 dwritetextlayout_SetFlowDirection,
4170 dwritetextlayout_SetIncrementalTabStop,
4171 dwritetextlayout_SetTrimming,
4172 dwritetextlayout_SetLineSpacing,
4173 dwritetextlayout_GetTextAlignment,
4174 dwritetextlayout_GetParagraphAlignment,
4175 dwritetextlayout_GetWordWrapping,
4176 dwritetextlayout_GetReadingDirection,
4177 dwritetextlayout_GetFlowDirection,
4178 dwritetextlayout_GetIncrementalTabStop,
4179 dwritetextlayout_GetTrimming,
4180 dwritetextlayout_GetLineSpacing,
4181 dwritetextlayout_GetFontCollection,
4182 dwritetextlayout_GetFontFamilyNameLength,
4183 dwritetextlayout_GetFontFamilyName,
4184 dwritetextlayout_GetFontWeight,
4185 dwritetextlayout_GetFontStyle,
4186 dwritetextlayout_GetFontStretch,
4187 dwritetextlayout_GetFontSize,
4188 dwritetextlayout_GetLocaleNameLength,
4189 dwritetextlayout_GetLocaleName,
4190 dwritetextlayout_SetMaxWidth,
4191 dwritetextlayout_SetMaxHeight,
4192 dwritetextlayout_SetFontCollection,
4193 dwritetextlayout_SetFontFamilyName,
4194 dwritetextlayout_SetFontWeight,
4195 dwritetextlayout_SetFontStyle,
4196 dwritetextlayout_SetFontStretch,
4197 dwritetextlayout_SetFontSize,
4198 dwritetextlayout_SetUnderline,
4199 dwritetextlayout_SetStrikethrough,
4200 dwritetextlayout_SetDrawingEffect,
4201 dwritetextlayout_SetInlineObject,
4202 dwritetextlayout_SetTypography,
4203 dwritetextlayout_SetLocaleName,
4204 dwritetextlayout_GetMaxWidth,
4205 dwritetextlayout_GetMaxHeight,
4206 dwritetextlayout_layout_GetFontCollection,
4207 dwritetextlayout_layout_GetFontFamilyNameLength,
4208 dwritetextlayout_layout_GetFontFamilyName,
4209 dwritetextlayout_layout_GetFontWeight,
4210 dwritetextlayout_layout_GetFontStyle,
4211 dwritetextlayout_layout_GetFontStretch,
4212 dwritetextlayout_layout_GetFontSize,
4213 dwritetextlayout_GetUnderline,
4214 dwritetextlayout_GetStrikethrough,
4215 dwritetextlayout_GetDrawingEffect,
4216 dwritetextlayout_GetInlineObject,
4217 dwritetextlayout_GetTypography,
4218 dwritetextlayout_layout_GetLocaleNameLength,
4219 dwritetextlayout_layout_GetLocaleName,
4220 dwritetextlayout_Draw,
4221 dwritetextlayout_GetLineMetrics,
4222 dwritetextlayout_GetMetrics,
4223 dwritetextlayout_GetOverhangMetrics,
4224 dwritetextlayout_GetClusterMetrics,
4225 dwritetextlayout_DetermineMinWidth,
4226 dwritetextlayout_HitTestPoint,
4227 dwritetextlayout_HitTestTextPosition,
4228 dwritetextlayout_HitTestTextRange,
4229 dwritetextlayout1_SetPairKerning,
4230 dwritetextlayout1_GetPairKerning,
4231 dwritetextlayout1_SetCharacterSpacing,
4232 dwritetextlayout1_GetCharacterSpacing,
4233 dwritetextlayout2_GetMetrics,
4234 dwritetextlayout2_SetVerticalGlyphOrientation,
4235 dwritetextlayout2_GetVerticalGlyphOrientation,
4236 dwritetextlayout2_SetLastLineWrapping,
4237 dwritetextlayout2_GetLastLineWrapping,
4238 dwritetextlayout2_SetOpticalAlignment,
4239 dwritetextlayout2_GetOpticalAlignment,
4240 dwritetextlayout2_SetFontFallback,
4241 dwritetextlayout2_GetFontFallback,
4242 dwritetextlayout3_InvalidateLayout,
4243 dwritetextlayout3_SetLineSpacing,
4244 dwritetextlayout3_GetLineSpacing,
4245 dwritetextlayout3_GetLineMetrics,
4246 dwritetextlayout4_SetFontAxisValues,
4247 dwritetextlayout4_GetFontAxisValueCount,
4248 dwritetextlayout4_GetFontAxisValues,
4249 dwritetextlayout4_GetAutomaticFontAxes,
4250 dwritetextlayout4_SetAutomaticFontAxes,
4253 static HRESULT WINAPI dwritetextformat_layout_QueryInterface(IDWriteTextFormat3 *iface, REFIID riid, void **obj)
4255 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4257 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
4259 return IDWriteTextLayout4_QueryInterface(&layout->IDWriteTextLayout4_iface, riid, obj);
4262 static ULONG WINAPI dwritetextformat_layout_AddRef(IDWriteTextFormat3 *iface)
4264 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4265 return IDWriteTextLayout4_AddRef(&layout->IDWriteTextLayout4_iface);
4268 static ULONG WINAPI dwritetextformat_layout_Release(IDWriteTextFormat3 *iface)
4270 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4271 return IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
4274 static HRESULT WINAPI dwritetextformat_layout_SetTextAlignment(IDWriteTextFormat3 *iface,
4275 DWRITE_TEXT_ALIGNMENT alignment)
4277 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4278 BOOL changed;
4279 HRESULT hr;
4281 TRACE("%p, %d.\n", iface, alignment);
4283 hr = format_set_textalignment(&layout->format, alignment, &changed);
4284 if (FAILED(hr))
4285 return hr;
4287 if (changed)
4289 /* if layout is not ready there's nothing to align */
4290 if (!(layout->recompute & RECOMPUTE_LINES))
4291 layout_apply_text_alignment(layout);
4292 layout->recompute |= RECOMPUTE_OVERHANGS;
4295 return S_OK;
4298 static HRESULT WINAPI dwritetextformat_layout_SetParagraphAlignment(IDWriteTextFormat3 *iface,
4299 DWRITE_PARAGRAPH_ALIGNMENT alignment)
4301 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4302 BOOL changed;
4303 HRESULT hr;
4305 TRACE("%p, %d.\n", iface, alignment);
4307 hr = format_set_paralignment(&layout->format, alignment, &changed);
4308 if (FAILED(hr))
4309 return hr;
4311 if (changed)
4313 /* if layout is not ready there's nothing to align */
4314 if (!(layout->recompute & RECOMPUTE_LINES))
4315 layout_apply_par_alignment(layout);
4316 layout->recompute |= RECOMPUTE_OVERHANGS;
4319 return S_OK;
4322 static HRESULT WINAPI dwritetextformat_layout_SetWordWrapping(IDWriteTextFormat3 *iface, DWRITE_WORD_WRAPPING wrapping)
4324 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4325 BOOL changed;
4326 HRESULT hr;
4328 TRACE("%p, %d.\n", iface, wrapping);
4330 hr = format_set_wordwrapping(&layout->format, wrapping, &changed);
4331 if (FAILED(hr))
4332 return hr;
4334 if (changed)
4335 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
4337 return S_OK;
4340 static HRESULT WINAPI dwritetextformat_layout_SetReadingDirection(IDWriteTextFormat3 *iface,
4341 DWRITE_READING_DIRECTION direction)
4343 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4344 BOOL changed;
4345 HRESULT hr;
4347 TRACE("%p, %d.\n", iface, direction);
4349 hr = format_set_readingdirection(&layout->format, direction, &changed);
4350 if (FAILED(hr))
4351 return hr;
4353 if (changed)
4354 layout->recompute = RECOMPUTE_EVERYTHING;
4356 return S_OK;
4359 static HRESULT WINAPI dwritetextformat_layout_SetFlowDirection(IDWriteTextFormat3 *iface,
4360 DWRITE_FLOW_DIRECTION direction)
4362 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4363 BOOL changed;
4364 HRESULT hr;
4366 TRACE("%p, %d.\n", iface, direction);
4368 hr = format_set_flowdirection(&layout->format, direction, &changed);
4369 if (FAILED(hr))
4370 return hr;
4372 if (changed)
4373 layout->recompute = RECOMPUTE_EVERYTHING;
4375 return S_OK;
4378 static HRESULT WINAPI dwritetextformat_layout_SetIncrementalTabStop(IDWriteTextFormat3 *iface, FLOAT tabstop)
4380 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4382 TRACE("%p, %.8e.\n", iface, tabstop);
4384 if (tabstop <= 0.0f)
4385 return E_INVALIDARG;
4387 layout->format.tabstop = tabstop;
4388 return S_OK;
4391 static HRESULT WINAPI dwritetextformat_layout_SetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING const *trimming,
4392 IDWriteInlineObject *trimming_sign)
4394 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4395 BOOL changed;
4396 HRESULT hr;
4398 TRACE("%p, %p, %p.\n", iface, trimming, trimming_sign);
4400 hr = format_set_trimming(&layout->format, trimming, trimming_sign, &changed);
4402 if (changed)
4403 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
4405 return hr;
4408 static HRESULT WINAPI dwritetextformat_layout_SetLineSpacing(IDWriteTextFormat3 *iface,
4409 DWRITE_LINE_SPACING_METHOD method, FLOAT height, FLOAT baseline)
4411 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4412 DWRITE_LINE_SPACING spacing;
4414 TRACE("%p, %d, %.8e, %.8e.\n", iface, method, height, baseline);
4416 spacing = layout->format.spacing;
4417 spacing.method = method;
4418 spacing.height = height;
4419 spacing.baseline = baseline;
4420 return IDWriteTextLayout4_SetLineSpacing(&layout->IDWriteTextLayout4_iface, &spacing);
4423 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_layout_GetTextAlignment(IDWriteTextFormat3 *iface)
4425 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4427 TRACE("%p.\n", iface);
4429 return layout->format.textalignment;
4432 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_layout_GetParagraphAlignment(IDWriteTextFormat3 *iface)
4434 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4436 TRACE("%p.\n", iface);
4438 return layout->format.paralign;
4441 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_layout_GetWordWrapping(IDWriteTextFormat3 *iface)
4443 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4445 TRACE("%p.\n", iface);
4447 return layout->format.wrapping;
4450 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_layout_GetReadingDirection(IDWriteTextFormat3 *iface)
4452 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4454 TRACE("%p.\n", iface);
4456 return layout->format.readingdir;
4459 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_layout_GetFlowDirection(IDWriteTextFormat3 *iface)
4461 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4463 TRACE("%p.\n", iface);
4465 return layout->format.flow;
4468 static FLOAT WINAPI dwritetextformat_layout_GetIncrementalTabStop(IDWriteTextFormat3 *iface)
4470 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4472 TRACE("%p.\n", iface);
4474 return layout->format.tabstop;
4477 static HRESULT WINAPI dwritetextformat_layout_GetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING *options,
4478 IDWriteInlineObject **trimming_sign)
4480 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4482 TRACE("%p, %p, %p.\n", iface, options, trimming_sign);
4484 *options = layout->format.trimming;
4485 *trimming_sign = layout->format.trimmingsign;
4486 if (*trimming_sign)
4487 IDWriteInlineObject_AddRef(*trimming_sign);
4488 return S_OK;
4491 static HRESULT WINAPI dwritetextformat_layout_GetLineSpacing(IDWriteTextFormat3 *iface,
4492 DWRITE_LINE_SPACING_METHOD *method, FLOAT *spacing, FLOAT *baseline)
4494 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4496 TRACE("%p, %p, %p, %p.\n", iface, method, spacing, baseline);
4498 *method = layout->format.spacing.method;
4499 *spacing = layout->format.spacing.height;
4500 *baseline = layout->format.spacing.baseline;
4501 return S_OK;
4504 static HRESULT WINAPI dwritetextformat_layout_GetFontCollection(IDWriteTextFormat3 *iface,
4505 IDWriteFontCollection **collection)
4507 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4509 TRACE("%p, %p.\n", iface, collection);
4511 *collection = layout->format.collection;
4512 if (*collection)
4513 IDWriteFontCollection_AddRef(*collection);
4514 return S_OK;
4517 static UINT32 WINAPI dwritetextformat_layout_GetFontFamilyNameLength(IDWriteTextFormat3 *iface)
4519 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4521 TRACE("%p.\n", iface);
4523 return layout->format.family_len;
4526 static HRESULT WINAPI dwritetextformat_layout_GetFontFamilyName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
4528 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4530 TRACE("%p, %p, %u.\n", iface, name, size);
4532 if (size <= layout->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
4533 strcpyW(name, layout->format.family_name);
4534 return S_OK;
4537 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_layout_GetFontWeight(IDWriteTextFormat3 *iface)
4539 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4541 TRACE("%p.\n", iface);
4543 return layout->format.weight;
4546 static DWRITE_FONT_STYLE WINAPI dwritetextformat_layout_GetFontStyle(IDWriteTextFormat3 *iface)
4548 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4550 TRACE("%p.\n", iface);
4552 return layout->format.style;
4555 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_layout_GetFontStretch(IDWriteTextFormat3 *iface)
4557 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4559 TRACE("%p.\n", iface);
4561 return layout->format.stretch;
4564 static FLOAT WINAPI dwritetextformat_layout_GetFontSize(IDWriteTextFormat3 *iface)
4566 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4568 TRACE("%p.\n", iface);
4570 return layout->format.fontsize;
4573 static UINT32 WINAPI dwritetextformat_layout_GetLocaleNameLength(IDWriteTextFormat3 *iface)
4575 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4577 TRACE("%p.\n", iface);
4579 return layout->format.locale_len;
4582 static HRESULT WINAPI dwritetextformat_layout_GetLocaleName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
4584 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4586 TRACE("%p, %p, %u.\n", iface, name, size);
4588 if (size <= layout->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
4589 strcpyW(name, layout->format.locale);
4590 return S_OK;
4593 static HRESULT WINAPI dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat3 *iface,
4594 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4596 FIXME("%p, %d: stub\n", iface, orientation);
4598 return E_NOTIMPL;
4601 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat3 *iface)
4603 FIXME("%p: stub\n", iface);
4605 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
4608 static HRESULT WINAPI dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat3 *iface,
4609 BOOL lastline_wrapping_enabled)
4611 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4613 TRACE("%p, %d.\n", iface, lastline_wrapping_enabled);
4615 layout->format.last_line_wrapping = !!lastline_wrapping_enabled;
4616 return S_OK;
4619 static BOOL WINAPI dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat3 *iface)
4621 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4623 TRACE("%p.\n", iface);
4625 return layout->format.last_line_wrapping;
4628 static HRESULT WINAPI dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat3 *iface,
4629 DWRITE_OPTICAL_ALIGNMENT alignment)
4631 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4633 TRACE("%p, %d.\n", iface, alignment);
4635 return format_set_optical_alignment(&layout->format, alignment);
4638 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat3 *iface)
4640 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4642 TRACE("%p.\n", iface);
4644 return layout->format.optical_alignment;
4647 static HRESULT WINAPI dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat3 *iface,
4648 IDWriteFontFallback *fallback)
4650 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4652 TRACE("%p, %p.\n", iface, fallback);
4654 return IDWriteTextLayout4_SetFontFallback(&layout->IDWriteTextLayout4_iface, fallback);
4657 static HRESULT WINAPI dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat3 *iface,
4658 IDWriteFontFallback **fallback)
4660 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4662 TRACE("%p, %p.\n", iface, fallback);
4664 return IDWriteTextLayout4_GetFontFallback(&layout->IDWriteTextLayout4_iface, fallback);
4667 static HRESULT WINAPI dwritetextformat2_layout_SetLineSpacing(IDWriteTextFormat3 *iface,
4668 DWRITE_LINE_SPACING const *spacing)
4670 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4671 return IDWriteTextLayout4_SetLineSpacing(&layout->IDWriteTextLayout4_iface, spacing);
4674 static HRESULT WINAPI dwritetextformat2_layout_GetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING *spacing)
4676 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4677 return IDWriteTextLayout4_GetLineSpacing(&layout->IDWriteTextLayout4_iface, spacing);
4680 static HRESULT WINAPI dwritetextformat3_layout_SetFontAxisValues(IDWriteTextFormat3 *iface,
4681 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values)
4683 FIXME("%p, %p, %u.\n", iface, axis_values, num_values);
4685 return E_NOTIMPL;
4688 static UINT32 WINAPI dwritetextformat3_layout_GetFontAxisValueCount(IDWriteTextFormat3 *iface)
4690 FIXME("%p.\n", iface);
4692 return 0;
4695 static HRESULT WINAPI dwritetextformat3_layout_GetFontAxisValues(IDWriteTextFormat3 *iface,
4696 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values)
4698 FIXME("%p, %p, %u.\n", iface, axis_values, num_values);
4700 return E_NOTIMPL;
4703 static DWRITE_AUTOMATIC_FONT_AXES WINAPI dwritetextformat3_layout_GetAutomaticFontAxes(IDWriteTextFormat3 *iface)
4705 FIXME("%p.\n", iface);
4707 return DWRITE_AUTOMATIC_FONT_AXES_NONE;
4710 static HRESULT WINAPI dwritetextformat3_layout_SetAutomaticFontAxes(IDWriteTextFormat3 *iface,
4711 DWRITE_AUTOMATIC_FONT_AXES axes)
4713 FIXME("%p, %d.\n", iface, axes);
4715 return E_NOTIMPL;
4718 static const IDWriteTextFormat3Vtbl dwritetextformat3_layout_vtbl =
4720 dwritetextformat_layout_QueryInterface,
4721 dwritetextformat_layout_AddRef,
4722 dwritetextformat_layout_Release,
4723 dwritetextformat_layout_SetTextAlignment,
4724 dwritetextformat_layout_SetParagraphAlignment,
4725 dwritetextformat_layout_SetWordWrapping,
4726 dwritetextformat_layout_SetReadingDirection,
4727 dwritetextformat_layout_SetFlowDirection,
4728 dwritetextformat_layout_SetIncrementalTabStop,
4729 dwritetextformat_layout_SetTrimming,
4730 dwritetextformat_layout_SetLineSpacing,
4731 dwritetextformat_layout_GetTextAlignment,
4732 dwritetextformat_layout_GetParagraphAlignment,
4733 dwritetextformat_layout_GetWordWrapping,
4734 dwritetextformat_layout_GetReadingDirection,
4735 dwritetextformat_layout_GetFlowDirection,
4736 dwritetextformat_layout_GetIncrementalTabStop,
4737 dwritetextformat_layout_GetTrimming,
4738 dwritetextformat_layout_GetLineSpacing,
4739 dwritetextformat_layout_GetFontCollection,
4740 dwritetextformat_layout_GetFontFamilyNameLength,
4741 dwritetextformat_layout_GetFontFamilyName,
4742 dwritetextformat_layout_GetFontWeight,
4743 dwritetextformat_layout_GetFontStyle,
4744 dwritetextformat_layout_GetFontStretch,
4745 dwritetextformat_layout_GetFontSize,
4746 dwritetextformat_layout_GetLocaleNameLength,
4747 dwritetextformat_layout_GetLocaleName,
4748 dwritetextformat1_layout_SetVerticalGlyphOrientation,
4749 dwritetextformat1_layout_GetVerticalGlyphOrientation,
4750 dwritetextformat1_layout_SetLastLineWrapping,
4751 dwritetextformat1_layout_GetLastLineWrapping,
4752 dwritetextformat1_layout_SetOpticalAlignment,
4753 dwritetextformat1_layout_GetOpticalAlignment,
4754 dwritetextformat1_layout_SetFontFallback,
4755 dwritetextformat1_layout_GetFontFallback,
4756 dwritetextformat2_layout_SetLineSpacing,
4757 dwritetextformat2_layout_GetLineSpacing,
4758 dwritetextformat3_layout_SetFontAxisValues,
4759 dwritetextformat3_layout_GetFontAxisValueCount,
4760 dwritetextformat3_layout_GetFontAxisValues,
4761 dwritetextformat3_layout_GetAutomaticFontAxes,
4762 dwritetextformat3_layout_SetAutomaticFontAxes,
4765 static HRESULT WINAPI dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink1 *iface,
4766 REFIID riid, void **obj)
4768 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink1) ||
4769 IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) ||
4770 IsEqualIID(riid, &IID_IUnknown))
4772 *obj = iface;
4773 IDWriteTextAnalysisSink1_AddRef(iface);
4774 return S_OK;
4777 WARN("%s not implemented.\n", debugstr_guid(riid));
4779 *obj = NULL;
4780 return E_NOINTERFACE;
4783 static ULONG WINAPI dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink1 *iface)
4785 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4786 return IDWriteTextLayout4_AddRef(&layout->IDWriteTextLayout4_iface);
4789 static ULONG WINAPI dwritetextlayout_sink_Release(IDWriteTextAnalysisSink1 *iface)
4791 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4792 return IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
4795 static HRESULT WINAPI dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink1 *iface,
4796 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
4798 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4799 struct layout_run *run;
4801 TRACE("[%u,%u) script=%u:%s\n", position, position + length, sa->script, debugstr_sa_script(sa->script));
4803 run = alloc_layout_run(LAYOUT_RUN_REGULAR, position);
4804 if (!run)
4805 return E_OUTOFMEMORY;
4807 run->u.regular.descr.string = &layout->str[position];
4808 run->u.regular.descr.stringLength = length;
4809 run->u.regular.descr.textPosition = position;
4810 run->u.regular.sa = *sa;
4811 list_add_tail(&layout->runs, &run->entry);
4812 return S_OK;
4815 static HRESULT WINAPI dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink1 *iface,
4816 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
4818 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4820 if (position + length > layout->len)
4821 return E_FAIL;
4823 memcpy(&layout->nominal_breakpoints[position], breakpoints, length*sizeof(DWRITE_LINE_BREAKPOINT));
4824 return S_OK;
4827 static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink1 *iface, UINT32 position,
4828 UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
4830 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4831 struct layout_run *cur_run;
4833 TRACE("[%u,%u) %u %u\n", position, position + length, explicitLevel, resolvedLevel);
4835 LIST_FOR_EACH_ENTRY(cur_run, &layout->runs, struct layout_run, entry) {
4836 struct regular_layout_run *cur = &cur_run->u.regular;
4837 struct layout_run *run;
4839 if (cur_run->kind == LAYOUT_RUN_INLINE)
4840 continue;
4842 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
4843 if (position < cur->descr.textPosition || position >= cur->descr.textPosition + cur->descr.stringLength)
4844 continue;
4846 /* full hit - just set run level */
4847 if (cur->descr.textPosition == position && cur->descr.stringLength == length) {
4848 cur->run.bidiLevel = resolvedLevel;
4849 break;
4852 /* current run is fully covered, move to next one */
4853 if (cur->descr.textPosition == position && cur->descr.stringLength < length) {
4854 cur->run.bidiLevel = resolvedLevel;
4855 position += cur->descr.stringLength;
4856 length -= cur->descr.stringLength;
4857 continue;
4860 /* all fully covered runs are processed at this point, reuse existing run for remaining
4861 reported bidi range and add another run for the rest of original one */
4863 run = alloc_layout_run(LAYOUT_RUN_REGULAR, position + length);
4864 if (!run)
4865 return E_OUTOFMEMORY;
4867 *run = *cur_run;
4868 run->u.regular.descr.textPosition = position + length;
4869 run->u.regular.descr.stringLength = cur->descr.stringLength - length;
4870 run->u.regular.descr.string = &layout->str[position + length];
4872 /* reduce existing run */
4873 cur->run.bidiLevel = resolvedLevel;
4874 cur->descr.stringLength = length;
4876 list_add_after(&cur_run->entry, &run->entry);
4877 break;
4880 return S_OK;
4883 static HRESULT WINAPI dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink1 *iface,
4884 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
4886 return E_NOTIMPL;
4889 static HRESULT WINAPI dwritetextlayout_sink_SetGlyphOrientation(IDWriteTextAnalysisSink1 *iface,
4890 UINT32 position, UINT32 length, DWRITE_GLYPH_ORIENTATION_ANGLE angle, UINT8 adjusted_bidi_level,
4891 BOOL is_sideways, BOOL is_rtl)
4893 return E_NOTIMPL;
4896 static const IDWriteTextAnalysisSink1Vtbl dwritetextlayoutsinkvtbl = {
4897 dwritetextlayout_sink_QueryInterface,
4898 dwritetextlayout_sink_AddRef,
4899 dwritetextlayout_sink_Release,
4900 dwritetextlayout_sink_SetScriptAnalysis,
4901 dwritetextlayout_sink_SetLineBreakpoints,
4902 dwritetextlayout_sink_SetBidiLevel,
4903 dwritetextlayout_sink_SetNumberSubstitution,
4904 dwritetextlayout_sink_SetGlyphOrientation
4907 static HRESULT WINAPI dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource1 *iface,
4908 REFIID riid, void **obj)
4910 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource1) ||
4911 IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) ||
4912 IsEqualIID(riid, &IID_IUnknown))
4914 *obj = iface;
4915 IDWriteTextAnalysisSource1_AddRef(iface);
4916 return S_OK;
4919 WARN("%s not implemented.\n", debugstr_guid(riid));
4921 *obj = NULL;
4922 return E_NOINTERFACE;
4925 static ULONG WINAPI dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource1 *iface)
4927 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4928 return IDWriteTextLayout4_AddRef(&layout->IDWriteTextLayout4_iface);
4931 static ULONG WINAPI dwritetextlayout_source_Release(IDWriteTextAnalysisSource1 *iface)
4933 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4934 return IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
4937 static HRESULT WINAPI dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource1 *iface,
4938 UINT32 position, WCHAR const** text, UINT32* text_len)
4940 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4942 TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
4944 if (position < layout->len) {
4945 *text = &layout->str[position];
4946 *text_len = layout->len - position;
4948 else {
4949 *text = NULL;
4950 *text_len = 0;
4953 return S_OK;
4956 static HRESULT WINAPI dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource1 *iface,
4957 UINT32 position, WCHAR const** text, UINT32* text_len)
4959 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4961 TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
4963 if (position > 0 && position < layout->len) {
4964 *text = layout->str;
4965 *text_len = position;
4967 else {
4968 *text = NULL;
4969 *text_len = 0;
4972 return S_OK;
4975 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource1 *iface)
4977 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4978 return IDWriteTextLayout4_GetReadingDirection(&layout->IDWriteTextLayout4_iface);
4981 static HRESULT WINAPI dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource1 *iface,
4982 UINT32 position, UINT32* text_len, WCHAR const** locale)
4984 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4985 struct layout_range *range = get_layout_range_by_pos(layout, position);
4987 if (position < layout->len) {
4988 struct layout_range *next;
4990 *locale = range->locale;
4991 *text_len = range->h.range.length - position;
4993 next = LIST_ENTRY(list_next(&layout->ranges, &range->h.entry), struct layout_range, h.entry);
4994 while (next && next->h.range.startPosition < layout->len && !strcmpW(range->locale, next->locale)) {
4995 *text_len += next->h.range.length;
4996 next = LIST_ENTRY(list_next(&layout->ranges, &next->h.entry), struct layout_range, h.entry);
4999 *text_len = min(*text_len, layout->len - position);
5001 else {
5002 *locale = NULL;
5003 *text_len = 0;
5006 return S_OK;
5009 static HRESULT WINAPI dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource1 *iface,
5010 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
5012 FIXME("%u %p %p: stub\n", position, text_len, substitution);
5013 return E_NOTIMPL;
5016 static HRESULT WINAPI dwritetextlayout_source_GetVerticalGlyphOrientation(IDWriteTextAnalysisSource1 *iface,
5017 UINT32 position, UINT32 *length, DWRITE_VERTICAL_GLYPH_ORIENTATION *orientation, UINT8 *bidi_level)
5019 FIXME("%u %p %p %p: stub\n", position, length, orientation, bidi_level);
5020 return E_NOTIMPL;
5023 static const IDWriteTextAnalysisSource1Vtbl dwritetextlayoutsourcevtbl = {
5024 dwritetextlayout_source_QueryInterface,
5025 dwritetextlayout_source_AddRef,
5026 dwritetextlayout_source_Release,
5027 dwritetextlayout_source_GetTextAtPosition,
5028 dwritetextlayout_source_GetTextBeforePosition,
5029 dwritetextlayout_source_GetParagraphReadingDirection,
5030 dwritetextlayout_source_GetLocaleName,
5031 dwritetextlayout_source_GetNumberSubstitution,
5032 dwritetextlayout_source_GetVerticalGlyphOrientation
5035 static HRESULT layout_format_from_textformat(struct dwrite_textlayout *layout, IDWriteTextFormat *format)
5037 struct dwrite_textformat *textformat;
5038 IDWriteTextFormat1 *format1;
5039 UINT32 len;
5040 HRESULT hr;
5042 if ((textformat = unsafe_impl_from_IDWriteTextFormat(format))) {
5043 layout->format = textformat->format;
5045 layout->format.locale = heap_strdupW(textformat->format.locale);
5046 layout->format.family_name = heap_strdupW(textformat->format.family_name);
5047 if (!layout->format.locale || !layout->format.family_name)
5049 heap_free(layout->format.locale);
5050 heap_free(layout->format.family_name);
5051 return E_OUTOFMEMORY;
5054 if (layout->format.trimmingsign)
5055 IDWriteInlineObject_AddRef(layout->format.trimmingsign);
5056 if (layout->format.collection)
5057 IDWriteFontCollection_AddRef(layout->format.collection);
5058 if (layout->format.fallback)
5059 IDWriteFontFallback_AddRef(layout->format.fallback);
5061 return S_OK;
5064 layout->format.weight = IDWriteTextFormat_GetFontWeight(format);
5065 layout->format.style = IDWriteTextFormat_GetFontStyle(format);
5066 layout->format.stretch = IDWriteTextFormat_GetFontStretch(format);
5067 layout->format.fontsize= IDWriteTextFormat_GetFontSize(format);
5068 layout->format.tabstop = IDWriteTextFormat_GetIncrementalTabStop(format);
5069 layout->format.textalignment = IDWriteTextFormat_GetTextAlignment(format);
5070 layout->format.paralign = IDWriteTextFormat_GetParagraphAlignment(format);
5071 layout->format.wrapping = IDWriteTextFormat_GetWordWrapping(format);
5072 layout->format.readingdir = IDWriteTextFormat_GetReadingDirection(format);
5073 layout->format.flow = IDWriteTextFormat_GetFlowDirection(format);
5074 layout->format.fallback = NULL;
5075 layout->format.spacing.leadingBefore = 0.0f;
5076 layout->format.spacing.fontLineGapUsage = DWRITE_FONT_LINE_GAP_USAGE_DEFAULT;
5077 hr = IDWriteTextFormat_GetLineSpacing(format, &layout->format.spacing.method,
5078 &layout->format.spacing.height, &layout->format.spacing.baseline);
5079 if (FAILED(hr))
5080 return hr;
5082 hr = IDWriteTextFormat_GetTrimming(format, &layout->format.trimming, &layout->format.trimmingsign);
5083 if (FAILED(hr))
5084 return hr;
5086 /* locale name and length */
5087 len = IDWriteTextFormat_GetLocaleNameLength(format);
5088 layout->format.locale = heap_alloc((len+1)*sizeof(WCHAR));
5089 if (!layout->format.locale)
5090 return E_OUTOFMEMORY;
5092 hr = IDWriteTextFormat_GetLocaleName(format, layout->format.locale, len+1);
5093 if (FAILED(hr))
5094 return hr;
5095 layout->format.locale_len = len;
5097 /* font family name and length */
5098 len = IDWriteTextFormat_GetFontFamilyNameLength(format);
5099 layout->format.family_name = heap_alloc((len+1)*sizeof(WCHAR));
5100 if (!layout->format.family_name)
5101 return E_OUTOFMEMORY;
5103 hr = IDWriteTextFormat_GetFontFamilyName(format, layout->format.family_name, len+1);
5104 if (FAILED(hr))
5105 return hr;
5106 layout->format.family_len = len;
5108 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
5109 if (hr == S_OK) {
5110 IDWriteTextFormat2 *format2;
5112 layout->format.vertical_orientation = IDWriteTextFormat1_GetVerticalGlyphOrientation(format1);
5113 layout->format.optical_alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
5114 IDWriteTextFormat1_GetFontFallback(format1, &layout->format.fallback);
5116 if (IDWriteTextFormat1_QueryInterface(format1, &IID_IDWriteTextFormat2, (void**)&format2) == S_OK) {
5117 IDWriteTextFormat2_GetLineSpacing(format2, &layout->format.spacing);
5118 IDWriteTextFormat2_Release(format2);
5121 IDWriteTextFormat1_Release(format1);
5123 else {
5124 layout->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
5125 layout->format.optical_alignment = DWRITE_OPTICAL_ALIGNMENT_NONE;
5128 return IDWriteTextFormat_GetFontCollection(format, &layout->format.collection);
5131 static HRESULT init_textlayout(const struct textlayout_desc *desc, struct dwrite_textlayout *layout)
5133 struct layout_range_header *range, *strike, *underline, *effect, *spacing, *typography;
5134 static const DWRITE_TEXT_RANGE r = { 0, ~0u };
5135 HRESULT hr;
5137 layout->IDWriteTextLayout4_iface.lpVtbl = &dwritetextlayoutvtbl;
5138 layout->IDWriteTextFormat3_iface.lpVtbl = &dwritetextformat3_layout_vtbl;
5139 layout->IDWriteTextAnalysisSink1_iface.lpVtbl = &dwritetextlayoutsinkvtbl;
5140 layout->IDWriteTextAnalysisSource1_iface.lpVtbl = &dwritetextlayoutsourcevtbl;
5141 layout->refcount = 1;
5142 layout->len = desc->length;
5143 layout->recompute = RECOMPUTE_EVERYTHING;
5144 layout->nominal_breakpoints = NULL;
5145 layout->actual_breakpoints = NULL;
5146 layout->cluster_count = 0;
5147 layout->clustermetrics = NULL;
5148 layout->clusters = NULL;
5149 layout->lines = NULL;
5150 layout->lines_size = 0;
5151 layout->minwidth = 0.0f;
5152 list_init(&layout->eruns);
5153 list_init(&layout->inlineobjects);
5154 list_init(&layout->underlines);
5155 list_init(&layout->strikethrough);
5156 list_init(&layout->runs);
5157 list_init(&layout->ranges);
5158 list_init(&layout->strike_ranges);
5159 list_init(&layout->underline_ranges);
5160 list_init(&layout->effects);
5161 list_init(&layout->spacing);
5162 list_init(&layout->typographies);
5163 memset(&layout->format, 0, sizeof(layout->format));
5164 memset(&layout->metrics, 0, sizeof(layout->metrics));
5165 layout->metrics.layoutWidth = desc->max_width;
5166 layout->metrics.layoutHeight = desc->max_height;
5167 layout->measuringmode = DWRITE_MEASURING_MODE_NATURAL;
5169 layout->ppdip = 0.0f;
5170 memset(&layout->transform, 0, sizeof(layout->transform));
5172 layout->str = heap_strdupnW(desc->string, desc->length);
5173 if (desc->length && !layout->str) {
5174 hr = E_OUTOFMEMORY;
5175 goto fail;
5178 hr = layout_format_from_textformat(layout, desc->format);
5179 if (FAILED(hr))
5180 goto fail;
5182 range = alloc_layout_range(layout, &r, LAYOUT_RANGE_REGULAR);
5183 strike = alloc_layout_range(layout, &r, LAYOUT_RANGE_STRIKETHROUGH);
5184 underline = alloc_layout_range(layout, &r, LAYOUT_RANGE_UNDERLINE);
5185 effect = alloc_layout_range(layout, &r, LAYOUT_RANGE_EFFECT);
5186 spacing = alloc_layout_range(layout, &r, LAYOUT_RANGE_SPACING);
5187 typography = alloc_layout_range(layout, &r, LAYOUT_RANGE_TYPOGRAPHY);
5188 if (!range || !strike || !effect || !spacing || !typography || !underline) {
5189 free_layout_range(range);
5190 free_layout_range(strike);
5191 free_layout_range(underline);
5192 free_layout_range(effect);
5193 free_layout_range(spacing);
5194 free_layout_range(typography);
5195 hr = E_OUTOFMEMORY;
5196 goto fail;
5199 if (desc->is_gdi_compatible)
5200 layout->measuringmode = desc->use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
5201 else
5202 layout->measuringmode = DWRITE_MEASURING_MODE_NATURAL;
5203 layout->ppdip = desc->ppdip;
5204 layout->transform = desc->transform ? *desc->transform : identity;
5206 layout->factory = desc->factory;
5207 IDWriteFactory7_AddRef(layout->factory);
5208 list_add_head(&layout->ranges, &range->entry);
5209 list_add_head(&layout->strike_ranges, &strike->entry);
5210 list_add_head(&layout->underline_ranges, &underline->entry);
5211 list_add_head(&layout->effects, &effect->entry);
5212 list_add_head(&layout->spacing, &spacing->entry);
5213 list_add_head(&layout->typographies, &typography->entry);
5214 return S_OK;
5216 fail:
5217 IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
5218 return hr;
5221 HRESULT create_textlayout(const struct textlayout_desc *desc, IDWriteTextLayout **ret)
5223 struct dwrite_textlayout *layout;
5224 HRESULT hr;
5226 *ret = NULL;
5228 if (!desc->format || !desc->string)
5229 return E_INVALIDARG;
5231 layout = heap_alloc(sizeof(struct dwrite_textlayout));
5232 if (!layout) return E_OUTOFMEMORY;
5234 hr = init_textlayout(desc, layout);
5235 if (hr == S_OK)
5236 *ret = (IDWriteTextLayout *)&layout->IDWriteTextLayout4_iface;
5238 return hr;
5241 static HRESULT WINAPI dwritetrimmingsign_QueryInterface(IDWriteInlineObject *iface, REFIID riid, void **obj)
5243 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
5245 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
5247 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteInlineObject)) {
5248 *obj = iface;
5249 IDWriteInlineObject_AddRef(iface);
5250 return S_OK;
5253 WARN("%s not implemented.\n", debugstr_guid(riid));
5255 *obj = NULL;
5256 return E_NOINTERFACE;
5259 static ULONG WINAPI dwritetrimmingsign_AddRef(IDWriteInlineObject *iface)
5261 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
5262 ULONG ref = InterlockedIncrement(&This->ref);
5263 TRACE("(%p)->(%d)\n", This, ref);
5264 return ref;
5267 static ULONG WINAPI dwritetrimmingsign_Release(IDWriteInlineObject *iface)
5269 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
5270 ULONG ref = InterlockedDecrement(&This->ref);
5272 TRACE("(%p)->(%d)\n", This, ref);
5274 if (!ref) {
5275 IDWriteTextLayout_Release(This->layout);
5276 heap_free(This);
5279 return ref;
5282 static HRESULT WINAPI dwritetrimmingsign_Draw(IDWriteInlineObject *iface, void *context, IDWriteTextRenderer *renderer,
5283 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *effect)
5285 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
5286 DWRITE_LINE_METRICS line;
5287 UINT32 line_count;
5289 TRACE("(%p)->(%p %p %.2f %.2f %d %d %p)\n", This, context, renderer, originX, originY,
5290 is_sideways, is_rtl, effect);
5292 IDWriteTextLayout_GetLineMetrics(This->layout, &line, 1, &line_count);
5293 return IDWriteTextLayout_Draw(This->layout, context, renderer, originX, originY - line.baseline);
5296 static HRESULT WINAPI dwritetrimmingsign_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *ret)
5298 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
5299 DWRITE_TEXT_METRICS metrics;
5300 HRESULT hr;
5302 TRACE("(%p)->(%p)\n", This, ret);
5304 hr = IDWriteTextLayout_GetMetrics(This->layout, &metrics);
5305 if (FAILED(hr)) {
5306 memset(ret, 0, sizeof(*ret));
5307 return hr;
5310 ret->width = metrics.width;
5311 ret->height = 0.0f;
5312 ret->baseline = 0.0f;
5313 ret->supportsSideways = FALSE;
5314 return S_OK;
5317 static HRESULT WINAPI dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
5319 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
5320 TRACE("(%p)->(%p)\n", This, overhangs);
5321 return IDWriteTextLayout_GetOverhangMetrics(This->layout, overhangs);
5324 static HRESULT WINAPI dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
5325 DWRITE_BREAK_CONDITION *after)
5327 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
5329 TRACE("(%p)->(%p %p)\n", This, before, after);
5331 *before = *after = DWRITE_BREAK_CONDITION_NEUTRAL;
5332 return S_OK;
5335 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl = {
5336 dwritetrimmingsign_QueryInterface,
5337 dwritetrimmingsign_AddRef,
5338 dwritetrimmingsign_Release,
5339 dwritetrimmingsign_Draw,
5340 dwritetrimmingsign_GetMetrics,
5341 dwritetrimmingsign_GetOverhangMetrics,
5342 dwritetrimmingsign_GetBreakConditions
5345 static inline BOOL is_reading_direction_horz(DWRITE_READING_DIRECTION direction)
5347 return (direction == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT) ||
5348 (direction == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
5351 static inline BOOL is_reading_direction_vert(DWRITE_READING_DIRECTION direction)
5353 return (direction == DWRITE_READING_DIRECTION_TOP_TO_BOTTOM) ||
5354 (direction == DWRITE_READING_DIRECTION_BOTTOM_TO_TOP);
5357 static inline BOOL is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction)
5359 return (direction == DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT) ||
5360 (direction == DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT);
5363 static inline BOOL is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction)
5365 return (direction == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM) ||
5366 (direction == DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP);
5369 HRESULT create_trimmingsign(IDWriteFactory7 *factory, IDWriteTextFormat *format, IDWriteInlineObject **sign)
5371 static const WCHAR ellipsisW = 0x2026;
5372 struct dwrite_trimmingsign *This;
5373 DWRITE_READING_DIRECTION reading;
5374 DWRITE_FLOW_DIRECTION flow;
5375 HRESULT hr;
5377 *sign = NULL;
5379 /* Validate reading/flow direction here, layout creation won't complain about
5380 invalid combinations. */
5381 reading = IDWriteTextFormat_GetReadingDirection(format);
5382 flow = IDWriteTextFormat_GetFlowDirection(format);
5384 if ((is_reading_direction_horz(reading) && is_flow_direction_horz(flow)) ||
5385 (is_reading_direction_vert(reading) && is_flow_direction_vert(flow)))
5386 return DWRITE_E_FLOWDIRECTIONCONFLICTS;
5388 This = heap_alloc(sizeof(*This));
5389 if (!This)
5390 return E_OUTOFMEMORY;
5392 This->IDWriteInlineObject_iface.lpVtbl = &dwritetrimmingsignvtbl;
5393 This->ref = 1;
5395 hr = IDWriteFactory7_CreateTextLayout(factory, &ellipsisW, 1, format, 0.0f, 0.0f, &This->layout);
5396 if (FAILED(hr)) {
5397 heap_free(This);
5398 return hr;
5401 IDWriteTextLayout_SetWordWrapping(This->layout, DWRITE_WORD_WRAPPING_NO_WRAP);
5402 IDWriteTextLayout_SetParagraphAlignment(This->layout, DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
5403 IDWriteTextLayout_SetTextAlignment(This->layout, DWRITE_TEXT_ALIGNMENT_LEADING);
5405 *sign = &This->IDWriteInlineObject_iface;
5407 return S_OK;
5410 static HRESULT WINAPI dwritetextformat_QueryInterface(IDWriteTextFormat3 *iface, REFIID riid, void **obj)
5412 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5414 if (IsEqualIID(riid, &IID_IDWriteTextFormat3) ||
5415 IsEqualIID(riid, &IID_IDWriteTextFormat2) ||
5416 IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
5417 IsEqualIID(riid, &IID_IDWriteTextFormat) ||
5418 IsEqualIID(riid, &IID_IUnknown))
5420 *obj = iface;
5421 IDWriteTextFormat3_AddRef(iface);
5422 return S_OK;
5425 WARN("%s not implemented.\n", debugstr_guid(riid));
5427 *obj = NULL;
5429 return E_NOINTERFACE;
5432 static ULONG WINAPI dwritetextformat_AddRef(IDWriteTextFormat3 *iface)
5434 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5435 ULONG refcount = InterlockedIncrement(&format->refcount);
5437 TRACE("%p, refcount %d.\n", iface, refcount);
5439 return refcount;
5442 static ULONG WINAPI dwritetextformat_Release(IDWriteTextFormat3 *iface)
5444 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5445 ULONG refcount = InterlockedDecrement(&format->refcount);
5447 TRACE("%p, refcount %d.\n", iface, refcount);
5449 if (!refcount)
5451 release_format_data(&format->format);
5452 heap_free(format);
5455 return refcount;
5458 static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat3 *iface, DWRITE_TEXT_ALIGNMENT alignment)
5460 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5462 TRACE("%p, %d.\n", iface, alignment);
5464 return format_set_textalignment(&format->format, alignment, NULL);
5467 static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat3 *iface,
5468 DWRITE_PARAGRAPH_ALIGNMENT alignment)
5470 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5472 TRACE("%p, %d.\n", iface, alignment);
5474 return format_set_paralignment(&format->format, alignment, NULL);
5477 static HRESULT WINAPI dwritetextformat_SetWordWrapping(IDWriteTextFormat3 *iface, DWRITE_WORD_WRAPPING wrapping)
5479 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5481 TRACE("%p, %d.\n", iface, wrapping);
5483 return format_set_wordwrapping(&format->format, wrapping, NULL);
5486 static HRESULT WINAPI dwritetextformat_SetReadingDirection(IDWriteTextFormat3 *iface, DWRITE_READING_DIRECTION direction)
5488 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5490 TRACE("%p, %d.\n", iface, direction);
5492 return format_set_readingdirection(&format->format, direction, NULL);
5495 static HRESULT WINAPI dwritetextformat_SetFlowDirection(IDWriteTextFormat3 *iface, DWRITE_FLOW_DIRECTION direction)
5497 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5499 TRACE("%p, %d.\n", iface, direction);
5501 return format_set_flowdirection(&format->format, direction, NULL);
5504 static HRESULT WINAPI dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat3 *iface, FLOAT tabstop)
5506 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5508 TRACE("%p, %f.\n", iface, tabstop);
5510 if (tabstop <= 0.0f)
5511 return E_INVALIDARG;
5513 format->format.tabstop = tabstop;
5514 return S_OK;
5517 static HRESULT WINAPI dwritetextformat_SetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING const *trimming,
5518 IDWriteInlineObject *trimming_sign)
5520 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5522 TRACE("%p, %p, %p.\n", iface, trimming, trimming_sign);
5524 return format_set_trimming(&format->format, trimming, trimming_sign, NULL);
5527 static HRESULT WINAPI dwritetextformat_SetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING_METHOD method,
5528 FLOAT height, FLOAT baseline)
5530 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5531 DWRITE_LINE_SPACING spacing;
5533 TRACE("%p, %d, %f, %f.\n", iface, method, height, baseline);
5535 spacing = format->format.spacing;
5536 spacing.method = method;
5537 spacing.height = height;
5538 spacing.baseline = baseline;
5540 return format_set_linespacing(&format->format, &spacing, NULL);
5543 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_GetTextAlignment(IDWriteTextFormat3 *iface)
5545 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5547 TRACE("%p.\n", iface);
5549 return format->format.textalignment;
5552 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_GetParagraphAlignment(IDWriteTextFormat3 *iface)
5554 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5556 TRACE("%p.\n", iface);
5558 return format->format.paralign;
5561 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_GetWordWrapping(IDWriteTextFormat3 *iface)
5563 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5565 TRACE("%p.\n", iface);
5567 return format->format.wrapping;
5570 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_GetReadingDirection(IDWriteTextFormat3 *iface)
5572 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5574 TRACE("%p.\n", iface);
5576 return format->format.readingdir;
5579 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_GetFlowDirection(IDWriteTextFormat3 *iface)
5581 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5583 TRACE("%p.\n", iface);
5585 return format->format.flow;
5588 static FLOAT WINAPI dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat3 *iface)
5590 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5592 TRACE("%p.\n", iface);
5594 return format->format.tabstop;
5597 static HRESULT WINAPI dwritetextformat_GetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING *options,
5598 IDWriteInlineObject **trimming_sign)
5600 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5602 TRACE("%p, %p, %p.\n", iface, options, trimming_sign);
5604 *options = format->format.trimming;
5605 if ((*trimming_sign = format->format.trimmingsign))
5606 IDWriteInlineObject_AddRef(*trimming_sign);
5608 return S_OK;
5611 static HRESULT WINAPI dwritetextformat_GetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING_METHOD *method,
5612 FLOAT *spacing, FLOAT *baseline)
5614 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5616 TRACE("%p, %p, %p, %p.\n", iface, method, spacing, baseline);
5618 *method = format->format.spacing.method;
5619 *spacing = format->format.spacing.height;
5620 *baseline = format->format.spacing.baseline;
5621 return S_OK;
5624 static HRESULT WINAPI dwritetextformat_GetFontCollection(IDWriteTextFormat3 *iface, IDWriteFontCollection **collection)
5626 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5628 TRACE("%p, %p.\n", iface, collection);
5630 *collection = format->format.collection;
5631 IDWriteFontCollection_AddRef(*collection);
5633 return S_OK;
5636 static UINT32 WINAPI dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat3 *iface)
5638 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5640 TRACE("%p.\n", iface);
5642 return format->format.family_len;
5645 static HRESULT WINAPI dwritetextformat_GetFontFamilyName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
5647 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5649 TRACE("%p, %p, %u.\n", iface, name, size);
5651 if (size <= format->format.family_len)
5652 return E_NOT_SUFFICIENT_BUFFER;
5653 strcpyW(name, format->format.family_name);
5654 return S_OK;
5657 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_GetFontWeight(IDWriteTextFormat3 *iface)
5659 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5661 TRACE("%p.\n", iface);
5663 return format->format.weight;
5666 static DWRITE_FONT_STYLE WINAPI dwritetextformat_GetFontStyle(IDWriteTextFormat3 *iface)
5668 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5670 TRACE("%p.\n", iface);
5672 return format->format.style;
5675 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_GetFontStretch(IDWriteTextFormat3 *iface)
5677 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5679 TRACE("%p.\n", iface);
5681 return format->format.stretch;
5684 static FLOAT WINAPI dwritetextformat_GetFontSize(IDWriteTextFormat3 *iface)
5686 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5688 TRACE("%p.\n", iface);
5690 return format->format.fontsize;
5693 static UINT32 WINAPI dwritetextformat_GetLocaleNameLength(IDWriteTextFormat3 *iface)
5695 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5697 TRACE("%p.\n", iface);
5699 return format->format.locale_len;
5702 static HRESULT WINAPI dwritetextformat_GetLocaleName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
5704 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5706 TRACE("%p, %p %u.\n", iface, name, size);
5708 if (size <= format->format.locale_len)
5709 return E_NOT_SUFFICIENT_BUFFER;
5710 strcpyW(name, format->format.locale);
5711 return S_OK;
5714 static HRESULT WINAPI dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat3 *iface,
5715 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
5717 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5719 TRACE("%p, %d.\n", iface, orientation);
5721 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
5722 return E_INVALIDARG;
5724 format->format.vertical_orientation = orientation;
5725 return S_OK;
5728 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat3 *iface)
5730 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5732 TRACE("%p.\n", iface);
5734 return format->format.vertical_orientation;
5737 static HRESULT WINAPI dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat3 *iface, BOOL lastline_wrapping_enabled)
5739 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5741 TRACE("%p, %d.\n", iface, lastline_wrapping_enabled);
5743 format->format.last_line_wrapping = !!lastline_wrapping_enabled;
5744 return S_OK;
5747 static BOOL WINAPI dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat3 *iface)
5749 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5751 TRACE("%p.\n", iface);
5753 return format->format.last_line_wrapping;
5756 static HRESULT WINAPI dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat3 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
5758 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5760 TRACE("%p, %d.\n", iface, alignment);
5762 return format_set_optical_alignment(&format->format, alignment);
5765 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat3 *iface)
5767 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5769 TRACE("%p.\n", iface);
5771 return format->format.optical_alignment;
5774 static HRESULT WINAPI dwritetextformat1_SetFontFallback(IDWriteTextFormat3 *iface, IDWriteFontFallback *fallback)
5776 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5778 TRACE("%p, %p.\n", iface, fallback);
5780 return set_fontfallback_for_format(&format->format, fallback);
5783 static HRESULT WINAPI dwritetextformat1_GetFontFallback(IDWriteTextFormat3 *iface, IDWriteFontFallback **fallback)
5785 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5787 TRACE("%p, %p.\n", iface, fallback);
5789 return get_fontfallback_from_format(&format->format, fallback);
5792 static HRESULT WINAPI dwritetextformat2_SetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING const *spacing)
5794 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5796 TRACE("%p, %p.\n", iface, spacing);
5798 return format_set_linespacing(&format->format, spacing, NULL);
5801 static HRESULT WINAPI dwritetextformat2_GetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING *spacing)
5803 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5805 TRACE("%p, %p.\n", iface, spacing);
5807 *spacing = format->format.spacing;
5808 return S_OK;
5811 static HRESULT WINAPI dwritetextformat3_SetFontAxisValues(IDWriteTextFormat3 *iface,
5812 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values)
5814 FIXME("%p, %p, %u.\n", iface, axis_values, num_values);
5816 return E_NOTIMPL;
5819 static UINT32 WINAPI dwritetextformat3_GetFontAxisValueCount(IDWriteTextFormat3 *iface)
5821 FIXME("%p.\n", iface);
5823 return 0;
5826 static HRESULT WINAPI dwritetextformat3_GetFontAxisValues(IDWriteTextFormat3 *iface,
5827 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values)
5829 FIXME("%p, %p, %u.\n", iface, axis_values, num_values);
5831 return E_NOTIMPL;
5834 static DWRITE_AUTOMATIC_FONT_AXES WINAPI dwritetextformat3_GetAutomaticFontAxes(IDWriteTextFormat3 *iface)
5836 FIXME("%p.\n", iface);
5838 return DWRITE_AUTOMATIC_FONT_AXES_NONE;
5841 static HRESULT WINAPI dwritetextformat3_SetAutomaticFontAxes(IDWriteTextFormat3 *iface, DWRITE_AUTOMATIC_FONT_AXES axes)
5843 FIXME("%p, %d.\n", iface, axes);
5845 return E_NOTIMPL;
5848 static const IDWriteTextFormat3Vtbl dwritetextformatvtbl =
5850 dwritetextformat_QueryInterface,
5851 dwritetextformat_AddRef,
5852 dwritetextformat_Release,
5853 dwritetextformat_SetTextAlignment,
5854 dwritetextformat_SetParagraphAlignment,
5855 dwritetextformat_SetWordWrapping,
5856 dwritetextformat_SetReadingDirection,
5857 dwritetextformat_SetFlowDirection,
5858 dwritetextformat_SetIncrementalTabStop,
5859 dwritetextformat_SetTrimming,
5860 dwritetextformat_SetLineSpacing,
5861 dwritetextformat_GetTextAlignment,
5862 dwritetextformat_GetParagraphAlignment,
5863 dwritetextformat_GetWordWrapping,
5864 dwritetextformat_GetReadingDirection,
5865 dwritetextformat_GetFlowDirection,
5866 dwritetextformat_GetIncrementalTabStop,
5867 dwritetextformat_GetTrimming,
5868 dwritetextformat_GetLineSpacing,
5869 dwritetextformat_GetFontCollection,
5870 dwritetextformat_GetFontFamilyNameLength,
5871 dwritetextformat_GetFontFamilyName,
5872 dwritetextformat_GetFontWeight,
5873 dwritetextformat_GetFontStyle,
5874 dwritetextformat_GetFontStretch,
5875 dwritetextformat_GetFontSize,
5876 dwritetextformat_GetLocaleNameLength,
5877 dwritetextformat_GetLocaleName,
5878 dwritetextformat1_SetVerticalGlyphOrientation,
5879 dwritetextformat1_GetVerticalGlyphOrientation,
5880 dwritetextformat1_SetLastLineWrapping,
5881 dwritetextformat1_GetLastLineWrapping,
5882 dwritetextformat1_SetOpticalAlignment,
5883 dwritetextformat1_GetOpticalAlignment,
5884 dwritetextformat1_SetFontFallback,
5885 dwritetextformat1_GetFontFallback,
5886 dwritetextformat2_SetLineSpacing,
5887 dwritetextformat2_GetLineSpacing,
5888 dwritetextformat3_SetFontAxisValues,
5889 dwritetextformat3_GetFontAxisValueCount,
5890 dwritetextformat3_GetFontAxisValues,
5891 dwritetextformat3_GetAutomaticFontAxes,
5892 dwritetextformat3_SetAutomaticFontAxes,
5895 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat *iface)
5897 return (iface->lpVtbl == (IDWriteTextFormatVtbl*)&dwritetextformatvtbl) ?
5898 CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat3_iface) : NULL;
5901 HRESULT create_textformat(const WCHAR *family_name, IDWriteFontCollection *collection, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style,
5902 DWRITE_FONT_STRETCH stretch, FLOAT size, const WCHAR *locale, IDWriteTextFormat **format)
5904 struct dwrite_textformat *This;
5906 *format = NULL;
5908 if (size <= 0.0f)
5909 return E_INVALIDARG;
5911 if (((UINT32)weight > DWRITE_FONT_WEIGHT_ULTRA_BLACK) ||
5912 ((UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED) ||
5913 ((UINT32)style > DWRITE_FONT_STYLE_ITALIC))
5914 return E_INVALIDARG;
5916 This = heap_alloc(sizeof(struct dwrite_textformat));
5917 if (!This) return E_OUTOFMEMORY;
5919 This->IDWriteTextFormat3_iface.lpVtbl = &dwritetextformatvtbl;
5920 This->refcount = 1;
5921 This->format.family_name = heap_strdupW(family_name);
5922 This->format.family_len = strlenW(family_name);
5923 This->format.locale = heap_strdupW(locale);
5924 This->format.locale_len = strlenW(locale);
5925 /* force locale name to lower case, layout will inherit this modified value */
5926 strlwrW(This->format.locale);
5927 This->format.weight = weight;
5928 This->format.style = style;
5929 This->format.fontsize = size;
5930 This->format.tabstop = 4.0f * size;
5931 This->format.stretch = stretch;
5932 This->format.textalignment = DWRITE_TEXT_ALIGNMENT_LEADING;
5933 This->format.optical_alignment = DWRITE_OPTICAL_ALIGNMENT_NONE;
5934 This->format.paralign = DWRITE_PARAGRAPH_ALIGNMENT_NEAR;
5935 This->format.wrapping = DWRITE_WORD_WRAPPING_WRAP;
5936 This->format.last_line_wrapping = TRUE;
5937 This->format.readingdir = DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
5938 This->format.flow = DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM;
5939 This->format.spacing.method = DWRITE_LINE_SPACING_METHOD_DEFAULT;
5940 This->format.spacing.height = 0.0f;
5941 This->format.spacing.baseline = 0.0f;
5942 This->format.spacing.leadingBefore = 0.0f;
5943 This->format.spacing.fontLineGapUsage = DWRITE_FONT_LINE_GAP_USAGE_DEFAULT;
5944 This->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
5945 This->format.trimming.granularity = DWRITE_TRIMMING_GRANULARITY_NONE;
5946 This->format.trimming.delimiter = 0;
5947 This->format.trimming.delimiterCount = 0;
5948 This->format.trimmingsign = NULL;
5949 This->format.collection = collection;
5950 This->format.fallback = NULL;
5951 IDWriteFontCollection_AddRef(collection);
5953 *format = (IDWriteTextFormat *)&This->IDWriteTextFormat3_iface;
5955 return S_OK;
5958 static HRESULT WINAPI dwritetypography_QueryInterface(IDWriteTypography *iface, REFIID riid, void **obj)
5960 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5962 if (IsEqualIID(riid, &IID_IDWriteTypography) || IsEqualIID(riid, &IID_IUnknown)) {
5963 *obj = iface;
5964 IDWriteTypography_AddRef(iface);
5965 return S_OK;
5968 WARN("%s not implemented.\n", debugstr_guid(riid));
5970 *obj = NULL;
5972 return E_NOINTERFACE;
5975 static ULONG WINAPI dwritetypography_AddRef(IDWriteTypography *iface)
5977 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5978 ULONG refcount = InterlockedIncrement(&typography->refcount);
5980 TRACE("%p, refcount %d.\n", iface, refcount);
5982 return refcount;
5985 static ULONG WINAPI dwritetypography_Release(IDWriteTypography *iface)
5987 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5988 ULONG refcount = InterlockedDecrement(&typography->refcount);
5990 TRACE("%p, refcount %d.\n", iface, refcount);
5992 if (!refcount)
5994 heap_free(typography->features);
5995 heap_free(typography);
5998 return refcount;
6001 static HRESULT WINAPI dwritetypography_AddFontFeature(IDWriteTypography *iface, DWRITE_FONT_FEATURE feature)
6003 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
6005 TRACE("%p, %s, %u.\n", iface, debugstr_tag(feature.nameTag), feature.parameter);
6007 if (!dwrite_array_reserve((void **)&typography->features, &typography->capacity, typography->count + 1,
6008 sizeof(*typography->features)))
6010 return E_OUTOFMEMORY;
6013 typography->features[typography->count++] = feature;
6015 return S_OK;
6018 static UINT32 WINAPI dwritetypography_GetFontFeatureCount(IDWriteTypography *iface)
6020 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
6022 TRACE("%p.\n", iface);
6024 return typography->count;
6027 static HRESULT WINAPI dwritetypography_GetFontFeature(IDWriteTypography *iface, UINT32 index,
6028 DWRITE_FONT_FEATURE *feature)
6030 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
6032 TRACE("%p, %u, %p.\n", iface, index, feature);
6034 if (index >= typography->count)
6035 return E_INVALIDARG;
6037 *feature = typography->features[index];
6038 return S_OK;
6041 static const IDWriteTypographyVtbl dwritetypographyvtbl = {
6042 dwritetypography_QueryInterface,
6043 dwritetypography_AddRef,
6044 dwritetypography_Release,
6045 dwritetypography_AddFontFeature,
6046 dwritetypography_GetFontFeatureCount,
6047 dwritetypography_GetFontFeature
6050 HRESULT create_typography(IDWriteTypography **ret)
6052 struct dwrite_typography *typography;
6054 *ret = NULL;
6056 typography = heap_alloc_zero(sizeof(*typography));
6057 if (!typography)
6058 return E_OUTOFMEMORY;
6060 typography->IDWriteTypography_iface.lpVtbl = &dwritetypographyvtbl;
6061 typography->refcount = 1;
6063 *ret = &typography->IDWriteTypography_iface;
6065 return S_OK;