explorer: Use root window if driver doesn't implement create_desktop.
[wine.git] / dlls / dwrite / layout.c
blob0d08ba99de614f31cda020bc7c108b31fc6eea3a
1 /*
2 * Copyright 2012, 2014-2022 Nikolay Sivov for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
21 #include <assert.h>
22 #include <stdarg.h>
23 #include <math.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "dwrite_private.h"
29 #include "scripts.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
33 enum layout_range_attr_kind {
34 LAYOUT_RANGE_ATTR_WEIGHT,
35 LAYOUT_RANGE_ATTR_STYLE,
36 LAYOUT_RANGE_ATTR_STRETCH,
37 LAYOUT_RANGE_ATTR_FONTSIZE,
38 LAYOUT_RANGE_ATTR_EFFECT,
39 LAYOUT_RANGE_ATTR_INLINE,
40 LAYOUT_RANGE_ATTR_UNDERLINE,
41 LAYOUT_RANGE_ATTR_STRIKETHROUGH,
42 LAYOUT_RANGE_ATTR_PAIR_KERNING,
43 LAYOUT_RANGE_ATTR_FONTCOLL,
44 LAYOUT_RANGE_ATTR_LOCALE,
45 LAYOUT_RANGE_ATTR_FONTFAMILY,
46 LAYOUT_RANGE_ATTR_SPACING,
47 LAYOUT_RANGE_ATTR_TYPOGRAPHY
50 struct layout_range_attr_value {
51 DWRITE_TEXT_RANGE range;
52 union {
53 DWRITE_FONT_WEIGHT weight;
54 DWRITE_FONT_STYLE style;
55 DWRITE_FONT_STRETCH stretch;
56 FLOAT fontsize;
57 IDWriteInlineObject *object;
58 IUnknown *effect;
59 BOOL underline;
60 BOOL strikethrough;
61 BOOL pair_kerning;
62 IDWriteFontCollection *collection;
63 const WCHAR *locale;
64 const WCHAR *fontfamily;
65 struct {
66 FLOAT leading;
67 FLOAT trailing;
68 FLOAT min_advance;
69 } spacing;
70 IDWriteTypography *typography;
71 } u;
74 enum layout_range_kind {
75 LAYOUT_RANGE_REGULAR,
76 LAYOUT_RANGE_UNDERLINE,
77 LAYOUT_RANGE_STRIKETHROUGH,
78 LAYOUT_RANGE_EFFECT,
79 LAYOUT_RANGE_SPACING,
80 LAYOUT_RANGE_TYPOGRAPHY
83 struct layout_range_header {
84 struct list entry;
85 enum layout_range_kind kind;
86 DWRITE_TEXT_RANGE range;
89 struct layout_range {
90 struct layout_range_header h;
91 DWRITE_FONT_WEIGHT weight;
92 DWRITE_FONT_STYLE style;
93 FLOAT fontsize;
94 DWRITE_FONT_STRETCH stretch;
95 IDWriteInlineObject *object;
96 BOOL pair_kerning;
97 IDWriteFontCollection *collection;
98 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
99 WCHAR *fontfamily;
102 struct layout_range_bool {
103 struct layout_range_header h;
104 BOOL value;
107 struct layout_range_iface {
108 struct layout_range_header h;
109 IUnknown *iface;
112 struct layout_range_spacing {
113 struct layout_range_header h;
114 FLOAT leading;
115 FLOAT trailing;
116 FLOAT min_advance;
119 enum layout_run_kind {
120 LAYOUT_RUN_REGULAR,
121 LAYOUT_RUN_INLINE
124 struct inline_object_run {
125 IDWriteInlineObject *object;
126 UINT16 length;
129 struct regular_layout_run {
130 DWRITE_GLYPH_RUN_DESCRIPTION descr;
131 DWRITE_GLYPH_RUN run;
132 DWRITE_SCRIPT_ANALYSIS sa;
133 UINT16 *glyphs;
134 UINT16 *clustermap;
135 FLOAT *advances;
136 DWRITE_GLYPH_OFFSET *offsets;
137 UINT32 glyphcount; /* actual glyph count after shaping, not necessarily the same as reported to Draw() */
140 struct layout_run
142 struct list entry;
143 enum layout_run_kind kind;
144 union
146 struct inline_object_run object;
147 struct regular_layout_run regular;
148 } u;
149 float baseline;
150 float height;
151 unsigned int start_position; /* run text position in range [0, layout-text-length) */
154 struct layout_effective_run {
155 struct list entry;
156 const struct layout_run *run; /* nominal run this one is based on */
157 UINT32 start; /* relative text position, 0 means first text position of a nominal run */
158 UINT32 length; /* length in codepoints that this run covers */
159 UINT32 glyphcount; /* total glyph count in this run */
160 IUnknown *effect; /* original reference is kept only at range level */
161 D2D1_POINT_2F origin; /* baseline origin */
162 FLOAT align_dx; /* adjustment from text alignment */
163 FLOAT width; /* run width */
164 UINT16 *clustermap; /* effective clustermap, allocated separately, is not reused from nominal map */
165 UINT32 line; /* 0-based line index in line metrics array */
166 BOOL underlined; /* set if this run is underlined */
167 D2D1_RECT_F bbox; /* ink run box, top == bottom means it wasn't estimated yet */
170 struct layout_effective_inline {
171 struct list entry;
172 IDWriteInlineObject *object; /* inline object, set explicitly or added when trimming a line */
173 IUnknown *effect; /* original reference is kept only at range level */
174 FLOAT baseline;
175 D2D1_POINT_2F origin; /* left top corner */
176 FLOAT align_dx; /* adjustment from text alignment */
177 FLOAT width; /* object width as it's reported it */
178 BOOL is_sideways; /* vertical flow direction flag passed to Draw */
179 BOOL is_rtl; /* bidi flag passed to Draw */
180 UINT32 line; /* 0-based line index in line metrics array */
183 struct layout_underline {
184 struct list entry;
185 const struct layout_effective_run *run;
186 DWRITE_UNDERLINE u;
189 struct layout_strikethrough {
190 struct list entry;
191 const struct layout_effective_run *run;
192 DWRITE_STRIKETHROUGH s;
195 struct layout_cluster {
196 const struct layout_run *run; /* link to nominal run this cluster belongs to */
197 UINT32 position; /* relative to run, first cluster has 0 position */
200 struct layout_line
202 float height; /* height based on content */
203 float baseline; /* baseline based on content */
204 DWRITE_LINE_METRICS1 metrics;
207 enum layout_recompute_mask {
208 RECOMPUTE_CLUSTERS = 1 << 0,
209 RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
210 RECOMPUTE_LINES = 1 << 2,
211 RECOMPUTE_OVERHANGS = 1 << 3,
212 RECOMPUTE_LINES_AND_OVERHANGS = RECOMPUTE_LINES | RECOMPUTE_OVERHANGS,
213 RECOMPUTE_EVERYTHING = 0xffff
216 struct dwrite_textlayout
218 IDWriteTextLayout4 IDWriteTextLayout4_iface;
219 IDWriteTextFormat3 IDWriteTextFormat3_iface;
220 IDWriteTextAnalysisSink1 IDWriteTextAnalysisSink1_iface;
221 IDWriteTextAnalysisSource1 IDWriteTextAnalysisSource1_iface;
222 LONG refcount;
224 IDWriteFactory7 *factory;
225 IDWriteFontCollection *system_collection;
227 WCHAR *str;
228 UINT32 len;
230 struct
232 unsigned int offset;
233 unsigned int length;
234 } text_source;
236 struct dwrite_textformat_data format;
237 struct list strike_ranges;
238 struct list underline_ranges;
239 struct list typographies;
240 struct list effects;
241 struct list spacing;
242 struct list ranges;
243 struct list runs;
244 /* lists ready to use by Draw() */
245 struct list eruns;
246 struct list inlineobjects;
247 struct list underlines;
248 struct list strikethrough;
249 USHORT recompute;
251 DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
252 DWRITE_LINE_BREAKPOINT *actual_breakpoints;
254 struct layout_cluster *clusters;
255 DWRITE_CLUSTER_METRICS *clustermetrics;
256 UINT32 cluster_count;
257 FLOAT minwidth;
259 struct layout_line *lines;
260 size_t lines_size;
262 DWRITE_TEXT_METRICS1 metrics;
263 DWRITE_OVERHANG_METRICS overhangs;
265 DWRITE_MEASURING_MODE measuringmode;
267 /* gdi-compatible layout specifics */
268 FLOAT ppdip;
269 DWRITE_MATRIX transform;
272 struct dwrite_typography {
273 IDWriteTypography IDWriteTypography_iface;
274 LONG refcount;
276 DWRITE_FONT_FEATURE *features;
277 size_t capacity;
278 size_t count;
281 static inline struct dwrite_textlayout *impl_from_IDWriteTextLayout4(IDWriteTextLayout4 *iface)
283 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextLayout4_iface);
286 static inline struct dwrite_textlayout *impl_from_IDWriteTextFormat3(IDWriteTextFormat3 *iface)
288 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextFormat3_iface);
291 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSink1(IDWriteTextAnalysisSink1 *iface)
293 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSink1_iface);
296 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSource1(IDWriteTextAnalysisSource1 *iface)
298 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSource1_iface);
301 static inline struct dwrite_typography *impl_from_IDWriteTypography(IDWriteTypography *iface)
303 return CONTAINING_RECORD(iface, struct dwrite_typography, IDWriteTypography_iface);
306 static inline const char *debugstr_rundescr(const DWRITE_GLYPH_RUN_DESCRIPTION *descr)
308 return wine_dbg_sprintf("[%u,%u)", descr->textPosition, descr->textPosition + descr->stringLength);
311 static inline BOOL is_layout_gdi_compatible(const struct dwrite_textlayout *layout)
313 return layout->measuringmode != DWRITE_MEASURING_MODE_NATURAL;
316 static BOOL is_run_rtl(const struct layout_effective_run *run)
318 return run->run->u.regular.run.bidiLevel & 1;
321 static HRESULT alloc_layout_run(enum layout_run_kind kind, unsigned int start_position,
322 struct layout_run **run)
324 if (!(*run = calloc(1, sizeof(**run))))
325 return E_OUTOFMEMORY;
327 (*run)->kind = kind;
328 (*run)->start_position = start_position;
330 return S_OK;
333 static void free_layout_runs(struct dwrite_textlayout *layout)
335 struct layout_run *cur, *cur2;
336 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->runs, struct layout_run, entry)
338 list_remove(&cur->entry);
339 if (cur->kind == LAYOUT_RUN_REGULAR)
341 if (cur->u.regular.run.fontFace)
342 IDWriteFontFace_Release(cur->u.regular.run.fontFace);
343 free(cur->u.regular.glyphs);
344 free(cur->u.regular.clustermap);
345 free(cur->u.regular.advances);
346 free(cur->u.regular.offsets);
348 free(cur);
352 static void free_layout_eruns(struct dwrite_textlayout *layout)
354 struct layout_effective_inline *in, *in2;
355 struct layout_effective_run *cur, *cur2;
356 struct layout_strikethrough *s, *s2;
357 struct layout_underline *u, *u2;
359 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->eruns, struct layout_effective_run, entry)
361 list_remove(&cur->entry);
362 free(cur->clustermap);
363 free(cur);
366 LIST_FOR_EACH_ENTRY_SAFE(in, in2, &layout->inlineobjects, struct layout_effective_inline, entry)
368 list_remove(&in->entry);
369 free(in);
372 LIST_FOR_EACH_ENTRY_SAFE(u, u2, &layout->underlines, struct layout_underline, entry)
374 list_remove(&u->entry);
375 free(u);
378 LIST_FOR_EACH_ENTRY_SAFE(s, s2, &layout->strikethrough, struct layout_strikethrough, entry)
380 list_remove(&s->entry);
381 free(s);
385 /* Used to resolve break condition by forcing stronger condition over weaker. */
386 static inline DWRITE_BREAK_CONDITION override_break_condition(DWRITE_BREAK_CONDITION existingbreak, DWRITE_BREAK_CONDITION newbreak)
388 switch (existingbreak) {
389 case DWRITE_BREAK_CONDITION_NEUTRAL:
390 return newbreak;
391 case DWRITE_BREAK_CONDITION_CAN_BREAK:
392 return newbreak == DWRITE_BREAK_CONDITION_NEUTRAL ? existingbreak : newbreak;
393 /* let's keep stronger conditions as is */
394 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK:
395 case DWRITE_BREAK_CONDITION_MUST_BREAK:
396 break;
397 default:
398 ERR("unknown break condition %d\n", existingbreak);
401 return existingbreak;
404 /* This helper should be used to get effective range length, in other words it returns number of text
405 positions from range starting point to the end of the range, limited by layout text length */
406 static inline UINT32 get_clipped_range_length(const struct dwrite_textlayout *layout, const struct layout_range *range)
408 if (range->h.range.startPosition + range->h.range.length <= layout->len)
409 return range->h.range.length;
410 return layout->len - range->h.range.startPosition;
413 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
414 static HRESULT layout_update_breakpoints_range(struct dwrite_textlayout *layout, const struct layout_range *cur)
416 DWRITE_BREAK_CONDITION before, after;
417 UINT32 i, length;
418 HRESULT hr;
420 /* ignore returned conditions if failed */
421 hr = IDWriteInlineObject_GetBreakConditions(cur->object, &before, &after);
422 if (FAILED(hr))
423 after = before = DWRITE_BREAK_CONDITION_NEUTRAL;
425 if (!layout->actual_breakpoints)
427 if (!(layout->actual_breakpoints = calloc(layout->len, sizeof(*layout->actual_breakpoints))))
428 return E_OUTOFMEMORY;
429 memcpy(layout->actual_breakpoints, layout->nominal_breakpoints, sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
432 length = get_clipped_range_length(layout, cur);
433 for (i = cur->h.range.startPosition; i < length + cur->h.range.startPosition; i++) {
434 /* for first codepoint check if there's anything before it and update accordingly */
435 if (i == cur->h.range.startPosition) {
436 if (i > 0)
437 layout->actual_breakpoints[i].breakConditionBefore = layout->actual_breakpoints[i-1].breakConditionAfter =
438 override_break_condition(layout->actual_breakpoints[i-1].breakConditionAfter, before);
439 else
440 layout->actual_breakpoints[i].breakConditionBefore = before;
441 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
443 /* similar check for last codepoint */
444 else if (i == cur->h.range.startPosition + length - 1) {
445 if (i == layout->len - 1)
446 layout->actual_breakpoints[i].breakConditionAfter = after;
447 else
448 layout->actual_breakpoints[i].breakConditionAfter = layout->actual_breakpoints[i+1].breakConditionBefore =
449 override_break_condition(layout->actual_breakpoints[i+1].breakConditionBefore, after);
450 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
452 /* for all positions within a range disable breaks */
453 else {
454 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
455 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
458 layout->actual_breakpoints[i].isWhitespace = 0;
459 layout->actual_breakpoints[i].isSoftHyphen = 0;
462 return S_OK;
465 static struct layout_range *get_layout_range_by_pos(const struct dwrite_textlayout *layout, UINT32 pos)
467 struct layout_range *cur;
469 LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, h.entry)
471 DWRITE_TEXT_RANGE *r = &cur->h.range;
472 if (r->startPosition <= pos && pos < r->startPosition + r->length)
473 return cur;
476 return NULL;
479 static struct layout_range_header *get_layout_range_header_by_pos(const struct list *ranges, UINT32 pos)
481 struct layout_range_header *cur;
483 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry)
485 DWRITE_TEXT_RANGE *r = &cur->range;
486 if (r->startPosition <= pos && pos < r->startPosition + r->length)
487 return cur;
490 return NULL;
493 static inline DWRITE_LINE_BREAKPOINT get_effective_breakpoint(const struct dwrite_textlayout *layout, UINT32 pos)
495 if (layout->actual_breakpoints)
496 return layout->actual_breakpoints[pos];
497 return layout->nominal_breakpoints[pos];
500 static inline void init_cluster_metrics(const struct dwrite_textlayout *layout, const struct regular_layout_run *run,
501 UINT16 start_glyph, UINT16 stop_glyph, UINT32 stop_position, UINT16 length, DWRITE_CLUSTER_METRICS *metrics)
503 UINT8 breakcondition;
504 UINT32 position;
505 UINT16 j;
507 /* For clusters made of control chars we report zero glyphs, and we need zero cluster
508 width as well; advances are already computed at this point and are not necessary zero. */
509 metrics->width = 0.0f;
510 if (run->run.glyphCount) {
511 for (j = start_glyph; j < stop_glyph; j++)
512 metrics->width += run->run.glyphAdvances[j];
514 metrics->length = length;
516 position = run->descr.textPosition + stop_position;
517 if (stop_glyph == run->glyphcount)
518 breakcondition = get_effective_breakpoint(layout, position).breakConditionAfter;
519 else {
520 breakcondition = get_effective_breakpoint(layout, position).breakConditionBefore;
521 if (stop_position) position -= 1;
524 metrics->canWrapLineAfter = breakcondition == DWRITE_BREAK_CONDITION_CAN_BREAK ||
525 breakcondition == DWRITE_BREAK_CONDITION_MUST_BREAK;
526 if (metrics->length == 1) {
527 DWRITE_LINE_BREAKPOINT bp = get_effective_breakpoint(layout, position);
528 metrics->isWhitespace = bp.isWhitespace;
529 metrics->isNewline = metrics->canWrapLineAfter && lb_is_newline_char(layout->str[position]);
530 metrics->isSoftHyphen = bp.isSoftHyphen;
532 else {
533 metrics->isWhitespace = 0;
534 metrics->isNewline = 0;
535 metrics->isSoftHyphen = 0;
537 metrics->isRightToLeft = run->run.bidiLevel & 1;
538 metrics->padding = 0;
543 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
544 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
545 Note that there's no need to reallocate anything at this point as we allocate one cluster per
546 codepoint initially.
549 static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 *cluster)
551 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[*cluster];
552 struct layout_cluster *c = &layout->clusters[*cluster];
553 const struct regular_layout_run *run = &r->u.regular;
554 UINT32 i, start = 0;
556 assert(r->kind == LAYOUT_RUN_REGULAR);
558 for (i = 0; i < run->descr.stringLength; i++) {
559 BOOL end = i == run->descr.stringLength - 1;
561 if (run->descr.clusterMap[start] != run->descr.clusterMap[i]) {
562 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->descr.clusterMap[i], i,
563 i - start, metrics);
564 c->position = start;
565 c->run = r;
567 *cluster += 1;
568 metrics++;
569 c++;
570 start = i;
573 if (end) {
574 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->glyphcount, i,
575 i - start + 1, metrics);
576 c->position = start;
577 c->run = r;
579 *cluster += 1;
580 return;
585 #define SCALE_FONT_METRIC(metric, emSize, metrics) ((FLOAT)(metric) * (emSize) / (FLOAT)(metrics)->designUnitsPerEm)
587 static void layout_get_font_metrics(const struct dwrite_textlayout *layout, IDWriteFontFace *fontface, float emsize,
588 DWRITE_FONT_METRICS *fontmetrics)
590 if (is_layout_gdi_compatible(layout)) {
591 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(fontface, emsize, layout->ppdip, &layout->transform, fontmetrics);
592 if (FAILED(hr))
593 WARN("failed to get compat metrics, 0x%08lx\n", hr);
595 else
596 IDWriteFontFace_GetMetrics(fontface, fontmetrics);
599 static inline void layout_get_font_height(float emsize, const DWRITE_FONT_METRICS *fontmetrics, float *baseline, float *height)
601 *baseline = SCALE_FONT_METRIC(fontmetrics->ascent + fontmetrics->lineGap, emsize, fontmetrics);
602 *height = SCALE_FONT_METRIC(fontmetrics->ascent + fontmetrics->descent + fontmetrics->lineGap, emsize, fontmetrics);
605 static inline void layout_initialize_text_source(struct dwrite_textlayout *layout, unsigned int offset,
606 unsigned int length)
608 layout->text_source.offset = offset;
609 layout->text_source.length = length;
612 static HRESULT layout_itemize(struct dwrite_textlayout *layout)
614 IDWriteTextAnalyzer2 *analyzer;
615 struct layout_range *range;
616 struct layout_run *r;
617 HRESULT hr = S_OK;
619 analyzer = get_text_analyzer();
621 layout_initialize_text_source(layout, 0, layout->len);
622 LIST_FOR_EACH_ENTRY(range, &layout->ranges, struct layout_range, h.entry) {
623 /* We don't care about ranges that don't contain any text. */
624 if (range->h.range.startPosition >= layout->len)
625 break;
627 /* Inline objects override actual text in range. */
628 if (range->object) {
629 hr = layout_update_breakpoints_range(layout, range);
630 if (FAILED(hr))
631 return hr;
633 if (FAILED(hr = alloc_layout_run(LAYOUT_RUN_INLINE, range->h.range.startPosition, &r)))
634 return hr;
636 r->u.object.object = range->object;
637 r->u.object.length = get_clipped_range_length(layout, range);
638 list_add_tail(&layout->runs, &r->entry);
639 continue;
642 /* Initial splitting by script. */
643 hr = IDWriteTextAnalyzer2_AnalyzeScript(analyzer, (IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
644 range->h.range.startPosition, get_clipped_range_length(layout, range),
645 (IDWriteTextAnalysisSink *)&layout->IDWriteTextAnalysisSink1_iface);
646 if (FAILED(hr))
647 break;
649 /* Splitting further by bidi levels. */
650 hr = IDWriteTextAnalyzer2_AnalyzeBidi(analyzer, (IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
651 range->h.range.startPosition, get_clipped_range_length(layout, range),
652 (IDWriteTextAnalysisSink *)&layout->IDWriteTextAnalysisSink1_iface);
653 if (FAILED(hr))
654 break;
657 return hr;
660 static HRESULT layout_map_run_characters(struct dwrite_textlayout *layout, struct layout_run *r,
661 IDWriteFontFallback *fallback, struct layout_run **remaining)
663 struct regular_layout_run *run = &r->u.regular;
664 IDWriteFontCollection *collection;
665 struct layout_range *range;
666 unsigned int length;
667 HRESULT hr = S_OK;
669 *remaining = NULL;
671 range = get_layout_range_by_pos(layout, run->descr.textPosition);
672 collection = range->collection ? range->collection : layout->system_collection;
674 length = run->descr.stringLength;
676 while (length)
678 unsigned int mapped_length = 0;
679 IDWriteFont *font = NULL;
680 float scale = 0.0f;
682 run = &r->u.regular;
684 layout_initialize_text_source(layout, run->descr.textPosition, run->descr.stringLength);
685 hr = IDWriteFontFallback_MapCharacters(fallback, (IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
686 0, run->descr.stringLength, collection, range->fontfamily, range->weight, range->style, range->stretch,
687 &mapped_length, &font, &scale);
688 if (FAILED(hr))
690 WARN("%s: failed to map family %s, collection %p, hr %#lx.\n", debugstr_rundescr(&run->descr),
691 debugstr_w(range->fontfamily), collection, hr);
692 return hr;
695 if (!font)
697 *remaining = r;
698 return S_OK;
701 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
702 IDWriteFont_Release(font);
703 if (FAILED(hr))
705 WARN("Failed to create a font face, hr %#lx.\n", hr);
706 return hr;
709 run->run.fontEmSize = range->fontsize * scale;
711 if (mapped_length < length)
713 struct regular_layout_run *nextrun;
714 struct layout_run *nextr;
716 /* Keep mapped part for current run, add another run for the rest. */
717 if (FAILED(hr = alloc_layout_run(LAYOUT_RUN_REGULAR, 0, &nextr)))
718 return hr;
720 *nextr = *r;
721 nextr->start_position = run->descr.textPosition + mapped_length;
722 nextrun = &nextr->u.regular;
723 nextrun->run.fontFace = NULL;
724 nextrun->descr.textPosition = nextr->start_position;
725 nextrun->descr.stringLength = run->descr.stringLength - mapped_length;
726 nextrun->descr.string = &layout->str[nextrun->descr.textPosition];
727 run->descr.stringLength = mapped_length;
728 list_add_after(&r->entry, &nextr->entry);
729 r = nextr;
732 length -= min(length, mapped_length);
735 return hr;
738 static HRESULT layout_run_get_last_resort_font(const struct dwrite_textlayout *layout, const struct layout_range *range,
739 IDWriteFontFace **fontface, float *size)
741 IDWriteFont *font;
742 HRESULT hr;
744 if (FAILED(create_matching_font(range->collection, range->fontfamily, range->weight, range->style,
745 range->stretch, &IID_IDWriteFont3, (void **)&font)))
747 if (FAILED(hr = create_matching_font(layout->system_collection, L"Tahoma", range->weight, range->style,
748 range->stretch, &IID_IDWriteFont3, (void **)&font)))
750 WARN("Failed to create last resort font, hr %#lx.\n", hr);
751 return hr;
755 hr = IDWriteFont_CreateFontFace(font, fontface);
756 IDWriteFont_Release(font);
757 if (FAILED(hr))
759 WARN("Failed to create last resort font face, hr %#lx.\n", hr);
760 return hr;
763 *size = range->fontsize;
765 return hr;
768 static HRESULT layout_resolve_fonts(struct dwrite_textlayout *layout)
770 IDWriteFontFallback *system_fallback;
771 struct layout_run *r, *remaining;
772 HRESULT hr;
774 if (FAILED(hr = IDWriteFactory7_GetSystemFontFallback(layout->factory, &system_fallback)))
776 WARN("Failed to get system fallback, hr %#lx.\n", hr);
777 return hr;
780 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry)
782 struct regular_layout_run *run = &r->u.regular;
784 if (r->kind == LAYOUT_RUN_INLINE)
785 continue;
787 /* For textual runs use both custom and system fallback. For non-visual ones only use the system fallback,
788 and no hard-coded names in assumption that support for missing control characters could be easily
789 added to bundled fonts. */
791 if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL)
793 if (FAILED(hr = layout_map_run_characters(layout, r, system_fallback, &remaining)))
795 WARN("Failed to map fonts for non-visual run, hr %#lx.\n", hr);
796 break;
799 else
801 if (layout->format.fallback)
802 hr = layout_map_run_characters(layout, r, layout->format.fallback, &remaining);
803 else
804 remaining = r;
806 if (remaining)
807 hr = layout_map_run_characters(layout, remaining, system_fallback, &remaining);
810 if (remaining)
812 hr = layout_run_get_last_resort_font(layout, get_layout_range_by_pos(layout, remaining->u.regular.descr.textPosition),
813 &remaining->u.regular.run.fontFace, &remaining->u.regular.run.fontEmSize);
816 if (FAILED(hr)) break;
819 IDWriteFontFallback_Release(system_fallback);
821 return hr;
824 struct shaping_context
826 IDWriteTextAnalyzer2 *analyzer;
827 struct regular_layout_run *run;
828 DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props;
829 DWRITE_SHAPING_TEXT_PROPERTIES *text_props;
831 struct
833 DWRITE_TYPOGRAPHIC_FEATURES **features;
834 unsigned int *range_lengths;
835 unsigned int range_count;
836 } user_features;
839 static void layout_shape_clear_user_features_context(struct shaping_context *context)
841 unsigned int i;
843 for (i = 0; i < context->user_features.range_count; ++i)
845 free(context->user_features.features[i]->features);
846 free(context->user_features.features[i]);
848 free(context->user_features.features);
849 memset(&context->user_features, 0, sizeof(context->user_features));
852 static void layout_shape_clear_context(struct shaping_context *context)
854 layout_shape_clear_user_features_context(context);
855 free(context->glyph_props);
856 free(context->text_props);
859 static HRESULT layout_shape_add_empty_user_features_range(struct shaping_context *context, unsigned int length)
861 DWRITE_TYPOGRAPHIC_FEATURES *features;
862 unsigned int r = context->user_features.range_count;
864 if (!(context->user_features.features[r] = calloc(1, sizeof(*features))))
865 return E_OUTOFMEMORY;
867 context->user_features.range_lengths[r] = length;
868 context->user_features.range_count++;
870 return S_OK;
873 static HRESULT layout_shape_get_user_features(const struct dwrite_textlayout *layout, struct shaping_context *context)
875 unsigned int i, f, start = 0, r, covered_length = 0, length, feature_count;
876 struct regular_layout_run *run = context->run;
877 DWRITE_TYPOGRAPHIC_FEATURES *features;
878 struct layout_range_iface *range;
879 IDWriteTypography *typography;
880 HRESULT hr = E_OUTOFMEMORY;
882 range = (struct layout_range_iface *)get_layout_range_header_by_pos(&layout->typographies, 0);
883 if (range->h.range.length >= run->descr.stringLength && !range->iface)
884 return S_OK;
886 if (!(context->user_features.features = calloc(run->descr.stringLength, sizeof(*context->user_features.features))))
887 goto failed;
888 if (!(context->user_features.range_lengths = calloc(run->descr.stringLength, sizeof(*context->user_features.range_lengths))))
889 goto failed;
891 for (i = run->descr.textPosition; i < run->descr.textPosition + run->descr.stringLength; ++i)
893 range = (struct layout_range_iface *)get_layout_range_header_by_pos(&layout->typographies, i);
894 if (!range || !range->iface) continue;
896 typography = (IDWriteTypography *)range->iface;
897 feature_count = IDWriteTypography_GetFontFeatureCount(typography);
898 if (!feature_count)
900 i = range->h.range.length - i + 1;
901 continue;
904 if (start != i)
906 if (FAILED(hr = layout_shape_add_empty_user_features_range(context, i - start))) goto failed;
907 covered_length += i - start;
908 start += range->h.range.length;
911 r = context->user_features.range_count;
912 if (!(features = context->user_features.features[r] = malloc(sizeof(*features))))
913 goto failed;
915 context->user_features.range_lengths[r] = length = min(run->descr.textPosition + run->descr.stringLength,
916 range->h.range.startPosition + range->h.range.length) - i;
917 features->featureCount = feature_count;
918 if (!(features->features = calloc(feature_count, sizeof(*features->features))))
919 goto failed;
921 for (f = 0; f < feature_count; ++f)
923 IDWriteTypography_GetFontFeature(typography, f, &features->features[f]);
926 i += length;
927 covered_length += length;
928 context->user_features.range_count++;
931 if (context->user_features.range_count && covered_length < run->descr.stringLength)
933 if (FAILED(hr = layout_shape_add_empty_user_features_range(context, run->descr.stringLength - covered_length)))
934 goto failed;
937 hr = S_OK;
939 failed:
941 if (!context->user_features.range_count || FAILED(hr))
942 layout_shape_clear_user_features_context(context);
944 return hr;
947 static HRESULT layout_shape_get_glyphs(struct dwrite_textlayout *layout, struct shaping_context *context)
949 struct regular_layout_run *run = context->run;
950 unsigned int max_count;
951 HRESULT hr;
953 run->descr.localeName = get_layout_range_by_pos(layout, run->descr.textPosition)->locale;
954 run->clustermap = calloc(run->descr.stringLength, sizeof(*run->clustermap));
955 if (!run->clustermap)
956 return E_OUTOFMEMORY;
958 max_count = 3 * run->descr.stringLength / 2 + 16;
959 run->glyphs = calloc(max_count, sizeof(*run->glyphs));
960 if (!run->glyphs)
961 return E_OUTOFMEMORY;
963 context->text_props = calloc(run->descr.stringLength, sizeof(*context->text_props));
964 context->glyph_props = calloc(max_count, sizeof(*context->glyph_props));
965 if (!context->text_props || !context->glyph_props)
966 return E_OUTOFMEMORY;
968 if (FAILED(hr = layout_shape_get_user_features(layout, context)))
969 return hr;
971 for (;;)
973 hr = IDWriteTextAnalyzer2_GetGlyphs(context->analyzer, run->descr.string, run->descr.stringLength, run->run.fontFace,
974 run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL /* FIXME */,
975 (const DWRITE_TYPOGRAPHIC_FEATURES **)context->user_features.features, context->user_features.range_lengths,
976 context->user_features.range_count, max_count, run->clustermap, context->text_props, run->glyphs,
977 context->glyph_props, &run->glyphcount);
978 if (hr == E_NOT_SUFFICIENT_BUFFER)
980 free(run->glyphs);
981 free(context->glyph_props);
983 max_count *= 2;
985 run->glyphs = calloc(max_count, sizeof(*run->glyphs));
986 context->glyph_props = calloc(max_count, sizeof(*context->glyph_props));
987 if (!run->glyphs || !context->glyph_props)
989 hr = E_OUTOFMEMORY;
990 break;
993 continue;
996 break;
999 if (FAILED(hr))
1000 WARN("%s: shaping failed, hr %#lx.\n", debugstr_rundescr(&run->descr), hr);
1002 run->run.glyphIndices = run->glyphs;
1003 run->descr.clusterMap = run->clustermap;
1005 return hr;
1008 static struct layout_range_spacing *layout_get_next_spacing_range(const struct dwrite_textlayout *layout,
1009 const struct layout_range_spacing *cur)
1011 return (struct layout_range_spacing *)LIST_ENTRY(list_next(&layout->spacing, &cur->h.entry),
1012 struct layout_range_header, entry);
1015 static HRESULT layout_shape_apply_character_spacing(struct dwrite_textlayout *layout, struct shaping_context *context)
1017 struct regular_layout_run *run = context->run;
1018 struct layout_range_spacing *first = NULL, *last = NULL, *cur;
1019 unsigned int i, length, pos, start, end, g0, glyph_count;
1020 struct layout_range_header *h;
1021 UINT16 *clustermap;
1023 LIST_FOR_EACH_ENTRY(h, &layout->spacing, struct layout_range_header, entry)
1025 if ((h->range.startPosition >= run->descr.textPosition &&
1026 h->range.startPosition <= run->descr.textPosition + run->descr.stringLength) ||
1027 (run->descr.textPosition >= h->range.startPosition &&
1028 run->descr.textPosition <= h->range.startPosition + h->range.length))
1030 if (!first) first = last = (struct layout_range_spacing *)h;
1032 else if (last) break;
1034 if (!first) return S_OK;
1036 if (!(clustermap = calloc(run->descr.stringLength, sizeof(*clustermap))))
1037 return E_OUTOFMEMORY;
1039 pos = run->descr.textPosition;
1041 for (cur = first;; cur = layout_get_next_spacing_range(layout, cur))
1043 float leading, trailing;
1045 /* The range current spacing settings apply to. */
1046 start = max(pos, cur->h.range.startPosition);
1047 pos = end = min(pos + run->descr.stringLength, cur->h.range.startPosition + cur->h.range.length);
1049 /* Back to run-relative index. */
1050 start -= run->descr.textPosition;
1051 end -= run->descr.textPosition;
1053 length = end - start;
1055 g0 = run->descr.clusterMap[start];
1057 for (i = 0; i < length; ++i)
1058 clustermap[i] = run->descr.clusterMap[start + i] - run->descr.clusterMap[start];
1060 glyph_count = (end < run->descr.stringLength ? run->descr.clusterMap[end] + 1 : run->glyphcount) - g0;
1062 /* There is no direction argument for spacing interface, we have to swap arguments here to get desired output. */
1063 if (run->run.bidiLevel & 1)
1065 leading = cur->trailing;
1066 trailing = cur->leading;
1068 else
1070 leading = cur->leading;
1071 trailing = cur->trailing;
1073 IDWriteTextAnalyzer2_ApplyCharacterSpacing(context->analyzer, leading, trailing, cur->min_advance,
1074 length, glyph_count, clustermap, &run->advances[g0], &run->offsets[g0], &context->glyph_props[g0],
1075 &run->advances[g0], &run->offsets[g0]);
1077 if (cur == last) break;
1080 free(clustermap);
1082 return S_OK;
1085 static HRESULT layout_shape_get_positions(struct dwrite_textlayout *layout, struct shaping_context *context)
1087 struct regular_layout_run *run = context->run;
1088 HRESULT hr;
1090 run->advances = calloc(run->glyphcount, sizeof(*run->advances));
1091 run->offsets = calloc(run->glyphcount, sizeof(*run->offsets));
1092 if (!run->advances || !run->offsets)
1093 return E_OUTOFMEMORY;
1095 /* Get advances and offsets. */
1096 if (is_layout_gdi_compatible(layout))
1097 hr = IDWriteTextAnalyzer2_GetGdiCompatibleGlyphPlacements(context->analyzer, run->descr.string, run->descr.clusterMap,
1098 context->text_props, run->descr.stringLength, run->run.glyphIndices, context->glyph_props, run->glyphcount,
1099 run->run.fontFace, run->run.fontEmSize, layout->ppdip, &layout->transform,
1100 layout->measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->run.isSideways, run->run.bidiLevel & 1,
1101 &run->sa, run->descr.localeName, (const DWRITE_TYPOGRAPHIC_FEATURES **)context->user_features.features,
1102 context->user_features.range_lengths, context->user_features.range_count, run->advances, run->offsets);
1103 else
1104 hr = IDWriteTextAnalyzer2_GetGlyphPlacements(context->analyzer, run->descr.string, run->descr.clusterMap,
1105 context->text_props, run->descr.stringLength, run->run.glyphIndices, context->glyph_props, run->glyphcount,
1106 run->run.fontFace, run->run.fontEmSize, run->run.isSideways, run->run.bidiLevel & 1, &run->sa,
1107 run->descr.localeName, (const DWRITE_TYPOGRAPHIC_FEATURES **)context->user_features.features,
1108 context->user_features.range_lengths, context->user_features.range_count, run->advances, run->offsets);
1110 if (FAILED(hr))
1112 memset(run->advances, 0, run->glyphcount * sizeof(*run->advances));
1113 memset(run->offsets, 0, run->glyphcount * sizeof(*run->offsets));
1114 WARN("%s: failed to get glyph placement info, hr %#lx.\n", debugstr_rundescr(&run->descr), hr);
1117 if (SUCCEEDED(hr))
1118 hr = layout_shape_apply_character_spacing(layout, context);
1120 run->run.glyphAdvances = run->advances;
1121 run->run.glyphOffsets = run->offsets;
1123 return hr;
1126 static HRESULT layout_shape_run(struct dwrite_textlayout *layout, struct regular_layout_run *run)
1128 struct shaping_context context = { 0 };
1129 HRESULT hr;
1131 context.analyzer = get_text_analyzer();
1132 context.run = run;
1134 if (SUCCEEDED(hr = layout_shape_get_glyphs(layout, &context)))
1135 hr = layout_shape_get_positions(layout, &context);
1137 layout_shape_clear_context(&context);
1139 /* Special treatment for runs that don't produce visual output, shaping code adds normal glyphs for them,
1140 with valid cluster map and potentially with non-zero advances; layout code exposes those as zero
1141 width clusters. */
1142 if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL)
1143 run->run.glyphCount = 0;
1144 else
1145 run->run.glyphCount = run->glyphcount;
1147 return hr;
1150 static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
1152 struct layout_run *r;
1153 UINT32 cluster = 0;
1154 HRESULT hr;
1156 free_layout_eruns(layout);
1157 free_layout_runs(layout);
1159 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
1160 if (!layout->clustermetrics && layout->len)
1162 layout->clustermetrics = calloc(layout->len, sizeof(*layout->clustermetrics));
1163 layout->clusters = calloc(layout->len, sizeof(*layout->clusters));
1164 if (!layout->clustermetrics || !layout->clusters)
1166 free(layout->clustermetrics);
1167 free(layout->clusters);
1168 return E_OUTOFMEMORY;
1171 layout->cluster_count = 0;
1173 if (FAILED(hr = layout_itemize(layout))) {
1174 WARN("Itemization failed, hr %#lx.\n", hr);
1175 return hr;
1178 if (FAILED(hr = layout_resolve_fonts(layout))) {
1179 WARN("Failed to resolve layout fonts, hr %#lx.\n", hr);
1180 return hr;
1183 /* fill run info */
1184 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
1185 struct regular_layout_run *run = &r->u.regular;
1186 DWRITE_FONT_METRICS fontmetrics = { 0 };
1188 /* we need to do very little in case of inline objects */
1189 if (r->kind == LAYOUT_RUN_INLINE) {
1190 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[cluster];
1191 struct layout_cluster *c = &layout->clusters[cluster];
1192 DWRITE_INLINE_OBJECT_METRICS inlinemetrics;
1194 metrics->width = 0.0f;
1195 metrics->length = r->u.object.length;
1196 metrics->canWrapLineAfter = 0;
1197 metrics->isWhitespace = 0;
1198 metrics->isNewline = 0;
1199 metrics->isSoftHyphen = 0;
1200 metrics->isRightToLeft = 0;
1201 metrics->padding = 0;
1202 c->run = r;
1203 c->position = 0; /* there's always one cluster per inline object, so 0 is valid value */
1204 cluster++;
1206 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
1207 hr = IDWriteInlineObject_GetMetrics(r->u.object.object, &inlinemetrics);
1208 if (FAILED(hr)) {
1209 memset(&inlinemetrics, 0, sizeof(inlinemetrics));
1210 hr = S_OK;
1212 metrics->width = inlinemetrics.width;
1213 r->baseline = inlinemetrics.baseline;
1214 r->height = inlinemetrics.height;
1216 /* FIXME: use resolved breakpoints in this case too */
1218 continue;
1221 if (FAILED(hr = layout_shape_run(layout, run)))
1222 WARN("%s: shaping failed, hr %#lx.\n", debugstr_rundescr(&run->descr), hr);
1224 /* baseline derived from font metrics */
1225 layout_get_font_metrics(layout, run->run.fontFace, run->run.fontEmSize, &fontmetrics);
1226 layout_get_font_height(run->run.fontEmSize, &fontmetrics, &r->baseline, &r->height);
1228 layout_set_cluster_metrics(layout, r, &cluster);
1231 if (hr == S_OK) {
1232 layout->cluster_count = cluster;
1233 if (cluster)
1234 layout->clustermetrics[cluster-1].canWrapLineAfter = 1;
1237 return hr;
1240 static HRESULT layout_compute(struct dwrite_textlayout *layout)
1242 HRESULT hr;
1244 if (!(layout->recompute & RECOMPUTE_CLUSTERS))
1245 return S_OK;
1247 /* nominal breakpoints are evaluated only once, because string never changes */
1248 if (!layout->nominal_breakpoints)
1250 IDWriteTextAnalyzer2 *analyzer;
1252 if (!(layout->nominal_breakpoints = calloc(layout->len, sizeof(*layout->nominal_breakpoints))))
1253 return E_OUTOFMEMORY;
1255 analyzer = get_text_analyzer();
1257 layout_initialize_text_source(layout, 0, layout->len);
1258 if (FAILED(hr = IDWriteTextAnalyzer2_AnalyzeLineBreakpoints(analyzer,
1259 (IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
1260 0, layout->len, (IDWriteTextAnalysisSink *)&layout->IDWriteTextAnalysisSink1_iface)))
1261 WARN("Line breakpoints analysis failed, hr %#lx.\n", hr);
1264 free(layout->actual_breakpoints);
1265 layout->actual_breakpoints = NULL;
1267 hr = layout_compute_runs(layout);
1269 if (TRACE_ON(dwrite)) {
1270 struct layout_run *cur;
1272 LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
1273 if (cur->kind == LAYOUT_RUN_INLINE)
1274 TRACE("run inline object %p, len %u\n", cur->u.object.object, cur->u.object.length);
1275 else
1276 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur->u.regular.descr.textPosition, cur->u.regular.descr.textPosition +
1277 cur->u.regular.descr.stringLength-1, cur->u.regular.descr.stringLength, cur->u.regular.run.bidiLevel);
1281 layout->recompute &= ~RECOMPUTE_CLUSTERS;
1282 return hr;
1285 static inline float get_cluster_range_width(const struct dwrite_textlayout *layout, UINT32 start, UINT32 end)
1287 float width = 0.0f;
1288 for (; start < end; start++)
1289 width += layout->clustermetrics[start].width;
1290 return width;
1293 static inline IUnknown *layout_get_effect_from_pos(const struct dwrite_textlayout *layout, UINT32 pos)
1295 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->effects, pos);
1296 return ((struct layout_range_iface*)h)->iface;
1299 /* A set of parameters that additionally splits resulting runs. It happens after shaping and all text processing,
1300 no glyph changes are possible. It's understandable for drawing effects, because DrawGlyphRun() reports them as
1301 one of the arguments, but it also happens for decorations, so every effective run has uniform
1302 underline/strikethough/effect tuple. */
1303 struct layout_final_splitting_params {
1304 BOOL strikethrough;
1305 BOOL underline;
1306 IUnknown *effect;
1309 static inline BOOL layout_get_strikethrough_from_pos(const struct dwrite_textlayout *layout, UINT32 pos)
1311 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->strike_ranges, pos);
1312 return ((struct layout_range_bool*)h)->value;
1315 static inline BOOL layout_get_underline_from_pos(const struct dwrite_textlayout *layout, UINT32 pos)
1317 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->underline_ranges, pos);
1318 return ((struct layout_range_bool*)h)->value;
1321 static void layout_splitting_params_from_pos(const struct dwrite_textlayout *layout, UINT32 pos,
1322 struct layout_final_splitting_params *params)
1324 params->strikethrough = layout_get_strikethrough_from_pos(layout, pos);
1325 params->underline = layout_get_underline_from_pos(layout, pos);
1326 params->effect = layout_get_effect_from_pos(layout, pos);
1329 static BOOL is_same_splitting_params(const struct layout_final_splitting_params *left,
1330 const struct layout_final_splitting_params *right)
1332 return left->strikethrough == right->strikethrough &&
1333 left->underline == right->underline &&
1334 left->effect == right->effect;
1337 static void layout_get_erun_font_metrics(const struct dwrite_textlayout *layout, const struct layout_effective_run *erun,
1338 DWRITE_FONT_METRICS *metrics)
1340 memset(metrics, 0, sizeof(*metrics));
1341 if (is_layout_gdi_compatible(layout)) {
1342 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(
1343 erun->run->u.regular.run.fontFace,
1344 erun->run->u.regular.run.fontEmSize,
1345 layout->ppdip,
1346 &layout->transform,
1347 metrics);
1348 if (FAILED(hr))
1349 WARN("failed to get font metrics, 0x%08lx\n", hr);
1351 else
1352 IDWriteFontFace_GetMetrics(erun->run->u.regular.run.fontFace, metrics);
1355 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
1356 'cluster_count' indicates how many clusters to add, including first one. */
1357 static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 first_cluster,
1358 UINT32 cluster_count, UINT32 line, FLOAT origin_x, struct layout_final_splitting_params *params)
1360 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1361 UINT32 i, start, length, last_cluster;
1362 struct layout_effective_run *run;
1364 if (r->kind == LAYOUT_RUN_INLINE)
1366 struct layout_effective_inline *inlineobject;
1368 if (!(inlineobject = malloc(sizeof(*inlineobject))))
1369 return E_OUTOFMEMORY;
1371 inlineobject->object = r->u.object.object;
1372 inlineobject->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1373 inlineobject->origin.x = is_rtl ? origin_x - inlineobject->width : origin_x;
1374 inlineobject->origin.y = 0.0f; /* set after line is built */
1375 inlineobject->align_dx = 0.0f;
1376 inlineobject->baseline = r->baseline;
1378 /* It's not clear how these two are set, possibly directionality
1379 is derived from surrounding text (replaced text could have
1380 different ranges which differ in reading direction). */
1381 inlineobject->is_sideways = FALSE;
1382 inlineobject->is_rtl = FALSE;
1383 inlineobject->line = line;
1385 /* effect assigned from start position and on is used for inline objects */
1386 inlineobject->effect = layout_get_effect_from_pos(layout, layout->clusters[first_cluster].position +
1387 layout->clusters[first_cluster].run->start_position);
1389 list_add_tail(&layout->inlineobjects, &inlineobject->entry);
1390 return S_OK;
1393 if (!(run = malloc(sizeof(*run))))
1394 return E_OUTOFMEMORY;
1396 /* No need to iterate for that, use simple fact that:
1397 <last cluster position> = <first cluster position> + <sum of cluster lengths not including last one> */
1398 last_cluster = first_cluster + cluster_count - 1;
1399 length = layout->clusters[last_cluster].position - layout->clusters[first_cluster].position +
1400 layout->clustermetrics[last_cluster].length;
1402 if (!(run->clustermap = calloc(length, sizeof(*run->clustermap))))
1404 free(run);
1405 return E_OUTOFMEMORY;
1408 run->run = r;
1409 run->start = start = layout->clusters[first_cluster].position;
1410 run->length = length;
1411 run->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1412 memset(&run->bbox, 0, sizeof(run->bbox));
1414 /* Adjust by run width if direction differs. */
1415 if (is_run_rtl(run) != is_rtl)
1416 run->origin.x = origin_x + (is_rtl ? -run->width : run->width);
1417 else
1418 run->origin.x = origin_x;
1420 run->origin.y = 0.0f; /* set after line is built */
1421 run->align_dx = 0.0f;
1422 run->line = line;
1424 if (r->u.regular.run.glyphCount) {
1425 /* Trim leading and trailing clusters. */
1426 run->glyphcount = r->u.regular.run.glyphCount - r->u.regular.clustermap[start];
1427 if (start + length < r->u.regular.descr.stringLength)
1428 run->glyphcount -= r->u.regular.run.glyphCount - r->u.regular.clustermap[start + length];
1430 else
1431 run->glyphcount = 0;
1433 /* cluster map needs to be shifted */
1434 for (i = 0; i < length; i++)
1435 run->clustermap[i] = r->u.regular.clustermap[start + i] - r->u.regular.clustermap[start];
1437 run->effect = params->effect;
1438 run->underlined = params->underline;
1439 list_add_tail(&layout->eruns, &run->entry);
1441 /* Strikethrough style is guaranteed to be consistent within effective run,
1442 its width equals to run width, thickness and offset are derived from
1443 font metrics, rest of the values are from layout or run itself */
1444 if (params->strikethrough)
1446 struct layout_strikethrough *s;
1447 DWRITE_FONT_METRICS metrics;
1449 if (!(s = malloc(sizeof(*s))))
1450 return E_OUTOFMEMORY;
1452 layout_get_erun_font_metrics(layout, run, &metrics);
1453 s->s.width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1454 s->s.thickness = SCALE_FONT_METRIC(metrics.strikethroughThickness, r->u.regular.run.fontEmSize, &metrics);
1455 /* Negative offset moves it above baseline as Y coordinate grows downward. */
1456 s->s.offset = -SCALE_FONT_METRIC(metrics.strikethroughPosition, r->u.regular.run.fontEmSize, &metrics);
1457 s->s.readingDirection = layout->format.readingdir;
1458 s->s.flowDirection = layout->format.flow;
1459 s->s.localeName = r->u.regular.descr.localeName;
1460 s->s.measuringMode = layout->measuringmode;
1461 s->run = run;
1463 list_add_tail(&layout->strikethrough, &s->entry);
1466 return S_OK;
1469 static void layout_apply_line_spacing(struct dwrite_textlayout *layout, UINT32 line)
1471 switch (layout->format.spacing.method)
1473 case DWRITE_LINE_SPACING_METHOD_DEFAULT:
1474 layout->lines[line].metrics.height = layout->lines[line].height;
1475 layout->lines[line].metrics.baseline = layout->lines[line].baseline;
1476 break;
1477 case DWRITE_LINE_SPACING_METHOD_UNIFORM:
1478 layout->lines[line].metrics.height = layout->format.spacing.height;
1479 layout->lines[line].metrics.baseline = layout->format.spacing.baseline;
1480 break;
1481 case DWRITE_LINE_SPACING_METHOD_PROPORTIONAL:
1482 layout->lines[line].metrics.height = layout->lines[line].height * layout->format.spacing.height;
1483 layout->lines[line].metrics.baseline = layout->lines[line].baseline * layout->format.spacing.baseline;
1484 break;
1485 default:
1486 ERR("Unknown spacing method %u\n", layout->format.spacing.method);
1490 static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_LINE_METRICS1 *metrics)
1492 size_t i = layout->metrics.lineCount;
1494 if (!dwrite_array_reserve((void **)&layout->lines, &layout->lines_size, layout->metrics.lineCount + 1,
1495 sizeof(*layout->lines)))
1497 return E_OUTOFMEMORY;
1500 layout->lines[i].metrics = *metrics;
1501 layout->lines[i].height = metrics->height;
1502 layout->lines[i].baseline = metrics->baseline;
1504 if (layout->format.spacing.method != DWRITE_LINE_SPACING_METHOD_DEFAULT)
1505 layout_apply_line_spacing(layout, i);
1507 layout->metrics.lineCount++;
1508 return S_OK;
1511 static inline struct layout_effective_run *layout_get_next_erun(const struct dwrite_textlayout *layout,
1512 const struct layout_effective_run *cur)
1514 struct list *e;
1516 if (!cur)
1517 e = list_head(&layout->eruns);
1518 else
1519 e = list_next(&layout->eruns, &cur->entry);
1520 if (!e)
1521 return NULL;
1522 return LIST_ENTRY(e, struct layout_effective_run, entry);
1525 static inline struct layout_effective_run *layout_get_prev_erun(const struct dwrite_textlayout *layout,
1526 const struct layout_effective_run *cur)
1528 struct list *e;
1530 if (!cur)
1531 e = list_tail(&layout->eruns);
1532 else
1533 e = list_prev(&layout->eruns, &cur->entry);
1534 if (!e)
1535 return NULL;
1536 return LIST_ENTRY(e, struct layout_effective_run, entry);
1539 static inline struct layout_effective_inline *layout_get_next_inline_run(const struct dwrite_textlayout *layout,
1540 const struct layout_effective_inline *cur)
1542 struct list *e;
1544 if (!cur)
1545 e = list_head(&layout->inlineobjects);
1546 else
1547 e = list_next(&layout->inlineobjects, &cur->entry);
1548 if (!e)
1549 return NULL;
1550 return LIST_ENTRY(e, struct layout_effective_inline, entry);
1553 static float layout_get_line_width(const struct dwrite_textlayout *layout, const struct layout_effective_run *erun,
1554 const struct layout_effective_inline *inrun, UINT32 line)
1556 FLOAT width = 0.0f;
1558 while (erun && erun->line == line) {
1559 width += erun->width;
1560 erun = layout_get_next_erun(layout, erun);
1561 if (!erun)
1562 break;
1565 while (inrun && inrun->line == line) {
1566 width += inrun->width;
1567 inrun = layout_get_next_inline_run(layout, inrun);
1568 if (!inrun)
1569 break;
1572 return width;
1575 static inline BOOL should_skip_transform(const DWRITE_MATRIX *m, FLOAT *det)
1577 *det = m->m11 * m->m22 - m->m12 * m->m21;
1578 /* on certain conditions we can skip transform */
1579 return (!memcmp(m, &identity, sizeof(*m)) || fabsf(*det) <= 1e-10f);
1582 static inline void layout_apply_snapping(D2D1_POINT_2F *vec, BOOL skiptransform, FLOAT ppdip,
1583 const DWRITE_MATRIX *m, FLOAT det)
1585 if (!skiptransform) {
1586 D2D1_POINT_2F vec2;
1588 /* apply transform */
1589 vec->x *= ppdip;
1590 vec->y *= ppdip;
1592 vec2.x = m->m11 * vec->x + m->m21 * vec->y + m->dx;
1593 vec2.y = m->m12 * vec->x + m->m22 * vec->y + m->dy;
1595 /* snap */
1596 vec2.x = floorf(vec2.x + 0.5f);
1597 vec2.y = floorf(vec2.y + 0.5f);
1599 /* apply inverted transform, we don't care about X component at this point */
1600 vec->x = (m->m22 * vec2.x - m->m21 * vec2.y + m->m21 * m->dy - m->m22 * m->dx) / det;
1601 vec->x /= ppdip;
1603 vec->y = (-m->m12 * vec2.x + m->m11 * vec2.y - (m->m11 * m->dy - m->m12 * m->dx)) / det;
1604 vec->y /= ppdip;
1606 else {
1607 vec->x = floorf(vec->x * ppdip + 0.5f) / ppdip;
1608 vec->y = floorf(vec->y * ppdip + 0.5f) / ppdip;
1612 static void layout_apply_leading_alignment(struct dwrite_textlayout *layout)
1614 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1615 struct layout_effective_inline *inrun;
1616 struct layout_effective_run *erun;
1618 erun = layout_get_next_erun(layout, NULL);
1619 inrun = layout_get_next_inline_run(layout, NULL);
1621 while (erun) {
1622 erun->align_dx = 0.0f;
1623 erun = layout_get_next_erun(layout, erun);
1626 while (inrun) {
1627 inrun->align_dx = 0.0f;
1628 inrun = layout_get_next_inline_run(layout, inrun);
1631 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
1634 static void layout_apply_trailing_alignment(struct dwrite_textlayout *layout)
1636 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1637 struct layout_effective_inline *inrun;
1638 struct layout_effective_run *erun;
1639 UINT32 line;
1641 erun = layout_get_next_erun(layout, NULL);
1642 inrun = layout_get_next_inline_run(layout, NULL);
1644 for (line = 0; line < layout->metrics.lineCount; line++) {
1645 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1646 FLOAT shift = layout->metrics.layoutWidth - width;
1648 if (is_rtl)
1649 shift *= -1.0f;
1651 while (erun && erun->line == line) {
1652 erun->align_dx = shift;
1653 erun = layout_get_next_erun(layout, erun);
1656 while (inrun && inrun->line == line) {
1657 inrun->align_dx = shift;
1658 inrun = layout_get_next_inline_run(layout, inrun);
1662 layout->metrics.left = is_rtl ? 0.0f : layout->metrics.layoutWidth - layout->metrics.width;
1665 static inline float layout_get_centered_shift(const struct dwrite_textlayout *layout, BOOL skiptransform,
1666 FLOAT width, FLOAT det)
1668 if (is_layout_gdi_compatible(layout)) {
1669 D2D1_POINT_2F vec = { layout->metrics.layoutWidth - width, 0.0f};
1670 layout_apply_snapping(&vec, skiptransform, layout->ppdip, &layout->transform, det);
1671 return floorf(vec.x / 2.0f);
1673 else
1674 return (layout->metrics.layoutWidth - width) / 2.0f;
1677 static void layout_apply_centered_alignment(struct dwrite_textlayout *layout)
1679 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1680 struct layout_effective_inline *inrun;
1681 struct layout_effective_run *erun;
1682 BOOL skiptransform;
1683 UINT32 line;
1684 FLOAT det;
1686 erun = layout_get_next_erun(layout, NULL);
1687 inrun = layout_get_next_inline_run(layout, NULL);
1689 skiptransform = should_skip_transform(&layout->transform, &det);
1691 for (line = 0; line < layout->metrics.lineCount; line++) {
1692 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1693 FLOAT shift = layout_get_centered_shift(layout, skiptransform, width, det);
1695 if (is_rtl)
1696 shift *= -1.0f;
1698 while (erun && erun->line == line) {
1699 erun->align_dx = shift;
1700 erun = layout_get_next_erun(layout, erun);
1703 while (inrun && inrun->line == line) {
1704 inrun->align_dx = shift;
1705 inrun = layout_get_next_inline_run(layout, inrun);
1709 layout->metrics.left = (layout->metrics.layoutWidth - layout->metrics.width) / 2.0f;
1712 static void layout_apply_text_alignment(struct dwrite_textlayout *layout)
1714 switch (layout->format.textalignment)
1716 case DWRITE_TEXT_ALIGNMENT_LEADING:
1717 layout_apply_leading_alignment(layout);
1718 break;
1719 case DWRITE_TEXT_ALIGNMENT_TRAILING:
1720 layout_apply_trailing_alignment(layout);
1721 break;
1722 case DWRITE_TEXT_ALIGNMENT_CENTER:
1723 layout_apply_centered_alignment(layout);
1724 break;
1725 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED:
1726 FIXME("alignment %d not implemented\n", layout->format.textalignment);
1727 break;
1728 default:
1733 static void layout_apply_par_alignment(struct dwrite_textlayout *layout)
1735 struct layout_effective_inline *inrun;
1736 struct layout_effective_run *erun;
1737 FLOAT origin_y = 0.0f;
1738 UINT32 line;
1740 /* alignment mode defines origin, after that all run origins are updated
1741 the same way */
1743 switch (layout->format.paralign)
1745 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR:
1746 origin_y = 0.0f;
1747 break;
1748 case DWRITE_PARAGRAPH_ALIGNMENT_FAR:
1749 origin_y = layout->metrics.layoutHeight - layout->metrics.height;
1750 break;
1751 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER:
1752 origin_y = (layout->metrics.layoutHeight - layout->metrics.height) / 2.0f;
1753 break;
1754 default:
1758 layout->metrics.top = origin_y;
1760 erun = layout_get_next_erun(layout, NULL);
1761 inrun = layout_get_next_inline_run(layout, NULL);
1762 for (line = 0; line < layout->metrics.lineCount; line++)
1764 float pos_y = origin_y + layout->lines[line].metrics.baseline;
1766 while (erun && erun->line == line) {
1767 erun->origin.y = pos_y;
1768 erun = layout_get_next_erun(layout, erun);
1771 while (inrun && inrun->line == line) {
1772 inrun->origin.y = pos_y - inrun->baseline;
1773 inrun = layout_get_next_inline_run(layout, inrun);
1776 origin_y += layout->lines[line].metrics.height;
1780 struct layout_underline_splitting_params {
1781 const WCHAR *locale; /* points to range data, no additional allocation */
1782 IUnknown *effect; /* does not hold another reference */
1785 static void init_u_splitting_params_from_erun(const struct layout_effective_run *erun,
1786 struct layout_underline_splitting_params *params)
1788 params->locale = erun->run->u.regular.descr.localeName;
1789 params->effect = erun->effect;
1792 static BOOL is_same_u_splitting(const struct layout_underline_splitting_params *left,
1793 const struct layout_underline_splitting_params *right)
1795 return left->effect == right->effect && !wcsicmp(left->locale, right->locale);
1798 static HRESULT layout_add_underline(struct dwrite_textlayout *layout, struct layout_effective_run *first,
1799 struct layout_effective_run *last)
1801 FLOAT thickness, offset, runheight;
1802 struct layout_effective_run *cur;
1803 DWRITE_FONT_METRICS metrics;
1805 if (first == layout_get_prev_erun(layout, last)) {
1806 layout_get_erun_font_metrics(layout, first, &metrics);
1807 thickness = SCALE_FONT_METRIC(metrics.underlineThickness, first->run->u.regular.run.fontEmSize, &metrics);
1808 offset = SCALE_FONT_METRIC(metrics.underlinePosition, first->run->u.regular.run.fontEmSize, &metrics);
1809 runheight = SCALE_FONT_METRIC(metrics.capHeight, first->run->u.regular.run.fontEmSize, &metrics);
1811 else {
1812 FLOAT width = 0.0f;
1814 /* Single underline is added for consecutive underlined runs. In this case underline parameters are
1815 calculated as weighted average, where run width acts as a weight. */
1816 thickness = offset = runheight = 0.0f;
1817 cur = first;
1818 do {
1819 layout_get_erun_font_metrics(layout, cur, &metrics);
1821 thickness += SCALE_FONT_METRIC(metrics.underlineThickness, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
1822 offset += SCALE_FONT_METRIC(metrics.underlinePosition, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
1823 runheight = max(SCALE_FONT_METRIC(metrics.capHeight, cur->run->u.regular.run.fontEmSize, &metrics), runheight);
1824 width += cur->width;
1826 cur = layout_get_next_erun(layout, cur);
1827 } while (cur != last);
1829 thickness /= width;
1830 offset /= width;
1833 cur = first;
1834 do {
1835 struct layout_underline_splitting_params params, prev_params;
1836 struct layout_effective_run *next, *w;
1837 struct layout_underline *u;
1839 init_u_splitting_params_from_erun(cur, &prev_params);
1840 while ((next = layout_get_next_erun(layout, cur)) != last) {
1841 init_u_splitting_params_from_erun(next, &params);
1842 if (!is_same_u_splitting(&prev_params, &params))
1843 break;
1844 cur = next;
1847 if (!(u = malloc(sizeof(*u))))
1848 return E_OUTOFMEMORY;
1850 w = cur;
1851 u->u.width = 0.0f;
1852 while (w != next) {
1853 u->u.width += w->width;
1854 w = layout_get_next_erun(layout, w);
1857 u->u.thickness = thickness;
1858 /* Font metrics convention is to have it negative when below baseline, for rendering
1859 however Y grows from baseline down for horizontal baseline. */
1860 u->u.offset = -offset;
1861 u->u.runHeight = runheight;
1862 u->u.readingDirection = is_run_rtl(cur) ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
1863 DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
1864 u->u.flowDirection = layout->format.flow;
1865 u->u.localeName = cur->run->u.regular.descr.localeName;
1866 u->u.measuringMode = layout->measuringmode;
1867 u->run = cur;
1868 list_add_tail(&layout->underlines, &u->entry);
1870 cur = next;
1871 } while (cur != last);
1873 return S_OK;
1876 static inline struct regular_layout_run * layout_get_last_run(const struct dwrite_textlayout *layout)
1878 struct layout_run *r;
1879 struct list *e;
1881 if (!(e = list_tail(&layout->runs))) return NULL;
1882 r = LIST_ENTRY(e, struct layout_run, entry);
1883 if (r->kind != LAYOUT_RUN_REGULAR) return NULL;
1884 return &r->u.regular;
1887 /* Adds a dummy line if:
1888 - there's no text, metrics come from first range in this case;
1889 - last ended with a mandatory break, metrics come from last text position.
1891 static HRESULT layout_set_dummy_line_metrics(struct dwrite_textlayout *layout)
1893 DWRITE_LINE_METRICS1 metrics = { 0 };
1894 DWRITE_FONT_METRICS fontmetrics;
1895 struct regular_layout_run *run;
1896 IDWriteFontFace *fontface;
1897 float size;
1898 HRESULT hr;
1900 if (layout->cluster_count && !layout->clustermetrics[layout->cluster_count - 1].isNewline)
1901 return S_OK;
1903 if (!layout->cluster_count)
1905 if (FAILED(hr = layout_run_get_last_resort_font(layout, get_layout_range_by_pos(layout, 0), &fontface, &size)))
1906 return hr;
1908 else if (!(run = layout_get_last_run(layout)))
1910 return S_OK;
1912 else
1914 fontface = run->run.fontFace;
1915 IDWriteFontFace_AddRef(fontface);
1916 size = run->run.fontEmSize;
1919 layout_get_font_metrics(layout, fontface, size, &fontmetrics);
1920 layout_get_font_height(size, &fontmetrics, &metrics.baseline, &metrics.height);
1921 IDWriteFontFace_Release(fontface);
1923 return layout_set_line_metrics(layout, &metrics);
1926 static void layout_add_line(struct dwrite_textlayout *layout, UINT32 first_cluster, UINT32 last_cluster,
1927 UINT32 *textpos)
1929 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1930 struct layout_final_splitting_params params, prev_params;
1931 DWRITE_INLINE_OBJECT_METRICS sign_metrics = { 0 };
1932 UINT32 line = layout->metrics.lineCount, i;
1933 DWRITE_LINE_METRICS1 metrics = { 0 };
1934 UINT32 index, start, pos = *textpos;
1935 FLOAT descent, trailingspacewidth;
1936 BOOL append_trimming_run = FALSE;
1937 const struct layout_run *run;
1938 float width = 0.0f, origin_x;
1939 HRESULT hr;
1941 /* Take a look at clusters we got for this line in reverse order to set trailing properties for current line */
1942 for (index = last_cluster, trailingspacewidth = 0.0f; index >= first_cluster; index--) {
1943 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1944 struct layout_cluster *lc = &layout->clusters[index];
1945 WCHAR ch;
1947 /* This also filters out clusters added from inline objects, those are never
1948 treated as a white space. */
1949 if (!cluster->isWhitespace)
1950 break;
1952 /* Every isNewline cluster is also isWhitespace, but not every
1953 newline character cluster has isNewline set, so go back to original string. */
1954 ch = lc->run->u.regular.descr.string[lc->position];
1955 if (cluster->length == 1 && lb_is_newline_char(ch))
1956 metrics.newlineLength += cluster->length;
1958 metrics.trailingWhitespaceLength += cluster->length;
1959 trailingspacewidth += cluster->width;
1961 if (index == 0)
1962 break;
1965 /* Line metrics length includes trailing whitespace length too */
1966 for (i = first_cluster; i <= last_cluster; i++)
1967 metrics.length += layout->clustermetrics[i].length;
1969 /* Ignore trailing whitespaces */
1970 while (last_cluster > first_cluster) {
1971 if (!layout->clustermetrics[last_cluster].isWhitespace)
1972 break;
1974 last_cluster--;
1977 /* Does not include trailing space width */
1978 if (!layout->clustermetrics[last_cluster].isWhitespace)
1979 width = get_cluster_range_width(layout, first_cluster, last_cluster + 1);
1981 /* Append trimming run if necessary */
1982 if (width > layout->metrics.layoutWidth && layout->format.trimmingsign != NULL &&
1983 layout->format.trimming.granularity != DWRITE_TRIMMING_GRANULARITY_NONE) {
1984 FLOAT trimmed_width = width;
1986 hr = IDWriteInlineObject_GetMetrics(layout->format.trimmingsign, &sign_metrics);
1987 if (SUCCEEDED(hr)) {
1988 while (last_cluster > first_cluster) {
1989 if (trimmed_width + sign_metrics.width <= layout->metrics.layoutWidth)
1990 break;
1991 if (layout->format.trimming.granularity == DWRITE_TRIMMING_GRANULARITY_CHARACTER)
1992 trimmed_width -= layout->clustermetrics[last_cluster--].width;
1993 else {
1994 while (last_cluster > first_cluster) {
1995 trimmed_width -= layout->clustermetrics[last_cluster].width;
1996 if (layout->clustermetrics[last_cluster--].canWrapLineAfter)
1997 break;
2001 append_trimming_run = TRUE;
2003 else
2004 WARN("Failed to get trimming sign metrics, lines won't be trimmed, hr %#lx.\n", hr);
2006 width = trimmed_width + sign_metrics.width;
2009 layout_splitting_params_from_pos(layout, pos, &params);
2010 prev_params = params;
2011 run = layout->clusters[first_cluster].run;
2013 /* Form runs from a range of clusters; this is what will be reported with DrawGlyphRun() */
2014 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0f;
2015 for (start = first_cluster, i = first_cluster; i <= last_cluster; i++) {
2016 layout_splitting_params_from_pos(layout, pos, &params);
2018 if (run != layout->clusters[i].run || !is_same_splitting_params(&prev_params, &params)) {
2019 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, &prev_params);
2020 if (FAILED(hr))
2021 return;
2023 origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) :
2024 get_cluster_range_width(layout, start, i);
2025 run = layout->clusters[i].run;
2026 start = i;
2029 prev_params = params;
2030 pos += layout->clustermetrics[i].length;
2033 /* Final run from what's left from cluster range */
2034 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, &prev_params);
2035 if (FAILED(hr))
2036 return;
2038 if (get_cluster_range_width(layout, start, i) + sign_metrics.width > layout->metrics.layoutWidth)
2039 append_trimming_run = FALSE;
2041 if (append_trimming_run) {
2042 struct layout_effective_inline *trimming_sign;
2044 if (!(trimming_sign = calloc(1, sizeof(*trimming_sign))))
2045 return;
2047 trimming_sign->object = layout->format.trimmingsign;
2048 trimming_sign->width = sign_metrics.width;
2049 origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) : get_cluster_range_width(layout, start, i);
2050 trimming_sign->origin.x = is_rtl ? origin_x - trimming_sign->width : origin_x;
2051 trimming_sign->origin.y = 0.0f; /* set after line is built */
2052 trimming_sign->align_dx = 0.0f;
2053 trimming_sign->baseline = sign_metrics.baseline;
2055 trimming_sign->is_sideways = FALSE;
2056 trimming_sign->is_rtl = FALSE;
2057 trimming_sign->line = line;
2059 trimming_sign->effect = layout_get_effect_from_pos(layout, layout->clusters[i].position +
2060 layout->clusters[i].run->start_position);
2062 list_add_tail(&layout->inlineobjects, &trimming_sign->entry);
2065 /* Look for max baseline and descent for this line */
2066 for (index = first_cluster, metrics.baseline = 0.0f, descent = 0.0f; index <= last_cluster; index++) {
2067 const struct layout_run *cur = layout->clusters[index].run;
2068 FLOAT cur_descent = cur->height - cur->baseline;
2070 if (cur->baseline > metrics.baseline)
2071 metrics.baseline = cur->baseline;
2072 if (cur_descent > descent)
2073 descent = cur_descent;
2076 layout->metrics.width = max(width, layout->metrics.width);
2077 layout->metrics.widthIncludingTrailingWhitespace = max(width + trailingspacewidth,
2078 layout->metrics.widthIncludingTrailingWhitespace);
2080 metrics.height = descent + metrics.baseline;
2081 metrics.isTrimmed = append_trimming_run || width > layout->metrics.layoutWidth;
2082 layout_set_line_metrics(layout, &metrics);
2084 *textpos += metrics.length;
2087 static void layout_set_line_positions(struct dwrite_textlayout *layout)
2089 struct layout_effective_inline *inrun;
2090 struct layout_effective_run *erun;
2091 FLOAT origin_y;
2092 UINT32 line;
2094 /* Now all line info is here, update effective runs positions in flow direction */
2095 erun = layout_get_next_erun(layout, NULL);
2096 inrun = layout_get_next_inline_run(layout, NULL);
2098 for (line = 0, origin_y = 0.0f; line < layout->metrics.lineCount; line++)
2100 float pos_y = origin_y + layout->lines[line].metrics.baseline;
2102 /* For all runs on this line */
2103 while (erun && erun->line == line) {
2104 erun->origin.y = pos_y;
2105 erun = layout_get_next_erun(layout, erun);
2108 /* Same for inline runs */
2109 while (inrun && inrun->line == line) {
2110 inrun->origin.y = pos_y - inrun->baseline;
2111 inrun = layout_get_next_inline_run(layout, inrun);
2114 origin_y += layout->lines[line].metrics.height;
2117 layout->metrics.height = origin_y;
2119 /* Initial paragraph alignment is always near */
2120 if (layout->format.paralign != DWRITE_PARAGRAPH_ALIGNMENT_NEAR)
2121 layout_apply_par_alignment(layout);
2124 static BOOL layout_can_wrap_after(const struct dwrite_textlayout *layout, UINT32 cluster)
2126 if (layout->format.wrapping == DWRITE_WORD_WRAPPING_CHARACTER)
2127 return TRUE;
2129 return layout->clustermetrics[cluster].canWrapLineAfter;
2132 static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
2134 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
2135 struct layout_effective_run *erun, *first_underlined;
2136 UINT32 i, start, textpos, last_breaking_point;
2137 DWRITE_LINE_METRICS1 metrics;
2138 FLOAT width;
2139 UINT32 line;
2140 HRESULT hr;
2142 if (!(layout->recompute & RECOMPUTE_LINES))
2143 return S_OK;
2145 free_layout_eruns(layout);
2147 hr = layout_compute(layout);
2148 if (FAILED(hr))
2149 return hr;
2151 layout->metrics.lineCount = 0;
2152 memset(&metrics, 0, sizeof(metrics));
2154 layout->metrics.height = 0.0f;
2155 layout->metrics.width = 0.0f;
2156 layout->metrics.widthIncludingTrailingWhitespace = 0.0f;
2158 last_breaking_point = ~0u;
2160 for (i = 0, start = 0, width = 0.0f, textpos = 0; i < layout->cluster_count; i++) {
2161 BOOL overflow = FALSE;
2163 while (i < layout->cluster_count && !layout->clustermetrics[i].isNewline) {
2164 /* Check for overflow */
2165 overflow = ((width + layout->clustermetrics[i].width > layout->metrics.layoutWidth) &&
2166 (layout->format.wrapping != DWRITE_WORD_WRAPPING_NO_WRAP));
2167 if (overflow)
2168 break;
2170 if (layout_can_wrap_after(layout, i))
2171 last_breaking_point = i;
2172 width += layout->clustermetrics[i].width;
2173 i++;
2175 i = min(i, layout->cluster_count - 1);
2177 /* Ignore if overflown on whitespace */
2178 if (overflow && !(layout->clustermetrics[i].isWhitespace && layout_can_wrap_after(layout, i))) {
2179 /* Use most recently found breaking point */
2180 if (last_breaking_point != ~0u) {
2181 i = last_breaking_point;
2182 last_breaking_point = ~0u;
2184 else {
2185 /* Otherwise proceed forward to next newline or breaking point */
2186 for (; i < layout->cluster_count; i++)
2187 if (layout_can_wrap_after(layout, i) || layout->clustermetrics[i].isNewline)
2188 break;
2191 i = min(i, layout->cluster_count - 1);
2193 layout_add_line(layout, start, i, &textpos);
2194 start = i + 1;
2195 width = 0.0f;
2198 if (FAILED(hr = layout_set_dummy_line_metrics(layout)))
2199 return hr;
2201 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
2202 layout->metrics.top = 0.0f;
2203 layout->metrics.maxBidiReorderingDepth = 1; /* FIXME */
2205 /* Add explicit underlined runs */
2206 erun = layout_get_next_erun(layout, NULL);
2207 first_underlined = erun && erun->underlined ? erun : NULL;
2208 for (line = 0; line < layout->metrics.lineCount; line++) {
2209 while (erun && erun->line == line) {
2210 erun = layout_get_next_erun(layout, erun);
2212 if (first_underlined && (!erun || !erun->underlined)) {
2213 layout_add_underline(layout, first_underlined, erun);
2214 first_underlined = NULL;
2216 else if (!first_underlined && erun && erun->underlined)
2217 first_underlined = erun;
2221 /* Position runs in flow direction */
2222 layout_set_line_positions(layout);
2224 /* Initial alignment is always leading */
2225 if (layout->format.textalignment != DWRITE_TEXT_ALIGNMENT_LEADING)
2226 layout_apply_text_alignment(layout);
2228 layout->recompute &= ~RECOMPUTE_LINES;
2229 return hr;
2232 static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum layout_range_attr_kind attr,
2233 struct layout_range_attr_value *value)
2235 struct layout_range_spacing const *range_spacing = (struct layout_range_spacing*)h;
2236 struct layout_range_iface const *range_iface = (struct layout_range_iface*)h;
2237 struct layout_range_bool const *range_bool = (struct layout_range_bool*)h;
2238 struct layout_range const *range = (struct layout_range*)h;
2240 switch (attr) {
2241 case LAYOUT_RANGE_ATTR_WEIGHT:
2242 return range->weight == value->u.weight;
2243 case LAYOUT_RANGE_ATTR_STYLE:
2244 return range->style == value->u.style;
2245 case LAYOUT_RANGE_ATTR_STRETCH:
2246 return range->stretch == value->u.stretch;
2247 case LAYOUT_RANGE_ATTR_FONTSIZE:
2248 return range->fontsize == value->u.fontsize;
2249 case LAYOUT_RANGE_ATTR_INLINE:
2250 return range->object == value->u.object;
2251 case LAYOUT_RANGE_ATTR_EFFECT:
2252 return range_iface->iface == value->u.effect;
2253 case LAYOUT_RANGE_ATTR_UNDERLINE:
2254 return range_bool->value == value->u.underline;
2255 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2256 return range_bool->value == value->u.strikethrough;
2257 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2258 return range->pair_kerning == value->u.pair_kerning;
2259 case LAYOUT_RANGE_ATTR_FONTCOLL:
2260 return range->collection == value->u.collection;
2261 case LAYOUT_RANGE_ATTR_LOCALE:
2262 return !wcsicmp(range->locale, value->u.locale);
2263 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2264 return !wcscmp(range->fontfamily, value->u.fontfamily);
2265 case LAYOUT_RANGE_ATTR_SPACING:
2266 return range_spacing->leading == value->u.spacing.leading &&
2267 range_spacing->trailing == value->u.spacing.trailing &&
2268 range_spacing->min_advance == value->u.spacing.min_advance;
2269 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2270 return range_iface->iface == (IUnknown*)value->u.typography;
2271 default:
2275 return FALSE;
2278 static inline BOOL is_same_layout_attributes(struct layout_range_header const *hleft, struct layout_range_header const *hright)
2280 switch (hleft->kind)
2282 case LAYOUT_RANGE_REGULAR:
2284 struct layout_range const *left = (struct layout_range const*)hleft;
2285 struct layout_range const *right = (struct layout_range const*)hright;
2286 return left->weight == right->weight &&
2287 left->style == right->style &&
2288 left->stretch == right->stretch &&
2289 left->fontsize == right->fontsize &&
2290 left->object == right->object &&
2291 left->pair_kerning == right->pair_kerning &&
2292 left->collection == right->collection &&
2293 !wcsicmp(left->locale, right->locale) &&
2294 !wcscmp(left->fontfamily, right->fontfamily);
2296 case LAYOUT_RANGE_UNDERLINE:
2297 case LAYOUT_RANGE_STRIKETHROUGH:
2299 struct layout_range_bool const *left = (struct layout_range_bool const*)hleft;
2300 struct layout_range_bool const *right = (struct layout_range_bool const*)hright;
2301 return left->value == right->value;
2303 case LAYOUT_RANGE_EFFECT:
2304 case LAYOUT_RANGE_TYPOGRAPHY:
2306 struct layout_range_iface const *left = (struct layout_range_iface const*)hleft;
2307 struct layout_range_iface const *right = (struct layout_range_iface const*)hright;
2308 return left->iface == right->iface;
2310 case LAYOUT_RANGE_SPACING:
2312 struct layout_range_spacing const *left = (struct layout_range_spacing const*)hleft;
2313 struct layout_range_spacing const *right = (struct layout_range_spacing const*)hright;
2314 return left->leading == right->leading &&
2315 left->trailing == right->trailing &&
2316 left->min_advance == right->min_advance;
2318 default:
2319 FIXME("unknown range kind %d\n", hleft->kind);
2320 return FALSE;
2324 static inline BOOL is_same_text_range(const DWRITE_TEXT_RANGE *left, const DWRITE_TEXT_RANGE *right)
2326 return left->startPosition == right->startPosition && left->length == right->length;
2329 /* Allocates range and inits it with default values from text format. */
2330 static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout *layout, const DWRITE_TEXT_RANGE *r,
2331 enum layout_range_kind kind)
2333 struct layout_range_header *h;
2335 switch (kind)
2337 case LAYOUT_RANGE_REGULAR:
2339 struct layout_range *range;
2341 if (!(range = calloc(1, sizeof(*range))))
2342 return NULL;
2344 range->weight = layout->format.weight;
2345 range->style = layout->format.style;
2346 range->stretch = layout->format.stretch;
2347 range->fontsize = layout->format.fontsize;
2349 range->fontfamily = wcsdup(layout->format.family_name);
2350 if (!range->fontfamily)
2352 free(range);
2353 return NULL;
2356 range->collection = layout->format.collection;
2357 if (range->collection)
2358 IDWriteFontCollection_AddRef(range->collection);
2359 wcscpy(range->locale, layout->format.locale);
2361 h = &range->h;
2362 break;
2364 case LAYOUT_RANGE_UNDERLINE:
2365 case LAYOUT_RANGE_STRIKETHROUGH:
2367 struct layout_range_bool *range;
2369 if (!(range = calloc(1, sizeof(*range))))
2370 return NULL;
2372 h = &range->h;
2373 break;
2375 case LAYOUT_RANGE_EFFECT:
2376 case LAYOUT_RANGE_TYPOGRAPHY:
2378 struct layout_range_iface *range;
2380 if (!(range = calloc(1, sizeof(*range))))
2381 return NULL;
2383 h = &range->h;
2384 break;
2386 case LAYOUT_RANGE_SPACING:
2388 struct layout_range_spacing *range;
2390 if (!(range = calloc(1, sizeof(*range))))
2391 return NULL;
2393 h = &range->h;
2394 break;
2396 default:
2397 FIXME("unknown range kind %d\n", kind);
2398 return NULL;
2401 h->kind = kind;
2402 h->range = *r;
2403 return h;
2406 static struct layout_range_header *alloc_layout_range_from(struct layout_range_header *h, const DWRITE_TEXT_RANGE *r)
2408 struct layout_range_header *ret;
2410 switch (h->kind)
2412 case LAYOUT_RANGE_REGULAR:
2414 struct layout_range *from = (struct layout_range *)h, *range;
2416 if (!(range = malloc(sizeof(*range))))
2417 return NULL;
2419 *range = *from;
2420 range->fontfamily = wcsdup(from->fontfamily);
2421 if (!range->fontfamily)
2423 free(range);
2424 return NULL;
2427 /* update refcounts */
2428 if (range->object)
2429 IDWriteInlineObject_AddRef(range->object);
2430 if (range->collection)
2431 IDWriteFontCollection_AddRef(range->collection);
2432 ret = &range->h;
2433 break;
2435 case LAYOUT_RANGE_UNDERLINE:
2436 case LAYOUT_RANGE_STRIKETHROUGH:
2438 struct layout_range_bool *strike = malloc(sizeof(*strike));
2439 if (!strike) return NULL;
2441 *strike = *(struct layout_range_bool*)h;
2442 ret = &strike->h;
2443 break;
2445 case LAYOUT_RANGE_EFFECT:
2446 case LAYOUT_RANGE_TYPOGRAPHY:
2448 struct layout_range_iface *effect = malloc(sizeof(*effect));
2449 if (!effect) return NULL;
2451 *effect = *(struct layout_range_iface*)h;
2452 if (effect->iface)
2453 IUnknown_AddRef(effect->iface);
2454 ret = &effect->h;
2455 break;
2457 case LAYOUT_RANGE_SPACING:
2459 struct layout_range_spacing *spacing = malloc(sizeof(*spacing));
2460 if (!spacing) return NULL;
2462 *spacing = *(struct layout_range_spacing*)h;
2463 ret = &spacing->h;
2464 break;
2466 default:
2467 FIXME("unknown range kind %d\n", h->kind);
2468 return NULL;
2471 ret->range = *r;
2472 return ret;
2475 static void free_layout_range(struct layout_range_header *h)
2477 if (!h)
2478 return;
2480 switch (h->kind)
2482 case LAYOUT_RANGE_REGULAR:
2484 struct layout_range *range = (struct layout_range*)h;
2486 if (range->object)
2487 IDWriteInlineObject_Release(range->object);
2488 if (range->collection)
2489 IDWriteFontCollection_Release(range->collection);
2490 free(range->fontfamily);
2491 break;
2493 case LAYOUT_RANGE_EFFECT:
2494 case LAYOUT_RANGE_TYPOGRAPHY:
2496 struct layout_range_iface *range = (struct layout_range_iface*)h;
2497 if (range->iface)
2498 IUnknown_Release(range->iface);
2499 break;
2501 default:
2505 free(h);
2508 static void free_layout_ranges_list(struct dwrite_textlayout *layout)
2510 struct layout_range_header *cur, *cur2;
2512 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->ranges, struct layout_range_header, entry) {
2513 list_remove(&cur->entry);
2514 free_layout_range(cur);
2517 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->underline_ranges, struct layout_range_header, entry) {
2518 list_remove(&cur->entry);
2519 free_layout_range(cur);
2522 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->strike_ranges, struct layout_range_header, entry) {
2523 list_remove(&cur->entry);
2524 free_layout_range(cur);
2527 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->effects, struct layout_range_header, entry) {
2528 list_remove(&cur->entry);
2529 free_layout_range(cur);
2532 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->spacing, struct layout_range_header, entry) {
2533 list_remove(&cur->entry);
2534 free_layout_range(cur);
2537 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->typographies, struct layout_range_header, entry) {
2538 list_remove(&cur->entry);
2539 free_layout_range(cur);
2543 static struct layout_range_header *find_outer_range(struct list *ranges, const DWRITE_TEXT_RANGE *range)
2545 struct layout_range_header *cur;
2547 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
2549 if (cur->range.startPosition > range->startPosition)
2550 return NULL;
2552 if ((cur->range.startPosition + cur->range.length < range->startPosition + range->length) &&
2553 (range->startPosition < cur->range.startPosition + cur->range.length))
2554 return NULL;
2555 if (cur->range.startPosition + cur->range.length >= range->startPosition + range->length)
2556 return cur;
2559 return NULL;
2562 static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
2564 if (*dest == value) return FALSE;
2566 if (*dest)
2567 IUnknown_Release(*dest);
2568 *dest = value;
2569 if (*dest)
2570 IUnknown_AddRef(*dest);
2572 return TRUE;
2575 static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2577 struct layout_range_spacing *dest_spacing = (struct layout_range_spacing*)h;
2578 struct layout_range_iface *dest_iface = (struct layout_range_iface*)h;
2579 struct layout_range_bool *dest_bool = (struct layout_range_bool*)h;
2580 struct layout_range *dest = (struct layout_range*)h;
2582 BOOL changed = FALSE;
2584 switch (attr) {
2585 case LAYOUT_RANGE_ATTR_WEIGHT:
2586 changed = dest->weight != value->u.weight;
2587 dest->weight = value->u.weight;
2588 break;
2589 case LAYOUT_RANGE_ATTR_STYLE:
2590 changed = dest->style != value->u.style;
2591 dest->style = value->u.style;
2592 break;
2593 case LAYOUT_RANGE_ATTR_STRETCH:
2594 changed = dest->stretch != value->u.stretch;
2595 dest->stretch = value->u.stretch;
2596 break;
2597 case LAYOUT_RANGE_ATTR_FONTSIZE:
2598 changed = dest->fontsize != value->u.fontsize;
2599 dest->fontsize = value->u.fontsize;
2600 break;
2601 case LAYOUT_RANGE_ATTR_INLINE:
2602 changed = set_layout_range_iface_attr((IUnknown**)&dest->object, (IUnknown*)value->u.object);
2603 break;
2604 case LAYOUT_RANGE_ATTR_EFFECT:
2605 changed = set_layout_range_iface_attr(&dest_iface->iface, value->u.effect);
2606 break;
2607 case LAYOUT_RANGE_ATTR_UNDERLINE:
2608 changed = dest_bool->value != value->u.underline;
2609 dest_bool->value = value->u.underline;
2610 break;
2611 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2612 changed = dest_bool->value != value->u.strikethrough;
2613 dest_bool->value = value->u.strikethrough;
2614 break;
2615 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2616 changed = dest->pair_kerning != value->u.pair_kerning;
2617 dest->pair_kerning = value->u.pair_kerning;
2618 break;
2619 case LAYOUT_RANGE_ATTR_FONTCOLL:
2620 changed = set_layout_range_iface_attr((IUnknown**)&dest->collection, (IUnknown*)value->u.collection);
2621 break;
2622 case LAYOUT_RANGE_ATTR_LOCALE:
2623 changed = !!wcsicmp(dest->locale, value->u.locale);
2624 if (changed)
2626 wcscpy(dest->locale, value->u.locale);
2627 wcslwr(dest->locale);
2629 break;
2630 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2631 changed = !!wcscmp(dest->fontfamily, value->u.fontfamily);
2632 if (changed)
2634 free(dest->fontfamily);
2635 dest->fontfamily = wcsdup(value->u.fontfamily);
2637 break;
2638 case LAYOUT_RANGE_ATTR_SPACING:
2639 changed = dest_spacing->leading != value->u.spacing.leading ||
2640 dest_spacing->trailing != value->u.spacing.trailing ||
2641 dest_spacing->min_advance != value->u.spacing.min_advance;
2642 dest_spacing->leading = value->u.spacing.leading;
2643 dest_spacing->trailing = value->u.spacing.trailing;
2644 dest_spacing->min_advance = value->u.spacing.min_advance;
2645 break;
2646 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2647 changed = set_layout_range_iface_attr(&dest_iface->iface, (IUnknown*)value->u.typography);
2648 break;
2649 default:
2653 return changed;
2656 static inline BOOL is_in_layout_range(const DWRITE_TEXT_RANGE *outer, const DWRITE_TEXT_RANGE *inner)
2658 return (inner->startPosition >= outer->startPosition) &&
2659 (inner->startPosition + inner->length <= outer->startPosition + outer->length);
2662 static inline HRESULT return_range(const struct layout_range_header *h, DWRITE_TEXT_RANGE *r)
2664 if (r) *r = h->range;
2665 return S_OK;
2668 /* Sets attribute value for given range, does all needed splitting/merging of existing ranges. */
2669 static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2671 struct layout_range_header *cur, *right, *left, *outer;
2672 BOOL changed = FALSE;
2673 struct list *ranges;
2674 DWRITE_TEXT_RANGE r;
2676 /* ignore zero length ranges */
2677 if (value->range.length == 0)
2678 return S_OK;
2680 if (~0u - value->range.startPosition < value->range.length)
2681 return E_INVALIDARG;
2683 /* select from ranges lists */
2684 switch (attr)
2686 case LAYOUT_RANGE_ATTR_WEIGHT:
2687 case LAYOUT_RANGE_ATTR_STYLE:
2688 case LAYOUT_RANGE_ATTR_STRETCH:
2689 case LAYOUT_RANGE_ATTR_FONTSIZE:
2690 case LAYOUT_RANGE_ATTR_INLINE:
2691 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2692 case LAYOUT_RANGE_ATTR_FONTCOLL:
2693 case LAYOUT_RANGE_ATTR_LOCALE:
2694 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2695 ranges = &layout->ranges;
2696 break;
2697 case LAYOUT_RANGE_ATTR_UNDERLINE:
2698 ranges = &layout->underline_ranges;
2699 break;
2700 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2701 ranges = &layout->strike_ranges;
2702 break;
2703 case LAYOUT_RANGE_ATTR_EFFECT:
2704 ranges = &layout->effects;
2705 break;
2706 case LAYOUT_RANGE_ATTR_SPACING:
2707 ranges = &layout->spacing;
2708 break;
2709 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2710 ranges = &layout->typographies;
2711 break;
2712 default:
2713 FIXME("unknown attr kind %d\n", attr);
2714 return E_FAIL;
2717 /* If new range is completely within existing range, split existing range in two */
2718 if ((outer = find_outer_range(ranges, &value->range))) {
2720 /* no need to add same range */
2721 if (is_same_layout_attrvalue(outer, attr, value))
2722 return S_OK;
2724 /* for matching range bounds just replace data */
2725 if (is_same_text_range(&outer->range, &value->range)) {
2726 changed = set_layout_range_attrval(outer, attr, value);
2727 goto done;
2730 /* add new range to the left */
2731 if (value->range.startPosition == outer->range.startPosition) {
2732 left = alloc_layout_range_from(outer, &value->range);
2733 if (!left) return E_OUTOFMEMORY;
2735 changed = set_layout_range_attrval(left, attr, value);
2736 list_add_before(&outer->entry, &left->entry);
2737 outer->range.startPosition += value->range.length;
2738 outer->range.length -= value->range.length;
2739 goto done;
2742 /* add new range to the right */
2743 if (value->range.startPosition + value->range.length == outer->range.startPosition + outer->range.length) {
2744 right = alloc_layout_range_from(outer, &value->range);
2745 if (!right) return E_OUTOFMEMORY;
2747 changed = set_layout_range_attrval(right, attr, value);
2748 list_add_after(&outer->entry, &right->entry);
2749 outer->range.length -= value->range.length;
2750 goto done;
2753 r.startPosition = value->range.startPosition + value->range.length;
2754 r.length = outer->range.length + outer->range.startPosition - r.startPosition;
2756 /* right part */
2757 right = alloc_layout_range_from(outer, &r);
2758 /* new range in the middle */
2759 cur = alloc_layout_range_from(outer, &value->range);
2760 if (!right || !cur) {
2761 free_layout_range(right);
2762 free_layout_range(cur);
2763 return E_OUTOFMEMORY;
2766 /* reuse container range as a left part */
2767 outer->range.length = value->range.startPosition - outer->range.startPosition;
2769 /* new part */
2770 set_layout_range_attrval(cur, attr, value);
2772 list_add_after(&outer->entry, &cur->entry);
2773 list_add_after(&cur->entry, &right->entry);
2775 layout->recompute = RECOMPUTE_EVERYTHING;
2776 return S_OK;
2779 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2780 Update all of them. */
2781 left = get_layout_range_header_by_pos(ranges, value->range.startPosition);
2782 if (left->range.startPosition == value->range.startPosition)
2783 changed = set_layout_range_attrval(left, attr, value);
2784 else /* need to split */ {
2785 r.startPosition = value->range.startPosition;
2786 r.length = left->range.length - value->range.startPosition + left->range.startPosition;
2787 left->range.length -= r.length;
2788 cur = alloc_layout_range_from(left, &r);
2789 changed = set_layout_range_attrval(cur, attr, value);
2790 list_add_after(&left->entry, &cur->entry);
2792 cur = LIST_ENTRY(list_next(ranges, &left->entry), struct layout_range_header, entry);
2794 /* for all existing ranges covered by new one update value */
2795 while (cur && is_in_layout_range(&value->range, &cur->range)) {
2796 changed |= set_layout_range_attrval(cur, attr, value);
2797 cur = LIST_ENTRY(list_next(ranges, &cur->entry), struct layout_range_header, entry);
2800 /* it's possible rightmost range intersects */
2801 if (cur && (cur->range.startPosition < value->range.startPosition + value->range.length)) {
2802 r.startPosition = cur->range.startPosition;
2803 r.length = value->range.startPosition + value->range.length - cur->range.startPosition;
2804 left = alloc_layout_range_from(cur, &r);
2805 changed |= set_layout_range_attrval(left, attr, value);
2806 cur->range.startPosition += left->range.length;
2807 cur->range.length -= left->range.length;
2808 list_add_before(&cur->entry, &left->entry);
2811 done:
2812 if (changed) {
2813 struct list *next, *i;
2815 layout->recompute = RECOMPUTE_EVERYTHING;
2816 i = list_head(ranges);
2817 while ((next = list_next(ranges, i))) {
2818 struct layout_range_header *next_range = LIST_ENTRY(next, struct layout_range_header, entry);
2820 cur = LIST_ENTRY(i, struct layout_range_header, entry);
2821 if (is_same_layout_attributes(cur, next_range)) {
2822 /* remove similar range */
2823 cur->range.length += next_range->range.length;
2824 list_remove(next);
2825 free_layout_range(next_range);
2827 else
2828 i = list_next(ranges, i);
2832 return S_OK;
2835 static inline const WCHAR *get_string_attribute_ptr(const struct layout_range *range, enum layout_range_attr_kind kind)
2837 const WCHAR *str;
2839 switch (kind) {
2840 case LAYOUT_RANGE_ATTR_LOCALE:
2841 str = range->locale;
2842 break;
2843 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2844 str = range->fontfamily;
2845 break;
2846 default:
2847 str = NULL;
2850 return str;
2853 static HRESULT get_string_attribute_length(const struct dwrite_textlayout *layout, enum layout_range_attr_kind kind,
2854 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
2856 struct layout_range *range;
2857 const WCHAR *str;
2859 range = get_layout_range_by_pos(layout, position);
2860 if (!range) {
2861 *length = 0;
2862 return S_OK;
2865 str = get_string_attribute_ptr(range, kind);
2866 *length = wcslen(str);
2867 return return_range(&range->h, r);
2870 static HRESULT get_string_attribute_value(const struct dwrite_textlayout *layout, enum layout_range_attr_kind kind,
2871 UINT32 position, WCHAR *ret, UINT32 length, DWRITE_TEXT_RANGE *r)
2873 struct layout_range *range;
2874 const WCHAR *str;
2876 if (length == 0)
2877 return E_INVALIDARG;
2879 ret[0] = 0;
2880 range = get_layout_range_by_pos(layout, position);
2881 if (!range)
2882 return E_INVALIDARG;
2884 str = get_string_attribute_ptr(range, kind);
2885 if (length < wcslen(str) + 1)
2886 return E_NOT_SUFFICIENT_BUFFER;
2888 wcscpy(ret, str);
2889 return return_range(&range->h, r);
2892 static HRESULT WINAPI dwritetextlayout_QueryInterface(IDWriteTextLayout4 *iface, REFIID riid, void **obj)
2894 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2896 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2898 *obj = NULL;
2900 if (IsEqualIID(riid, &IID_IDWriteTextLayout4) ||
2901 IsEqualIID(riid, &IID_IDWriteTextLayout3) ||
2902 IsEqualIID(riid, &IID_IDWriteTextLayout2) ||
2903 IsEqualIID(riid, &IID_IDWriteTextLayout1) ||
2904 IsEqualIID(riid, &IID_IDWriteTextLayout) ||
2905 IsEqualIID(riid, &IID_IUnknown))
2907 *obj = iface;
2909 else if (IsEqualIID(riid, &IID_IDWriteTextFormat3) ||
2910 IsEqualIID(riid, &IID_IDWriteTextFormat2) ||
2911 IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
2912 IsEqualIID(riid, &IID_IDWriteTextFormat))
2914 *obj = &layout->IDWriteTextFormat3_iface;
2917 if (*obj) {
2918 IDWriteTextLayout4_AddRef(iface);
2919 return S_OK;
2922 WARN("%s not implemented.\n", debugstr_guid(riid));
2924 return E_NOINTERFACE;
2927 static ULONG WINAPI dwritetextlayout_AddRef(IDWriteTextLayout4 *iface)
2929 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2930 ULONG refcount = InterlockedIncrement(&layout->refcount);
2932 TRACE("%p, refcount %lu.\n", iface, refcount);
2934 return refcount;
2937 static ULONG WINAPI dwritetextlayout_Release(IDWriteTextLayout4 *iface)
2939 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2940 ULONG refcount = InterlockedDecrement(&layout->refcount);
2942 TRACE("%p, refcount %lu.\n", iface, refcount);
2944 if (!refcount)
2946 IDWriteFactory7_Release(layout->factory);
2947 if (layout->system_collection)
2948 IDWriteFontCollection_Release(layout->system_collection);
2949 free_layout_ranges_list(layout);
2950 free_layout_eruns(layout);
2951 free_layout_runs(layout);
2952 release_format_data(&layout->format);
2953 free(layout->nominal_breakpoints);
2954 free(layout->actual_breakpoints);
2955 free(layout->clustermetrics);
2956 free(layout->clusters);
2957 free(layout->lines);
2958 free(layout->str);
2959 free(layout);
2962 return refcount;
2965 static HRESULT WINAPI dwritetextlayout_SetTextAlignment(IDWriteTextLayout4 *iface, DWRITE_TEXT_ALIGNMENT alignment)
2967 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2968 return IDWriteTextFormat3_SetTextAlignment(&layout->IDWriteTextFormat3_iface, alignment);
2971 static HRESULT WINAPI dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout4 *iface,
2972 DWRITE_PARAGRAPH_ALIGNMENT alignment)
2974 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2975 return IDWriteTextFormat3_SetParagraphAlignment(&layout->IDWriteTextFormat3_iface, alignment);
2978 static HRESULT WINAPI dwritetextlayout_SetWordWrapping(IDWriteTextLayout4 *iface, DWRITE_WORD_WRAPPING wrapping)
2980 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2981 return IDWriteTextFormat3_SetWordWrapping(&layout->IDWriteTextFormat3_iface, wrapping);
2984 static HRESULT WINAPI dwritetextlayout_SetReadingDirection(IDWriteTextLayout4 *iface,
2985 DWRITE_READING_DIRECTION direction)
2987 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2988 return IDWriteTextFormat3_SetReadingDirection(&layout->IDWriteTextFormat3_iface, direction);
2991 static HRESULT WINAPI dwritetextlayout_SetFlowDirection(IDWriteTextLayout4 *iface, DWRITE_FLOW_DIRECTION direction)
2993 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2994 return IDWriteTextFormat3_SetFlowDirection(&layout->IDWriteTextFormat3_iface, direction);
2997 static HRESULT WINAPI dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout4 *iface, FLOAT tabstop)
2999 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3000 return IDWriteTextFormat3_SetIncrementalTabStop(&layout->IDWriteTextFormat3_iface, tabstop);
3003 static HRESULT WINAPI dwritetextlayout_SetTrimming(IDWriteTextLayout4 *iface, DWRITE_TRIMMING const *trimming,
3004 IDWriteInlineObject *trimming_sign)
3006 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3007 return IDWriteTextFormat3_SetTrimming(&layout->IDWriteTextFormat3_iface, trimming, trimming_sign);
3010 static HRESULT WINAPI dwritetextlayout_SetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING_METHOD spacing,
3011 FLOAT line_spacing, FLOAT baseline)
3013 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3014 return IDWriteTextFormat1_SetLineSpacing((IDWriteTextFormat1 *)&layout->IDWriteTextFormat3_iface, spacing,
3015 line_spacing, baseline);
3018 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextlayout_GetTextAlignment(IDWriteTextLayout4 *iface)
3020 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3021 return IDWriteTextFormat3_GetTextAlignment(&layout->IDWriteTextFormat3_iface);
3024 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout4 *iface)
3026 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3027 return IDWriteTextFormat3_GetParagraphAlignment(&layout->IDWriteTextFormat3_iface);
3030 static DWRITE_WORD_WRAPPING WINAPI dwritetextlayout_GetWordWrapping(IDWriteTextLayout4 *iface)
3032 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3033 return IDWriteTextFormat3_GetWordWrapping(&layout->IDWriteTextFormat3_iface);
3036 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_GetReadingDirection(IDWriteTextLayout4 *iface)
3038 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3039 return IDWriteTextFormat3_GetReadingDirection(&layout->IDWriteTextFormat3_iface);
3042 static DWRITE_FLOW_DIRECTION WINAPI dwritetextlayout_GetFlowDirection(IDWriteTextLayout4 *iface)
3044 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3045 return IDWriteTextFormat3_GetFlowDirection(&layout->IDWriteTextFormat3_iface);
3048 static FLOAT WINAPI dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout4 *iface)
3050 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3051 return IDWriteTextFormat3_GetIncrementalTabStop(&layout->IDWriteTextFormat3_iface);
3054 static HRESULT WINAPI dwritetextlayout_GetTrimming(IDWriteTextLayout4 *iface, DWRITE_TRIMMING *options,
3055 IDWriteInlineObject **trimming_sign)
3057 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3058 return IDWriteTextFormat3_GetTrimming(&layout->IDWriteTextFormat3_iface, options, trimming_sign);
3061 static HRESULT WINAPI dwritetextlayout_GetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING_METHOD *method,
3062 FLOAT *spacing, FLOAT *baseline)
3064 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3065 return IDWriteTextFormat_GetLineSpacing((IDWriteTextFormat *)&layout->IDWriteTextFormat3_iface, method,
3066 spacing, baseline);
3069 static HRESULT WINAPI dwritetextlayout_GetFontCollection(IDWriteTextLayout4 *iface, IDWriteFontCollection **collection)
3071 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3072 return IDWriteTextFormat3_GetFontCollection(&layout->IDWriteTextFormat3_iface, collection);
3075 static UINT32 WINAPI dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout4 *iface)
3077 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3078 return IDWriteTextFormat3_GetFontFamilyNameLength(&layout->IDWriteTextFormat3_iface);
3081 static HRESULT WINAPI dwritetextlayout_GetFontFamilyName(IDWriteTextLayout4 *iface, WCHAR *name, UINT32 size)
3083 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3084 return IDWriteTextFormat3_GetFontFamilyName(&layout->IDWriteTextFormat3_iface, name, size);
3087 static DWRITE_FONT_WEIGHT WINAPI dwritetextlayout_GetFontWeight(IDWriteTextLayout4 *iface)
3089 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3090 return IDWriteTextFormat3_GetFontWeight(&layout->IDWriteTextFormat3_iface);
3093 static DWRITE_FONT_STYLE WINAPI dwritetextlayout_GetFontStyle(IDWriteTextLayout4 *iface)
3095 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3096 return IDWriteTextFormat3_GetFontStyle(&layout->IDWriteTextFormat3_iface);
3099 static DWRITE_FONT_STRETCH WINAPI dwritetextlayout_GetFontStretch(IDWriteTextLayout4 *iface)
3101 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3102 return IDWriteTextFormat3_GetFontStretch(&layout->IDWriteTextFormat3_iface);
3105 static FLOAT WINAPI dwritetextlayout_GetFontSize(IDWriteTextLayout4 *iface)
3107 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3108 return IDWriteTextFormat3_GetFontSize(&layout->IDWriteTextFormat3_iface);
3111 static UINT32 WINAPI dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout4 *iface)
3113 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3114 return IDWriteTextFormat3_GetLocaleNameLength(&layout->IDWriteTextFormat3_iface);
3117 static HRESULT WINAPI dwritetextlayout_GetLocaleName(IDWriteTextLayout4 *iface, WCHAR *name, UINT32 size)
3119 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3120 return IDWriteTextFormat3_GetLocaleName(&layout->IDWriteTextFormat3_iface, name, size);
3123 static HRESULT WINAPI dwritetextlayout_SetMaxWidth(IDWriteTextLayout4 *iface, FLOAT maxWidth)
3125 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3126 BOOL changed;
3128 TRACE("%p, %.8e.\n", iface, maxWidth);
3130 if (maxWidth < 0.0f)
3131 return E_INVALIDARG;
3133 changed = layout->metrics.layoutWidth != maxWidth;
3134 layout->metrics.layoutWidth = maxWidth;
3136 if (changed)
3137 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
3138 return S_OK;
3141 static HRESULT WINAPI dwritetextlayout_SetMaxHeight(IDWriteTextLayout4 *iface, FLOAT maxHeight)
3143 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3144 BOOL changed;
3146 TRACE("%p, %.8e.\n", iface, maxHeight);
3148 if (maxHeight < 0.0f)
3149 return E_INVALIDARG;
3151 changed = layout->metrics.layoutHeight != maxHeight;
3152 layout->metrics.layoutHeight = maxHeight;
3154 if (changed)
3155 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
3156 return S_OK;
3159 static HRESULT WINAPI dwritetextlayout_SetFontCollection(IDWriteTextLayout4 *iface, IDWriteFontCollection *collection,
3160 DWRITE_TEXT_RANGE range)
3162 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3163 struct layout_range_attr_value value;
3165 TRACE("%p, %p, %s.\n", iface, collection, debugstr_range(&range));
3167 value.range = range;
3168 value.u.collection = collection;
3169 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_FONTCOLL, &value);
3172 static HRESULT WINAPI dwritetextlayout_SetFontFamilyName(IDWriteTextLayout4 *iface, WCHAR const *name,
3173 DWRITE_TEXT_RANGE range)
3175 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3176 struct layout_range_attr_value value;
3178 TRACE("%p, %s, %s.\n", iface, debugstr_w(name), debugstr_range(&range));
3180 if (!name)
3181 return E_INVALIDARG;
3183 value.range = range;
3184 value.u.fontfamily = name;
3185 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_FONTFAMILY, &value);
3188 static HRESULT WINAPI dwritetextlayout_SetFontWeight(IDWriteTextLayout4 *iface, DWRITE_FONT_WEIGHT weight,
3189 DWRITE_TEXT_RANGE range)
3191 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3192 struct layout_range_attr_value value;
3194 TRACE("%p, %d, %s.\n", iface, weight, debugstr_range(&range));
3196 if ((UINT32)weight > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
3197 return E_INVALIDARG;
3199 value.range = range;
3200 value.u.weight = weight;
3201 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_WEIGHT, &value);
3204 static HRESULT WINAPI dwritetextlayout_SetFontStyle(IDWriteTextLayout4 *iface, DWRITE_FONT_STYLE style,
3205 DWRITE_TEXT_RANGE range)
3207 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3208 struct layout_range_attr_value value;
3210 TRACE("%p, %d, %s.\n", iface, style, debugstr_range(&range));
3212 if ((UINT32)style > DWRITE_FONT_STYLE_ITALIC)
3213 return E_INVALIDARG;
3215 value.range = range;
3216 value.u.style = style;
3217 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_STYLE, &value);
3220 static HRESULT WINAPI dwritetextlayout_SetFontStretch(IDWriteTextLayout4 *iface, DWRITE_FONT_STRETCH stretch,
3221 DWRITE_TEXT_RANGE range)
3223 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3224 struct layout_range_attr_value value;
3226 TRACE("%p, %d, %s.\n", iface, stretch, debugstr_range(&range));
3228 if (stretch == DWRITE_FONT_STRETCH_UNDEFINED || (UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
3229 return E_INVALIDARG;
3231 value.range = range;
3232 value.u.stretch = stretch;
3233 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_STRETCH, &value);
3236 static HRESULT WINAPI dwritetextlayout_SetFontSize(IDWriteTextLayout4 *iface, FLOAT size, DWRITE_TEXT_RANGE range)
3238 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3239 struct layout_range_attr_value value;
3241 TRACE("%p, %.8e, %s.\n", iface, size, debugstr_range(&range));
3243 if (size <= 0.0f)
3244 return E_INVALIDARG;
3246 value.range = range;
3247 value.u.fontsize = size;
3248 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_FONTSIZE, &value);
3251 static HRESULT WINAPI dwritetextlayout_SetUnderline(IDWriteTextLayout4 *iface, BOOL underline, DWRITE_TEXT_RANGE range)
3253 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3254 struct layout_range_attr_value value;
3256 TRACE("%p, %d, %s.\n", iface, underline, debugstr_range(&range));
3258 value.range = range;
3259 value.u.underline = underline;
3260 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_UNDERLINE, &value);
3263 static HRESULT WINAPI dwritetextlayout_SetStrikethrough(IDWriteTextLayout4 *iface, BOOL strikethrough,
3264 DWRITE_TEXT_RANGE range)
3266 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3267 struct layout_range_attr_value value;
3269 TRACE("%p, %d, %s.\n", iface, strikethrough, debugstr_range(&range));
3271 value.range = range;
3272 value.u.strikethrough = strikethrough;
3273 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_STRIKETHROUGH, &value);
3276 static HRESULT WINAPI dwritetextlayout_SetDrawingEffect(IDWriteTextLayout4 *iface, IUnknown* effect,
3277 DWRITE_TEXT_RANGE range)
3279 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3280 struct layout_range_attr_value value;
3282 TRACE("%p, %p, %s.\n", iface, effect, debugstr_range(&range));
3284 value.range = range;
3285 value.u.effect = effect;
3286 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_EFFECT, &value);
3289 static HRESULT WINAPI dwritetextlayout_SetInlineObject(IDWriteTextLayout4 *iface, IDWriteInlineObject *object,
3290 DWRITE_TEXT_RANGE range)
3292 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3293 struct layout_range_attr_value value;
3295 TRACE("%p, %p, %s.\n", iface, object, debugstr_range(&range));
3297 value.range = range;
3298 value.u.object = object;
3299 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_INLINE, &value);
3302 static HRESULT WINAPI dwritetextlayout_SetTypography(IDWriteTextLayout4 *iface, IDWriteTypography *typography,
3303 DWRITE_TEXT_RANGE range)
3305 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3306 struct layout_range_attr_value value;
3308 TRACE("%p, %p, %s.\n", iface, typography, debugstr_range(&range));
3310 value.range = range;
3311 value.u.typography = typography;
3312 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_TYPOGRAPHY, &value);
3315 static HRESULT WINAPI dwritetextlayout_SetLocaleName(IDWriteTextLayout4 *iface, WCHAR const* locale,
3316 DWRITE_TEXT_RANGE range)
3318 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3319 struct layout_range_attr_value value;
3321 TRACE("%p, %s, %s.\n", iface, debugstr_w(locale), debugstr_range(&range));
3323 if (!locale || wcslen(locale) > LOCALE_NAME_MAX_LENGTH-1)
3324 return E_INVALIDARG;
3326 value.range = range;
3327 value.u.locale = locale;
3328 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_LOCALE, &value);
3331 static FLOAT WINAPI dwritetextlayout_GetMaxWidth(IDWriteTextLayout4 *iface)
3333 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3335 TRACE("%p.\n", iface);
3337 return layout->metrics.layoutWidth;
3340 static FLOAT WINAPI dwritetextlayout_GetMaxHeight(IDWriteTextLayout4 *iface)
3342 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3344 TRACE("%p.\n", iface);
3346 return layout->metrics.layoutHeight;
3349 static HRESULT WINAPI dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout4 *iface, UINT32 position,
3350 IDWriteFontCollection **collection, DWRITE_TEXT_RANGE *r)
3352 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3353 struct layout_range *range;
3355 TRACE("%p, %u, %p, %p.\n", iface, position, collection, r);
3357 range = get_layout_range_by_pos(layout, position);
3358 *collection = range->collection;
3359 if (*collection)
3360 IDWriteFontCollection_AddRef(*collection);
3362 return return_range(&range->h, r);
3365 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout4 *iface,
3366 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
3368 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3370 TRACE("%p, %d, %p, %p.\n", iface, position, length, r);
3372 return get_string_attribute_length(layout, LAYOUT_RANGE_ATTR_FONTFAMILY, position, length, r);
3375 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout4 *iface,
3376 UINT32 position, WCHAR *name, UINT32 length, DWRITE_TEXT_RANGE *r)
3378 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3380 TRACE("%p, %u, %p, %u, %p.\n", iface, position, name, length, r);
3382 return get_string_attribute_value(layout, LAYOUT_RANGE_ATTR_FONTFAMILY, position, name, length, r);
3385 static HRESULT WINAPI dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout4 *iface,
3386 UINT32 position, DWRITE_FONT_WEIGHT *weight, DWRITE_TEXT_RANGE *r)
3388 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3389 struct layout_range *range;
3391 TRACE("%p, %u, %p, %p.\n", iface, position, weight, r);
3393 range = get_layout_range_by_pos(layout, position);
3394 *weight = range->weight;
3396 return return_range(&range->h, r);
3399 static HRESULT WINAPI dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout4 *iface,
3400 UINT32 position, DWRITE_FONT_STYLE *style, DWRITE_TEXT_RANGE *r)
3402 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3403 struct layout_range *range;
3405 TRACE("%p, %u, %p, %p.\n", iface, position, style, r);
3407 range = get_layout_range_by_pos(layout, position);
3408 *style = range->style;
3409 return return_range(&range->h, r);
3412 static HRESULT WINAPI dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout4 *iface,
3413 UINT32 position, DWRITE_FONT_STRETCH *stretch, DWRITE_TEXT_RANGE *r)
3415 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3416 struct layout_range *range;
3418 TRACE("%p, %u, %p, %p.\n", iface, position, stretch, r);
3420 range = get_layout_range_by_pos(layout, position);
3421 *stretch = range->stretch;
3422 return return_range(&range->h, r);
3425 static HRESULT WINAPI dwritetextlayout_layout_GetFontSize(IDWriteTextLayout4 *iface,
3426 UINT32 position, FLOAT *size, DWRITE_TEXT_RANGE *r)
3428 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3429 struct layout_range *range;
3431 TRACE("%p, %u, %p, %p.\n", iface, position, size, r);
3433 range = get_layout_range_by_pos(layout, position);
3434 *size = range->fontsize;
3435 return return_range(&range->h, r);
3438 static HRESULT WINAPI dwritetextlayout_GetUnderline(IDWriteTextLayout4 *iface,
3439 UINT32 position, BOOL *underline, DWRITE_TEXT_RANGE *r)
3441 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3442 struct layout_range_bool *range;
3444 TRACE("%p, %u, %p, %p.\n", iface, position, underline, r);
3446 range = (struct layout_range_bool *)get_layout_range_header_by_pos(&layout->underline_ranges, position);
3447 *underline = range->value;
3449 return return_range(&range->h, r);
3452 static HRESULT WINAPI dwritetextlayout_GetStrikethrough(IDWriteTextLayout4 *iface,
3453 UINT32 position, BOOL *strikethrough, DWRITE_TEXT_RANGE *r)
3455 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3456 struct layout_range_bool *range;
3458 TRACE("%p, %u, %p, %p.\n", iface, position, strikethrough, r);
3460 range = (struct layout_range_bool *)get_layout_range_header_by_pos(&layout->strike_ranges, position);
3461 *strikethrough = range->value;
3463 return return_range(&range->h, r);
3466 static HRESULT WINAPI dwritetextlayout_GetDrawingEffect(IDWriteTextLayout4 *iface,
3467 UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r)
3469 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3470 struct layout_range_iface *range;
3472 TRACE("%p, %u, %p, %p.\n", iface, position, effect, r);
3474 range = (struct layout_range_iface *)get_layout_range_header_by_pos(&layout->effects, position);
3475 *effect = range->iface;
3476 if (*effect)
3477 IUnknown_AddRef(*effect);
3479 return return_range(&range->h, r);
3482 static HRESULT WINAPI dwritetextlayout_GetInlineObject(IDWriteTextLayout4 *iface,
3483 UINT32 position, IDWriteInlineObject **object, DWRITE_TEXT_RANGE *r)
3485 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3486 struct layout_range *range;
3488 TRACE("%p, %u, %p, %p.\n", iface, position, object, r);
3490 range = get_layout_range_by_pos(layout, position);
3491 *object = range->object;
3492 if (*object)
3493 IDWriteInlineObject_AddRef(*object);
3495 return return_range(&range->h, r);
3498 static HRESULT WINAPI dwritetextlayout_GetTypography(IDWriteTextLayout4 *iface,
3499 UINT32 position, IDWriteTypography** typography, DWRITE_TEXT_RANGE *r)
3501 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3502 struct layout_range_iface *range;
3504 TRACE("%p, %u, %p, %p.\n", iface, position, typography, r);
3506 range = (struct layout_range_iface *)get_layout_range_header_by_pos(&layout->typographies, position);
3507 *typography = (IDWriteTypography *)range->iface;
3508 if (*typography)
3509 IDWriteTypography_AddRef(*typography);
3511 return return_range(&range->h, r);
3514 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout4 *iface,
3515 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
3517 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3519 TRACE("%p, %u, %p, %p.\n", iface, position, length, r);
3521 return get_string_attribute_length(layout, LAYOUT_RANGE_ATTR_LOCALE, position, length, r);
3524 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout4 *iface,
3525 UINT32 position, WCHAR *locale, UINT32 length, DWRITE_TEXT_RANGE *r)
3527 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3529 TRACE("%p, %u, %p, %u, %p.\n", iface, position, locale, length, r);
3531 return get_string_attribute_value(layout, LAYOUT_RANGE_ATTR_LOCALE, position, locale, length, r);
3534 static inline FLOAT renderer_apply_snapping(FLOAT coord, BOOL skiptransform, FLOAT ppdip, FLOAT det,
3535 const DWRITE_MATRIX *m)
3537 D2D1_POINT_2F vec, vec2;
3539 if (!skiptransform) {
3540 /* apply transform */
3541 vec.x = 0.0f;
3542 vec.y = coord * ppdip;
3544 vec2.x = m->m11 * vec.x + m->m21 * vec.y + m->dx;
3545 vec2.y = m->m12 * vec.x + m->m22 * vec.y + m->dy;
3547 /* snap */
3548 vec2.x = floorf(vec2.x + 0.5f);
3549 vec2.y = floorf(vec2.y + 0.5f);
3551 /* apply inverted transform, we don't care about X component at this point */
3552 vec.y = (-m->m12 * vec2.x + m->m11 * vec2.y - (m->m11 * m->dy - m->m12 * m->dx)) / det;
3553 vec.y /= ppdip;
3555 else
3556 vec.y = floorf(coord * ppdip + 0.5f) / ppdip;
3558 return vec.y;
3561 static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout4 *iface,
3562 void *context, IDWriteTextRenderer* renderer, FLOAT origin_x, FLOAT origin_y)
3564 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3565 BOOL disabled = FALSE, skiptransform = FALSE;
3566 struct layout_effective_inline *inlineobject;
3567 struct layout_effective_run *run;
3568 struct layout_strikethrough *s;
3569 struct layout_underline *u;
3570 FLOAT det = 0.0f, ppdip = 0.0f;
3571 DWRITE_MATRIX m = { 0 };
3572 HRESULT hr;
3574 TRACE("%p, %p, %p, %.8e, %.8e.\n", iface, context, renderer, origin_x, origin_y);
3576 hr = layout_compute_effective_runs(layout);
3577 if (FAILED(hr))
3578 return hr;
3580 hr = IDWriteTextRenderer_IsPixelSnappingDisabled(renderer, context, &disabled);
3581 if (FAILED(hr))
3582 return hr;
3584 if (!disabled) {
3585 hr = IDWriteTextRenderer_GetPixelsPerDip(renderer, context, &ppdip);
3586 if (FAILED(hr))
3587 return hr;
3589 hr = IDWriteTextRenderer_GetCurrentTransform(renderer, context, &m);
3590 if (FAILED(hr))
3591 return hr;
3593 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
3594 if (ppdip <= 0.0f ||
3595 (m.m11 * m.m22 != 0.0f && (m.m12 != 0.0f || m.m21 != 0.0f)) ||
3596 (m.m12 * m.m21 != 0.0f && (m.m11 != 0.0f || m.m22 != 0.0f)))
3597 disabled = TRUE;
3598 else
3599 skiptransform = should_skip_transform(&m, &det);
3602 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
3603 /* 1. Regular runs */
3604 LIST_FOR_EACH_ENTRY(run, &layout->eruns, struct layout_effective_run, entry)
3606 const struct regular_layout_run *regular = &run->run->u.regular;
3607 UINT32 start_glyph = regular->clustermap[run->start];
3608 DWRITE_GLYPH_RUN_DESCRIPTION descr;
3609 DWRITE_GLYPH_RUN glyph_run;
3611 /* Everything but cluster map will be reused from nominal run, as we only need
3612 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
3613 it can't be reused because it has to start with 0 index for each reported run. */
3614 glyph_run = regular->run;
3615 glyph_run.glyphCount = run->glyphcount;
3617 /* fixup glyph data arrays */
3618 glyph_run.glyphIndices += start_glyph;
3619 glyph_run.glyphAdvances += start_glyph;
3620 glyph_run.glyphOffsets += start_glyph;
3622 /* description */
3623 descr = regular->descr;
3624 descr.stringLength = run->length;
3625 descr.string += run->start;
3626 descr.clusterMap = run->clustermap;
3627 descr.textPosition += run->start;
3629 /* return value is ignored */
3630 IDWriteTextRenderer_DrawGlyphRun(renderer,
3631 context,
3632 run->origin.x + run->align_dx + origin_x,
3633 SNAP_COORD(run->origin.y + origin_y),
3634 layout->measuringmode,
3635 &glyph_run,
3636 &descr,
3637 run->effect);
3640 /* 2. Inline objects */
3641 LIST_FOR_EACH_ENTRY(inlineobject, &layout->inlineobjects, struct layout_effective_inline, entry)
3643 IDWriteTextRenderer_DrawInlineObject(renderer,
3644 context,
3645 inlineobject->origin.x + inlineobject->align_dx + origin_x,
3646 SNAP_COORD(inlineobject->origin.y + origin_y),
3647 inlineobject->object,
3648 inlineobject->is_sideways,
3649 inlineobject->is_rtl,
3650 inlineobject->effect);
3653 /* 3. Underlines */
3654 LIST_FOR_EACH_ENTRY(u, &layout->underlines, struct layout_underline, entry)
3656 IDWriteTextRenderer_DrawUnderline(renderer,
3657 context,
3658 /* horizontal underline always grows from left to right, width is always added to origin regardless of run direction */
3659 (is_run_rtl(u->run) ? u->run->origin.x - u->run->width : u->run->origin.x) + u->run->align_dx + origin_x,
3660 SNAP_COORD(u->run->origin.y + origin_y),
3661 &u->u,
3662 u->run->effect);
3665 /* 4. Strikethrough */
3666 LIST_FOR_EACH_ENTRY(s, &layout->strikethrough, struct layout_strikethrough, entry)
3668 IDWriteTextRenderer_DrawStrikethrough(renderer,
3669 context,
3670 s->run->origin.x + s->run->align_dx + origin_x,
3671 SNAP_COORD(s->run->origin.y + origin_y),
3672 &s->s,
3673 s->run->effect);
3675 #undef SNAP_COORD
3677 return S_OK;
3680 static HRESULT WINAPI dwritetextlayout_GetLineMetrics(IDWriteTextLayout4 *iface,
3681 DWRITE_LINE_METRICS *metrics, UINT32 max_count, UINT32 *count)
3683 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3684 unsigned int line_count;
3685 HRESULT hr;
3686 size_t i;
3688 TRACE("%p, %p, %u, %p.\n", iface, metrics, max_count, count);
3690 if (FAILED(hr = layout_compute_effective_runs(layout)))
3691 return hr;
3693 if (metrics)
3695 line_count = min(max_count, layout->metrics.lineCount);
3696 for (i = 0; i < line_count; ++i)
3697 memcpy(&metrics[i], &layout->lines[i].metrics, sizeof(*metrics));
3700 *count = layout->metrics.lineCount;
3701 return max_count >= layout->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3704 static HRESULT layout_update_metrics(struct dwrite_textlayout *layout)
3706 return layout_compute_effective_runs(layout);
3709 static HRESULT WINAPI dwritetextlayout_GetMetrics(IDWriteTextLayout4 *iface, DWRITE_TEXT_METRICS *metrics)
3711 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3712 HRESULT hr;
3714 TRACE("%p, %p.\n", iface, metrics);
3716 hr = layout_update_metrics(layout);
3717 if (hr == S_OK)
3718 memcpy(metrics, &layout->metrics, sizeof(*metrics));
3720 return hr;
3723 static void d2d_rect_offset(D2D1_RECT_F *rect, FLOAT x, FLOAT y)
3725 rect->left += x;
3726 rect->right += x;
3727 rect->top += y;
3728 rect->bottom += y;
3731 static BOOL d2d_rect_is_empty(const D2D1_RECT_F *rect)
3733 return ((rect->left >= rect->right) || (rect->top >= rect->bottom));
3736 static void d2d_rect_union(D2D1_RECT_F *dst, const D2D1_RECT_F *src)
3738 if (d2d_rect_is_empty(dst)) {
3739 if (d2d_rect_is_empty(src)) {
3740 dst->left = dst->right = dst->top = dst->bottom = 0.0f;
3741 return;
3743 else
3744 *dst = *src;
3746 else {
3747 if (!d2d_rect_is_empty(src)) {
3748 dst->left = min(dst->left, src->left);
3749 dst->right = max(dst->right, src->right);
3750 dst->top = min(dst->top, src->top);
3751 dst->bottom = max(dst->bottom, src->bottom);
3756 static void layout_get_erun_bbox(struct dwrite_textlayout *layout, struct layout_effective_run *run, D2D1_RECT_F *bbox)
3758 const struct regular_layout_run *regular = &run->run->u.regular;
3759 UINT32 start_glyph = regular->clustermap[run->start];
3760 D2D1_POINT_2F baseline_origin = { 0 }, *origins;
3761 DWRITE_GLYPH_RUN glyph_run;
3762 unsigned int i;
3763 HRESULT hr;
3765 if (run->bbox.top == run->bbox.bottom)
3767 struct dwrite_glyphbitmap glyph_bitmap;
3768 RECT *bbox;
3770 glyph_run = regular->run;
3771 glyph_run.glyphCount = run->glyphcount;
3772 glyph_run.glyphIndices = &regular->run.glyphIndices[start_glyph];
3773 glyph_run.glyphAdvances = &regular->run.glyphAdvances[start_glyph];
3774 glyph_run.glyphOffsets = &regular->run.glyphOffsets[start_glyph];
3776 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
3777 glyph_bitmap.simulations = IDWriteFontFace_GetSimulations(glyph_run.fontFace);
3778 glyph_bitmap.emsize = glyph_run.fontEmSize;
3780 bbox = &glyph_bitmap.bbox;
3782 if (!(origins = calloc(glyph_run.glyphCount, sizeof(*origins))))
3783 return;
3785 if (FAILED(hr = compute_glyph_origins(&glyph_run, layout->measuringmode, baseline_origin, &layout->transform, origins)))
3787 WARN("Failed to compute glyph origins, hr %#lx.\n", hr);
3788 free(origins);
3789 return;
3792 for (i = 0; i < glyph_run.glyphCount; ++i)
3794 D2D1_RECT_F glyph_bbox;
3796 glyph_bitmap.glyph = glyph_run.glyphIndices[i];
3797 dwrite_fontface_get_glyph_bbox(glyph_run.fontFace, &glyph_bitmap);
3799 glyph_bbox.left = bbox->left;
3800 glyph_bbox.top = bbox->top;
3801 glyph_bbox.right = bbox->right;
3802 glyph_bbox.bottom = bbox->bottom;
3804 d2d_rect_offset(&glyph_bbox, origins[i].x, origins[i].y);
3805 d2d_rect_union(&run->bbox, &glyph_bbox);
3808 free(origins);
3811 *bbox = run->bbox;
3812 d2d_rect_offset(bbox, run->origin.x + run->align_dx, run->origin.y);
3815 static void layout_get_inlineobj_bbox(const struct layout_effective_inline *run, D2D1_RECT_F *bbox)
3817 DWRITE_OVERHANG_METRICS overhang_metrics = { 0 };
3818 DWRITE_INLINE_OBJECT_METRICS metrics = { 0 };
3819 HRESULT hr;
3821 if (FAILED(hr = IDWriteInlineObject_GetMetrics(run->object, &metrics))) {
3822 WARN("Failed to get inline object metrics, hr %#lx.\n", hr);
3823 memset(bbox, 0, sizeof(*bbox));
3824 return;
3827 bbox->left = run->origin.x + run->align_dx;
3828 bbox->right = bbox->left + metrics.width;
3829 bbox->top = run->origin.y;
3830 bbox->bottom = bbox->top + metrics.height;
3832 IDWriteInlineObject_GetOverhangMetrics(run->object, &overhang_metrics);
3834 bbox->left -= overhang_metrics.left;
3835 bbox->right += overhang_metrics.right;
3836 bbox->top -= overhang_metrics.top;
3837 bbox->bottom += overhang_metrics.bottom;
3840 static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout4 *iface,
3841 DWRITE_OVERHANG_METRICS *overhangs)
3843 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3844 struct layout_effective_inline *inline_run;
3845 struct layout_effective_run *run;
3846 D2D1_RECT_F bbox = { 0 };
3847 HRESULT hr;
3849 TRACE("%p, %p.\n", iface, overhangs);
3851 memset(overhangs, 0, sizeof(*overhangs));
3853 if (!(layout->recompute & RECOMPUTE_OVERHANGS))
3855 *overhangs = layout->overhangs;
3856 return S_OK;
3859 hr = layout_compute_effective_runs(layout);
3860 if (FAILED(hr))
3861 return hr;
3863 LIST_FOR_EACH_ENTRY(run, &layout->eruns, struct layout_effective_run, entry)
3865 D2D1_RECT_F run_bbox;
3867 layout_get_erun_bbox(layout, run, &run_bbox);
3868 d2d_rect_union(&bbox, &run_bbox);
3871 LIST_FOR_EACH_ENTRY(inline_run, &layout->inlineobjects, struct layout_effective_inline, entry)
3873 D2D1_RECT_F object_bbox;
3875 layout_get_inlineobj_bbox(inline_run, &object_bbox);
3876 d2d_rect_union(&bbox, &object_bbox);
3879 /* Deltas from layout box. */
3880 layout->overhangs.left = -bbox.left;
3881 layout->overhangs.top = -bbox.top;
3882 layout->overhangs.right = bbox.right - layout->metrics.layoutWidth;
3883 layout->overhangs.bottom = bbox.bottom - layout->metrics.layoutHeight;
3884 layout->recompute &= ~RECOMPUTE_OVERHANGS;
3886 *overhangs = layout->overhangs;
3888 return S_OK;
3891 static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout4 *iface,
3892 DWRITE_CLUSTER_METRICS *metrics, UINT32 max_count, UINT32 *count)
3894 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3895 HRESULT hr;
3897 TRACE("%p, %p, %u, %p.\n", iface, metrics, max_count, count);
3899 hr = layout_compute(layout);
3900 if (FAILED(hr))
3901 return hr;
3903 if (metrics)
3904 memcpy(metrics, layout->clustermetrics, sizeof(DWRITE_CLUSTER_METRICS) * min(max_count, layout->cluster_count));
3906 *count = layout->cluster_count;
3907 return max_count >= layout->cluster_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3910 static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout4 *iface, FLOAT* min_width)
3912 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3913 UINT32 start;
3914 FLOAT width;
3915 HRESULT hr;
3917 TRACE("%p, %p.\n", iface, min_width);
3919 if (!min_width)
3920 return E_INVALIDARG;
3922 if (!(layout->recompute & RECOMPUTE_MINIMAL_WIDTH))
3923 goto width_done;
3925 *min_width = 0.0f;
3926 hr = layout_compute(layout);
3927 if (FAILED(hr))
3928 return hr;
3930 /* Find widest word without emergency breaking between clusters, trailing whitespaces
3931 preceding breaking point do not contribute to word width. */
3932 for (start = 0; start < layout->cluster_count;)
3934 UINT32 end = start, j, next;
3936 /* Last cluster always could be wrapped after. */
3937 while (!layout->clustermetrics[end].canWrapLineAfter)
3938 end++;
3939 /* make is so current cluster range that we can wrap after is [start,end) */
3940 end++;
3942 next = end;
3944 /* Ignore trailing whitespace clusters, in case of single space range will
3945 be reduced to empty range, or [start,start+1). */
3946 while (end > start && layout->clustermetrics[end-1].isWhitespace)
3947 end--;
3949 /* check if cluster range exceeds last minimal width */
3950 width = 0.0f;
3951 for (j = start; j < end; j++)
3952 width += layout->clustermetrics[j].width;
3954 start = next;
3956 if (width > layout->minwidth)
3957 layout->minwidth = width;
3959 layout->recompute &= ~RECOMPUTE_MINIMAL_WIDTH;
3961 width_done:
3962 *min_width = layout->minwidth;
3963 return S_OK;
3966 static HRESULT WINAPI dwritetextlayout_HitTestPoint(IDWriteTextLayout4 *iface,
3967 FLOAT pointX, FLOAT pointY, BOOL* is_trailinghit, BOOL* is_inside, DWRITE_HIT_TEST_METRICS *metrics)
3969 FIXME("%p, %.8e, %.8e, %p, %p, %p): stub\n", iface, pointX, pointY, is_trailinghit, is_inside, metrics);
3971 return E_NOTIMPL;
3974 static HRESULT WINAPI dwritetextlayout_HitTestTextPosition(IDWriteTextLayout4 *iface,
3975 UINT32 textPosition, BOOL is_trailinghit, FLOAT *pointX, FLOAT *pointY, DWRITE_HIT_TEST_METRICS *metrics)
3977 FIXME("%p, %u, %d, %p, %p, %p): stub\n", iface, textPosition, is_trailinghit, pointX, pointY, metrics);
3979 return E_NOTIMPL;
3982 static HRESULT WINAPI dwritetextlayout_HitTestTextRange(IDWriteTextLayout4 *iface,
3983 UINT32 textPosition, UINT32 textLength, FLOAT originX, FLOAT originY,
3984 DWRITE_HIT_TEST_METRICS *metrics, UINT32 max_metricscount, UINT32* actual_metricscount)
3986 FIXME("%p, %u, %u, %f, %f, %p, %u, %p): stub\n", iface, textPosition, textLength, originX, originY, metrics,
3987 max_metricscount, actual_metricscount);
3989 return E_NOTIMPL;
3992 static HRESULT WINAPI dwritetextlayout1_SetPairKerning(IDWriteTextLayout4 *iface, BOOL is_pairkerning_enabled,
3993 DWRITE_TEXT_RANGE range)
3995 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3996 struct layout_range_attr_value value;
3998 TRACE("%p, %d, %s.\n", iface, is_pairkerning_enabled, debugstr_range(&range));
4000 value.range = range;
4001 value.u.pair_kerning = !!is_pairkerning_enabled;
4002 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_PAIR_KERNING, &value);
4005 static HRESULT WINAPI dwritetextlayout1_GetPairKerning(IDWriteTextLayout4 *iface, UINT32 position,
4006 BOOL *is_pairkerning_enabled, DWRITE_TEXT_RANGE *r)
4008 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4009 struct layout_range *range;
4011 TRACE("%p, %u, %p, %p.\n", iface, position, is_pairkerning_enabled, r);
4013 range = get_layout_range_by_pos(layout, position);
4014 *is_pairkerning_enabled = range->pair_kerning;
4016 return return_range(&range->h, r);
4019 static HRESULT WINAPI dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout4 *iface, FLOAT leading, FLOAT trailing,
4020 FLOAT min_advance, DWRITE_TEXT_RANGE range)
4022 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4023 struct layout_range_attr_value value;
4025 TRACE("%p, %.8e, %.8e, %.8e, %s.\n", iface, leading, trailing, min_advance, debugstr_range(&range));
4027 if (min_advance < 0.0f)
4028 return E_INVALIDARG;
4030 value.range = range;
4031 value.u.spacing.leading = leading;
4032 value.u.spacing.trailing = trailing;
4033 value.u.spacing.min_advance = min_advance;
4034 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_SPACING, &value);
4037 static HRESULT WINAPI dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout4 *iface, UINT32 position, FLOAT *leading,
4038 FLOAT *trailing, FLOAT *min_advance, DWRITE_TEXT_RANGE *r)
4040 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4041 struct layout_range_spacing *range;
4043 TRACE("%p, %u, %p, %p, %p, %p.\n", iface, position, leading, trailing, min_advance, r);
4045 range = (struct layout_range_spacing *)get_layout_range_header_by_pos(&layout->spacing, position);
4046 *leading = range->leading;
4047 *trailing = range->trailing;
4048 *min_advance = range->min_advance;
4050 return return_range(&range->h, r);
4053 static HRESULT WINAPI dwritetextlayout2_GetMetrics(IDWriteTextLayout4 *iface, DWRITE_TEXT_METRICS1 *metrics)
4055 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4056 HRESULT hr;
4058 TRACE("%p, %p.\n", iface, metrics);
4060 if (SUCCEEDED(hr = layout_update_metrics(layout)))
4061 *metrics = layout->metrics;
4063 return hr;
4066 static HRESULT layout_set_vertical_orientation(struct dwrite_textlayout *layout,
4067 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4069 BOOL changed;
4070 HRESULT hr;
4072 if (FAILED(hr = format_set_vertical_orientation(&layout->format, orientation, &changed)))
4073 return hr;
4075 if (changed)
4076 layout->recompute = RECOMPUTE_EVERYTHING;
4078 return S_OK;
4081 static HRESULT WINAPI dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout4 *iface,
4082 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4084 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4086 TRACE("%p, %d.\n", iface, orientation);
4088 return layout_set_vertical_orientation(layout, orientation);
4091 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout4 *iface)
4093 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4095 TRACE("%p.\n", iface);
4097 return layout->format.vertical_orientation;
4100 static HRESULT WINAPI dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout4 *iface, BOOL lastline_wrapping_enabled)
4102 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4104 TRACE("%p, %d.\n", iface, lastline_wrapping_enabled);
4106 return IDWriteTextFormat3_SetLastLineWrapping(&layout->IDWriteTextFormat3_iface, lastline_wrapping_enabled);
4109 static BOOL WINAPI dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout4 *iface)
4111 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4113 TRACE("%p.\n", iface);
4115 return IDWriteTextFormat3_GetLastLineWrapping(&layout->IDWriteTextFormat3_iface);
4118 static HRESULT WINAPI dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout4 *iface,
4119 DWRITE_OPTICAL_ALIGNMENT alignment)
4121 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4123 TRACE("%p, %d.\n", iface, alignment);
4125 return IDWriteTextFormat3_SetOpticalAlignment(&layout->IDWriteTextFormat3_iface, alignment);
4128 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout4 *iface)
4130 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4132 TRACE("%p.\n", iface);
4134 return IDWriteTextFormat3_GetOpticalAlignment(&layout->IDWriteTextFormat3_iface);
4137 static HRESULT WINAPI dwritetextlayout2_SetFontFallback(IDWriteTextLayout4 *iface, IDWriteFontFallback *fallback)
4139 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4141 TRACE("%p, %p.\n", iface, fallback);
4143 return format_set_fontfallback(&layout->format, fallback);
4146 static HRESULT WINAPI dwritetextlayout2_GetFontFallback(IDWriteTextLayout4 *iface, IDWriteFontFallback **fallback)
4148 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4150 TRACE("%p, %p.\n", iface, fallback);
4152 return format_get_fontfallback(&layout->format, fallback);
4155 static HRESULT WINAPI dwritetextlayout3_InvalidateLayout(IDWriteTextLayout4 *iface)
4157 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4159 TRACE("%p.\n", iface);
4161 layout->recompute = RECOMPUTE_EVERYTHING;
4162 return S_OK;
4165 static HRESULT WINAPI dwritetextlayout3_SetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING const *spacing)
4167 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4168 BOOL changed;
4169 HRESULT hr;
4171 TRACE("%p, %p.\n", iface, spacing);
4173 hr = format_set_linespacing(&layout->format, spacing, &changed);
4174 if (FAILED(hr))
4175 return hr;
4177 if (changed)
4179 if (!(layout->recompute & RECOMPUTE_LINES))
4181 UINT32 line;
4183 for (line = 0; line < layout->metrics.lineCount; line++)
4184 layout_apply_line_spacing(layout, line);
4186 layout_set_line_positions(layout);
4189 layout->recompute |= RECOMPUTE_OVERHANGS;
4192 return S_OK;
4195 static HRESULT WINAPI dwritetextlayout3_GetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING *spacing)
4197 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4199 TRACE("%p, %p.\n", iface, spacing);
4201 *spacing = layout->format.spacing;
4202 return S_OK;
4205 static HRESULT WINAPI dwritetextlayout3_GetLineMetrics(IDWriteTextLayout4 *iface, DWRITE_LINE_METRICS1 *metrics,
4206 UINT32 max_count, UINT32 *count)
4208 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4209 unsigned int line_count;
4210 HRESULT hr;
4211 size_t i;
4213 TRACE("%p, %p, %u, %p.\n", iface, metrics, max_count, count);
4215 if (FAILED(hr = layout_compute_effective_runs(layout)))
4216 return hr;
4218 if (metrics)
4220 line_count = min(max_count, layout->metrics.lineCount);
4221 for (i = 0; i < line_count; ++i)
4222 metrics[i] = layout->lines[i].metrics;
4225 *count = layout->metrics.lineCount;
4226 return max_count >= layout->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
4229 static HRESULT WINAPI dwritetextlayout4_SetFontAxisValues(IDWriteTextLayout4 *iface,
4230 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, DWRITE_TEXT_RANGE range)
4232 FIXME("%p, %p, %u, %s.\n", iface, axis_values, num_values, debugstr_range(&range));
4234 return E_NOTIMPL;
4237 static UINT32 WINAPI dwritetextlayout4_GetFontAxisValueCount(IDWriteTextLayout4 *iface, UINT32 pos)
4239 FIXME("%p, %u.\n", iface, pos);
4241 return 0;
4244 static HRESULT WINAPI dwritetextlayout4_GetFontAxisValues(IDWriteTextLayout4 *iface, UINT32 pos,
4245 DWRITE_FONT_AXIS_VALUE *values, UINT32 num_values, DWRITE_TEXT_RANGE *range)
4247 FIXME("%p, %u, %p, %u, %p.\n", iface, pos, values, num_values, range);
4249 return E_NOTIMPL;
4252 static DWRITE_AUTOMATIC_FONT_AXES WINAPI dwritetextlayout4_GetAutomaticFontAxes(IDWriteTextLayout4 *iface)
4254 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4256 TRACE("%p.\n", iface);
4258 return layout->format.automatic_axes;
4261 static HRESULT WINAPI dwritetextlayout4_SetAutomaticFontAxes(IDWriteTextLayout4 *iface,
4262 DWRITE_AUTOMATIC_FONT_AXES axes)
4264 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4266 TRACE("%p, %d.\n", iface, axes);
4268 if ((unsigned int)axes > DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE)
4269 return E_INVALIDARG;
4271 layout->format.automatic_axes = axes;
4272 return S_OK;
4275 static const IDWriteTextLayout4Vtbl dwritetextlayoutvtbl =
4277 dwritetextlayout_QueryInterface,
4278 dwritetextlayout_AddRef,
4279 dwritetextlayout_Release,
4280 dwritetextlayout_SetTextAlignment,
4281 dwritetextlayout_SetParagraphAlignment,
4282 dwritetextlayout_SetWordWrapping,
4283 dwritetextlayout_SetReadingDirection,
4284 dwritetextlayout_SetFlowDirection,
4285 dwritetextlayout_SetIncrementalTabStop,
4286 dwritetextlayout_SetTrimming,
4287 dwritetextlayout_SetLineSpacing,
4288 dwritetextlayout_GetTextAlignment,
4289 dwritetextlayout_GetParagraphAlignment,
4290 dwritetextlayout_GetWordWrapping,
4291 dwritetextlayout_GetReadingDirection,
4292 dwritetextlayout_GetFlowDirection,
4293 dwritetextlayout_GetIncrementalTabStop,
4294 dwritetextlayout_GetTrimming,
4295 dwritetextlayout_GetLineSpacing,
4296 dwritetextlayout_GetFontCollection,
4297 dwritetextlayout_GetFontFamilyNameLength,
4298 dwritetextlayout_GetFontFamilyName,
4299 dwritetextlayout_GetFontWeight,
4300 dwritetextlayout_GetFontStyle,
4301 dwritetextlayout_GetFontStretch,
4302 dwritetextlayout_GetFontSize,
4303 dwritetextlayout_GetLocaleNameLength,
4304 dwritetextlayout_GetLocaleName,
4305 dwritetextlayout_SetMaxWidth,
4306 dwritetextlayout_SetMaxHeight,
4307 dwritetextlayout_SetFontCollection,
4308 dwritetextlayout_SetFontFamilyName,
4309 dwritetextlayout_SetFontWeight,
4310 dwritetextlayout_SetFontStyle,
4311 dwritetextlayout_SetFontStretch,
4312 dwritetextlayout_SetFontSize,
4313 dwritetextlayout_SetUnderline,
4314 dwritetextlayout_SetStrikethrough,
4315 dwritetextlayout_SetDrawingEffect,
4316 dwritetextlayout_SetInlineObject,
4317 dwritetextlayout_SetTypography,
4318 dwritetextlayout_SetLocaleName,
4319 dwritetextlayout_GetMaxWidth,
4320 dwritetextlayout_GetMaxHeight,
4321 dwritetextlayout_layout_GetFontCollection,
4322 dwritetextlayout_layout_GetFontFamilyNameLength,
4323 dwritetextlayout_layout_GetFontFamilyName,
4324 dwritetextlayout_layout_GetFontWeight,
4325 dwritetextlayout_layout_GetFontStyle,
4326 dwritetextlayout_layout_GetFontStretch,
4327 dwritetextlayout_layout_GetFontSize,
4328 dwritetextlayout_GetUnderline,
4329 dwritetextlayout_GetStrikethrough,
4330 dwritetextlayout_GetDrawingEffect,
4331 dwritetextlayout_GetInlineObject,
4332 dwritetextlayout_GetTypography,
4333 dwritetextlayout_layout_GetLocaleNameLength,
4334 dwritetextlayout_layout_GetLocaleName,
4335 dwritetextlayout_Draw,
4336 dwritetextlayout_GetLineMetrics,
4337 dwritetextlayout_GetMetrics,
4338 dwritetextlayout_GetOverhangMetrics,
4339 dwritetextlayout_GetClusterMetrics,
4340 dwritetextlayout_DetermineMinWidth,
4341 dwritetextlayout_HitTestPoint,
4342 dwritetextlayout_HitTestTextPosition,
4343 dwritetextlayout_HitTestTextRange,
4344 dwritetextlayout1_SetPairKerning,
4345 dwritetextlayout1_GetPairKerning,
4346 dwritetextlayout1_SetCharacterSpacing,
4347 dwritetextlayout1_GetCharacterSpacing,
4348 dwritetextlayout2_GetMetrics,
4349 dwritetextlayout2_SetVerticalGlyphOrientation,
4350 dwritetextlayout2_GetVerticalGlyphOrientation,
4351 dwritetextlayout2_SetLastLineWrapping,
4352 dwritetextlayout2_GetLastLineWrapping,
4353 dwritetextlayout2_SetOpticalAlignment,
4354 dwritetextlayout2_GetOpticalAlignment,
4355 dwritetextlayout2_SetFontFallback,
4356 dwritetextlayout2_GetFontFallback,
4357 dwritetextlayout3_InvalidateLayout,
4358 dwritetextlayout3_SetLineSpacing,
4359 dwritetextlayout3_GetLineSpacing,
4360 dwritetextlayout3_GetLineMetrics,
4361 dwritetextlayout4_SetFontAxisValues,
4362 dwritetextlayout4_GetFontAxisValueCount,
4363 dwritetextlayout4_GetFontAxisValues,
4364 dwritetextlayout4_GetAutomaticFontAxes,
4365 dwritetextlayout4_SetAutomaticFontAxes,
4368 static HRESULT WINAPI dwritetextformat_layout_QueryInterface(IDWriteTextFormat3 *iface, REFIID riid, void **obj)
4370 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4372 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
4374 return IDWriteTextLayout4_QueryInterface(&layout->IDWriteTextLayout4_iface, riid, obj);
4377 static ULONG WINAPI dwritetextformat_layout_AddRef(IDWriteTextFormat3 *iface)
4379 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4380 return IDWriteTextLayout4_AddRef(&layout->IDWriteTextLayout4_iface);
4383 static ULONG WINAPI dwritetextformat_layout_Release(IDWriteTextFormat3 *iface)
4385 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4386 return IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
4389 static HRESULT WINAPI dwritetextformat_layout_SetTextAlignment(IDWriteTextFormat3 *iface,
4390 DWRITE_TEXT_ALIGNMENT alignment)
4392 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4393 BOOL changed;
4394 HRESULT hr;
4396 TRACE("%p, %d.\n", iface, alignment);
4398 hr = format_set_textalignment(&layout->format, alignment, &changed);
4399 if (FAILED(hr))
4400 return hr;
4402 if (changed)
4404 /* if layout is not ready there's nothing to align */
4405 if (!(layout->recompute & RECOMPUTE_LINES))
4406 layout_apply_text_alignment(layout);
4407 layout->recompute |= RECOMPUTE_OVERHANGS;
4410 return S_OK;
4413 static HRESULT WINAPI dwritetextformat_layout_SetParagraphAlignment(IDWriteTextFormat3 *iface,
4414 DWRITE_PARAGRAPH_ALIGNMENT alignment)
4416 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4417 BOOL changed;
4418 HRESULT hr;
4420 TRACE("%p, %d.\n", iface, alignment);
4422 hr = format_set_paralignment(&layout->format, alignment, &changed);
4423 if (FAILED(hr))
4424 return hr;
4426 if (changed)
4428 /* if layout is not ready there's nothing to align */
4429 if (!(layout->recompute & RECOMPUTE_LINES))
4430 layout_apply_par_alignment(layout);
4431 layout->recompute |= RECOMPUTE_OVERHANGS;
4434 return S_OK;
4437 static HRESULT WINAPI dwritetextformat_layout_SetWordWrapping(IDWriteTextFormat3 *iface, DWRITE_WORD_WRAPPING wrapping)
4439 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4440 BOOL changed;
4441 HRESULT hr;
4443 TRACE("%p, %d.\n", iface, wrapping);
4445 hr = format_set_wordwrapping(&layout->format, wrapping, &changed);
4446 if (FAILED(hr))
4447 return hr;
4449 if (changed)
4450 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
4452 return S_OK;
4455 static HRESULT WINAPI dwritetextformat_layout_SetReadingDirection(IDWriteTextFormat3 *iface,
4456 DWRITE_READING_DIRECTION direction)
4458 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4459 BOOL changed;
4460 HRESULT hr;
4462 TRACE("%p, %d.\n", iface, direction);
4464 hr = format_set_readingdirection(&layout->format, direction, &changed);
4465 if (FAILED(hr))
4466 return hr;
4468 if (changed)
4469 layout->recompute = RECOMPUTE_EVERYTHING;
4471 return S_OK;
4474 static HRESULT WINAPI dwritetextformat_layout_SetFlowDirection(IDWriteTextFormat3 *iface,
4475 DWRITE_FLOW_DIRECTION direction)
4477 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4478 BOOL changed;
4479 HRESULT hr;
4481 TRACE("%p, %d.\n", iface, direction);
4483 hr = format_set_flowdirection(&layout->format, direction, &changed);
4484 if (FAILED(hr))
4485 return hr;
4487 if (changed)
4488 layout->recompute = RECOMPUTE_EVERYTHING;
4490 return S_OK;
4493 static HRESULT WINAPI dwritetextformat_layout_SetIncrementalTabStop(IDWriteTextFormat3 *iface, FLOAT tabstop)
4495 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4497 TRACE("%p, %.8e.\n", iface, tabstop);
4499 if (tabstop <= 0.0f)
4500 return E_INVALIDARG;
4502 layout->format.tabstop = tabstop;
4503 return S_OK;
4506 static HRESULT WINAPI dwritetextformat_layout_SetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING const *trimming,
4507 IDWriteInlineObject *trimming_sign)
4509 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4510 BOOL changed;
4511 HRESULT hr;
4513 TRACE("%p, %p, %p.\n", iface, trimming, trimming_sign);
4515 hr = format_set_trimming(&layout->format, trimming, trimming_sign, &changed);
4517 if (changed)
4518 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
4520 return hr;
4523 static HRESULT WINAPI dwritetextformat_layout_SetLineSpacing(IDWriteTextFormat3 *iface,
4524 DWRITE_LINE_SPACING_METHOD method, FLOAT height, FLOAT baseline)
4526 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4527 DWRITE_LINE_SPACING spacing;
4529 TRACE("%p, %d, %.8e, %.8e.\n", iface, method, height, baseline);
4531 spacing = layout->format.spacing;
4532 spacing.method = method;
4533 spacing.height = height;
4534 spacing.baseline = baseline;
4535 return IDWriteTextLayout4_SetLineSpacing(&layout->IDWriteTextLayout4_iface, &spacing);
4538 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_layout_GetTextAlignment(IDWriteTextFormat3 *iface)
4540 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4542 TRACE("%p.\n", iface);
4544 return layout->format.textalignment;
4547 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_layout_GetParagraphAlignment(IDWriteTextFormat3 *iface)
4549 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4551 TRACE("%p.\n", iface);
4553 return layout->format.paralign;
4556 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_layout_GetWordWrapping(IDWriteTextFormat3 *iface)
4558 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4560 TRACE("%p.\n", iface);
4562 return layout->format.wrapping;
4565 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_layout_GetReadingDirection(IDWriteTextFormat3 *iface)
4567 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4569 TRACE("%p.\n", iface);
4571 return layout->format.readingdir;
4574 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_layout_GetFlowDirection(IDWriteTextFormat3 *iface)
4576 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4578 TRACE("%p.\n", iface);
4580 return layout->format.flow;
4583 static FLOAT WINAPI dwritetextformat_layout_GetIncrementalTabStop(IDWriteTextFormat3 *iface)
4585 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4587 TRACE("%p.\n", iface);
4589 return layout->format.tabstop;
4592 static HRESULT WINAPI dwritetextformat_layout_GetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING *options,
4593 IDWriteInlineObject **trimming_sign)
4595 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4597 TRACE("%p, %p, %p.\n", iface, options, trimming_sign);
4599 *options = layout->format.trimming;
4600 *trimming_sign = layout->format.trimmingsign;
4601 if (*trimming_sign)
4602 IDWriteInlineObject_AddRef(*trimming_sign);
4603 return S_OK;
4606 static HRESULT WINAPI dwritetextformat_layout_GetLineSpacing(IDWriteTextFormat3 *iface,
4607 DWRITE_LINE_SPACING_METHOD *method, FLOAT *spacing, FLOAT *baseline)
4609 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4611 TRACE("%p, %p, %p, %p.\n", iface, method, spacing, baseline);
4613 *method = layout->format.spacing.method;
4614 *spacing = layout->format.spacing.height;
4615 *baseline = layout->format.spacing.baseline;
4616 return S_OK;
4619 static HRESULT WINAPI dwritetextformat_layout_GetFontCollection(IDWriteTextFormat3 *iface,
4620 IDWriteFontCollection **collection)
4622 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4624 TRACE("%p, %p.\n", iface, collection);
4626 *collection = layout->format.collection;
4627 if (*collection)
4628 IDWriteFontCollection_AddRef(*collection);
4629 return S_OK;
4632 static UINT32 WINAPI dwritetextformat_layout_GetFontFamilyNameLength(IDWriteTextFormat3 *iface)
4634 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4636 TRACE("%p.\n", iface);
4638 return layout->format.family_len;
4641 static HRESULT WINAPI dwritetextformat_layout_GetFontFamilyName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
4643 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4645 TRACE("%p, %p, %u.\n", iface, name, size);
4647 if (size <= layout->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
4648 wcscpy(name, layout->format.family_name);
4649 return S_OK;
4652 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_layout_GetFontWeight(IDWriteTextFormat3 *iface)
4654 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4656 TRACE("%p.\n", iface);
4658 return layout->format.weight;
4661 static DWRITE_FONT_STYLE WINAPI dwritetextformat_layout_GetFontStyle(IDWriteTextFormat3 *iface)
4663 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4665 TRACE("%p.\n", iface);
4667 return layout->format.style;
4670 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_layout_GetFontStretch(IDWriteTextFormat3 *iface)
4672 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4674 TRACE("%p.\n", iface);
4676 return layout->format.stretch;
4679 static FLOAT WINAPI dwritetextformat_layout_GetFontSize(IDWriteTextFormat3 *iface)
4681 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4683 TRACE("%p.\n", iface);
4685 return layout->format.fontsize;
4688 static UINT32 WINAPI dwritetextformat_layout_GetLocaleNameLength(IDWriteTextFormat3 *iface)
4690 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4692 TRACE("%p.\n", iface);
4694 return layout->format.locale_len;
4697 static HRESULT WINAPI dwritetextformat_layout_GetLocaleName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
4699 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4701 TRACE("%p, %p, %u.\n", iface, name, size);
4703 if (size <= layout->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
4704 wcscpy(name, layout->format.locale);
4705 return S_OK;
4708 static HRESULT WINAPI dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat3 *iface,
4709 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4711 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4713 TRACE("%p, %d.\n", iface, orientation);
4715 return layout_set_vertical_orientation(layout, orientation);
4718 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat3 *iface)
4720 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4722 TRACE("%p.\n", iface);
4724 return layout->format.vertical_orientation;
4727 static HRESULT WINAPI dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat3 *iface,
4728 BOOL lastline_wrapping_enabled)
4730 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4732 TRACE("%p, %d.\n", iface, lastline_wrapping_enabled);
4734 layout->format.last_line_wrapping = !!lastline_wrapping_enabled;
4735 return S_OK;
4738 static BOOL WINAPI dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat3 *iface)
4740 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4742 TRACE("%p.\n", iface);
4744 return layout->format.last_line_wrapping;
4747 static HRESULT WINAPI dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat3 *iface,
4748 DWRITE_OPTICAL_ALIGNMENT alignment)
4750 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4752 TRACE("%p, %d.\n", iface, alignment);
4754 return format_set_optical_alignment(&layout->format, alignment);
4757 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat3 *iface)
4759 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4761 TRACE("%p.\n", iface);
4763 return layout->format.optical_alignment;
4766 static HRESULT WINAPI dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat3 *iface,
4767 IDWriteFontFallback *fallback)
4769 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4771 TRACE("%p, %p.\n", iface, fallback);
4773 return IDWriteTextLayout4_SetFontFallback(&layout->IDWriteTextLayout4_iface, fallback);
4776 static HRESULT WINAPI dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat3 *iface,
4777 IDWriteFontFallback **fallback)
4779 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4781 TRACE("%p, %p.\n", iface, fallback);
4783 return IDWriteTextLayout4_GetFontFallback(&layout->IDWriteTextLayout4_iface, fallback);
4786 static HRESULT WINAPI dwritetextformat2_layout_SetLineSpacing(IDWriteTextFormat3 *iface,
4787 DWRITE_LINE_SPACING const *spacing)
4789 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4790 return IDWriteTextLayout4_SetLineSpacing(&layout->IDWriteTextLayout4_iface, spacing);
4793 static HRESULT WINAPI dwritetextformat2_layout_GetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING *spacing)
4795 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4796 return IDWriteTextLayout4_GetLineSpacing(&layout->IDWriteTextLayout4_iface, spacing);
4799 static HRESULT WINAPI dwritetextformat3_layout_SetFontAxisValues(IDWriteTextFormat3 *iface,
4800 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values)
4802 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4804 TRACE("%p, %p, %u.\n", iface, axis_values, num_values);
4806 return format_set_font_axisvalues(&layout->format, axis_values, num_values);
4809 static UINT32 WINAPI dwritetextformat3_layout_GetFontAxisValueCount(IDWriteTextFormat3 *iface)
4811 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4813 TRACE("%p.\n", iface);
4815 return layout->format.axis_values_count;
4818 static HRESULT WINAPI dwritetextformat3_layout_GetFontAxisValues(IDWriteTextFormat3 *iface,
4819 DWRITE_FONT_AXIS_VALUE *axis_values, UINT32 num_values)
4821 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4823 TRACE("%p, %p, %u.\n", iface, axis_values, num_values);
4825 return format_get_font_axisvalues(&layout->format, axis_values, num_values);
4828 static DWRITE_AUTOMATIC_FONT_AXES WINAPI dwritetextformat3_layout_GetAutomaticFontAxes(IDWriteTextFormat3 *iface)
4830 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4831 return IDWriteTextLayout4_GetAutomaticFontAxes(&layout->IDWriteTextLayout4_iface);
4834 static HRESULT WINAPI dwritetextformat3_layout_SetAutomaticFontAxes(IDWriteTextFormat3 *iface,
4835 DWRITE_AUTOMATIC_FONT_AXES axes)
4837 struct dwrite_textlayout *layout = impl_from_IDWriteTextFormat3(iface);
4838 return IDWriteTextLayout4_SetAutomaticFontAxes(&layout->IDWriteTextLayout4_iface, axes);
4841 static const IDWriteTextFormat3Vtbl dwritetextformat3_layout_vtbl =
4843 dwritetextformat_layout_QueryInterface,
4844 dwritetextformat_layout_AddRef,
4845 dwritetextformat_layout_Release,
4846 dwritetextformat_layout_SetTextAlignment,
4847 dwritetextformat_layout_SetParagraphAlignment,
4848 dwritetextformat_layout_SetWordWrapping,
4849 dwritetextformat_layout_SetReadingDirection,
4850 dwritetextformat_layout_SetFlowDirection,
4851 dwritetextformat_layout_SetIncrementalTabStop,
4852 dwritetextformat_layout_SetTrimming,
4853 dwritetextformat_layout_SetLineSpacing,
4854 dwritetextformat_layout_GetTextAlignment,
4855 dwritetextformat_layout_GetParagraphAlignment,
4856 dwritetextformat_layout_GetWordWrapping,
4857 dwritetextformat_layout_GetReadingDirection,
4858 dwritetextformat_layout_GetFlowDirection,
4859 dwritetextformat_layout_GetIncrementalTabStop,
4860 dwritetextformat_layout_GetTrimming,
4861 dwritetextformat_layout_GetLineSpacing,
4862 dwritetextformat_layout_GetFontCollection,
4863 dwritetextformat_layout_GetFontFamilyNameLength,
4864 dwritetextformat_layout_GetFontFamilyName,
4865 dwritetextformat_layout_GetFontWeight,
4866 dwritetextformat_layout_GetFontStyle,
4867 dwritetextformat_layout_GetFontStretch,
4868 dwritetextformat_layout_GetFontSize,
4869 dwritetextformat_layout_GetLocaleNameLength,
4870 dwritetextformat_layout_GetLocaleName,
4871 dwritetextformat1_layout_SetVerticalGlyphOrientation,
4872 dwritetextformat1_layout_GetVerticalGlyphOrientation,
4873 dwritetextformat1_layout_SetLastLineWrapping,
4874 dwritetextformat1_layout_GetLastLineWrapping,
4875 dwritetextformat1_layout_SetOpticalAlignment,
4876 dwritetextformat1_layout_GetOpticalAlignment,
4877 dwritetextformat1_layout_SetFontFallback,
4878 dwritetextformat1_layout_GetFontFallback,
4879 dwritetextformat2_layout_SetLineSpacing,
4880 dwritetextformat2_layout_GetLineSpacing,
4881 dwritetextformat3_layout_SetFontAxisValues,
4882 dwritetextformat3_layout_GetFontAxisValueCount,
4883 dwritetextformat3_layout_GetFontAxisValues,
4884 dwritetextformat3_layout_GetAutomaticFontAxes,
4885 dwritetextformat3_layout_SetAutomaticFontAxes,
4888 static HRESULT WINAPI dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink1 *iface,
4889 REFIID riid, void **obj)
4891 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink1) ||
4892 IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) ||
4893 IsEqualIID(riid, &IID_IUnknown))
4895 *obj = iface;
4896 IDWriteTextAnalysisSink1_AddRef(iface);
4897 return S_OK;
4900 WARN("%s not implemented.\n", debugstr_guid(riid));
4902 *obj = NULL;
4903 return E_NOINTERFACE;
4906 static ULONG WINAPI dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink1 *iface)
4908 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4909 return IDWriteTextLayout4_AddRef(&layout->IDWriteTextLayout4_iface);
4912 static ULONG WINAPI dwritetextlayout_sink_Release(IDWriteTextAnalysisSink1 *iface)
4914 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4915 return IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
4918 static HRESULT WINAPI dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink1 *iface,
4919 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
4921 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4922 struct layout_run *run;
4923 HRESULT hr;
4925 TRACE("[%u,%u) script=%u:%s\n", position, position + length, sa->script, debugstr_sa_script(sa->script));
4927 if (FAILED(hr = alloc_layout_run(LAYOUT_RUN_REGULAR, position, &run)))
4928 return hr;
4930 run->u.regular.descr.string = &layout->str[position];
4931 run->u.regular.descr.stringLength = length;
4932 run->u.regular.descr.textPosition = position;
4933 run->u.regular.sa = *sa;
4934 list_add_tail(&layout->runs, &run->entry);
4935 return S_OK;
4938 static HRESULT WINAPI dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink1 *iface,
4939 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
4941 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4943 if (position + length > layout->len)
4944 return E_FAIL;
4946 memcpy(&layout->nominal_breakpoints[position], breakpoints, length*sizeof(DWRITE_LINE_BREAKPOINT));
4947 return S_OK;
4950 static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink1 *iface, UINT32 position,
4951 UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
4953 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4954 struct layout_run *cur_run;
4955 HRESULT hr;
4957 TRACE("[%u,%u) %u %u\n", position, position + length, explicitLevel, resolvedLevel);
4959 LIST_FOR_EACH_ENTRY(cur_run, &layout->runs, struct layout_run, entry) {
4960 struct regular_layout_run *cur = &cur_run->u.regular;
4961 struct layout_run *run;
4963 if (cur_run->kind == LAYOUT_RUN_INLINE)
4964 continue;
4966 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
4967 if (position < cur->descr.textPosition || position >= cur->descr.textPosition + cur->descr.stringLength)
4968 continue;
4970 /* full hit - just set run level */
4971 if (cur->descr.textPosition == position && cur->descr.stringLength == length) {
4972 cur->run.bidiLevel = resolvedLevel;
4973 break;
4976 /* current run is fully covered, move to next one */
4977 if (cur->descr.textPosition == position && cur->descr.stringLength < length) {
4978 cur->run.bidiLevel = resolvedLevel;
4979 position += cur->descr.stringLength;
4980 length -= cur->descr.stringLength;
4981 continue;
4984 /* all fully covered runs are processed at this point, reuse existing run for remaining
4985 reported bidi range and add another run for the rest of original one */
4987 if (FAILED(hr = alloc_layout_run(LAYOUT_RUN_REGULAR, position + length, &run)))
4988 return hr;
4990 *run = *cur_run;
4991 run->u.regular.descr.textPosition = position + length;
4992 run->u.regular.descr.stringLength = cur->descr.stringLength - length;
4993 run->u.regular.descr.string = &layout->str[position + length];
4995 /* reduce existing run */
4996 cur->run.bidiLevel = resolvedLevel;
4997 cur->descr.stringLength = length;
4999 list_add_after(&cur_run->entry, &run->entry);
5000 break;
5003 return S_OK;
5006 static HRESULT WINAPI dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink1 *iface,
5007 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
5009 return E_NOTIMPL;
5012 static HRESULT WINAPI dwritetextlayout_sink_SetGlyphOrientation(IDWriteTextAnalysisSink1 *iface,
5013 UINT32 position, UINT32 length, DWRITE_GLYPH_ORIENTATION_ANGLE angle, UINT8 adjusted_bidi_level,
5014 BOOL is_sideways, BOOL is_rtl)
5016 return E_NOTIMPL;
5019 static const IDWriteTextAnalysisSink1Vtbl dwritetextlayoutsinkvtbl = {
5020 dwritetextlayout_sink_QueryInterface,
5021 dwritetextlayout_sink_AddRef,
5022 dwritetextlayout_sink_Release,
5023 dwritetextlayout_sink_SetScriptAnalysis,
5024 dwritetextlayout_sink_SetLineBreakpoints,
5025 dwritetextlayout_sink_SetBidiLevel,
5026 dwritetextlayout_sink_SetNumberSubstitution,
5027 dwritetextlayout_sink_SetGlyphOrientation
5030 static HRESULT WINAPI dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource1 *iface,
5031 REFIID riid, void **obj)
5033 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource1) ||
5034 IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) ||
5035 IsEqualIID(riid, &IID_IUnknown))
5037 *obj = iface;
5038 IDWriteTextAnalysisSource1_AddRef(iface);
5039 return S_OK;
5042 WARN("%s not implemented.\n", debugstr_guid(riid));
5044 *obj = NULL;
5045 return E_NOINTERFACE;
5048 static ULONG WINAPI dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource1 *iface)
5050 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5051 return IDWriteTextLayout4_AddRef(&layout->IDWriteTextLayout4_iface);
5054 static ULONG WINAPI dwritetextlayout_source_Release(IDWriteTextAnalysisSource1 *iface)
5056 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5057 return IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
5060 static HRESULT WINAPI dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource1 *iface,
5061 UINT32 position, WCHAR const** text, UINT32* text_len)
5063 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5065 TRACE("%p, %u, %p, %p.\n", iface, position, text, text_len);
5067 if (position < layout->text_source.length)
5069 *text = &layout->str[position + layout->text_source.offset];
5070 *text_len = layout->text_source.length - position;
5072 else
5074 *text = NULL;
5075 *text_len = 0;
5078 return S_OK;
5081 static HRESULT WINAPI dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource1 *iface,
5082 UINT32 position, WCHAR const** text, UINT32* text_len)
5084 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5086 TRACE("%p, %u, %p, %p.\n", iface, position, text, text_len);
5088 if (position && position < layout->text_source.length)
5090 *text = &layout->str[layout->text_source.offset];
5091 *text_len = position;
5093 else
5095 *text = NULL;
5096 *text_len = 0;
5099 return S_OK;
5102 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource1 *iface)
5104 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5105 return IDWriteTextLayout4_GetReadingDirection(&layout->IDWriteTextLayout4_iface);
5108 static HRESULT WINAPI dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource1 *iface,
5109 UINT32 position, UINT32* text_len, WCHAR const** locale)
5111 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5112 struct layout_range *range, *next;
5113 unsigned int end;
5115 if (position < layout->text_source.length)
5117 position += layout->text_source.offset;
5118 end = layout->text_source.offset + layout->text_source.length;
5120 range = get_layout_range_by_pos(layout, position);
5122 *locale = range->locale;
5123 *text_len = range->h.range.startPosition + range->h.range.length - position;
5125 next = LIST_ENTRY(list_next(&layout->ranges, &range->h.entry), struct layout_range, h.entry);
5126 while (next && next->h.range.startPosition < end && !wcscmp(range->locale, next->locale))
5128 *text_len += next->h.range.length;
5129 next = LIST_ENTRY(list_next(&layout->ranges, &next->h.entry), struct layout_range, h.entry);
5132 *text_len = min(*text_len, layout->text_source.length - position);
5134 else
5136 *locale = NULL;
5137 *text_len = 0;
5140 return S_OK;
5143 static HRESULT WINAPI dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource1 *iface,
5144 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
5146 FIXME("%u %p %p: stub\n", position, text_len, substitution);
5147 return E_NOTIMPL;
5150 static HRESULT WINAPI dwritetextlayout_source_GetVerticalGlyphOrientation(IDWriteTextAnalysisSource1 *iface,
5151 UINT32 position, UINT32 *length, DWRITE_VERTICAL_GLYPH_ORIENTATION *orientation, UINT8 *bidi_level)
5153 FIXME("%u %p %p %p: stub\n", position, length, orientation, bidi_level);
5154 return E_NOTIMPL;
5157 static const IDWriteTextAnalysisSource1Vtbl dwritetextlayoutsourcevtbl = {
5158 dwritetextlayout_source_QueryInterface,
5159 dwritetextlayout_source_AddRef,
5160 dwritetextlayout_source_Release,
5161 dwritetextlayout_source_GetTextAtPosition,
5162 dwritetextlayout_source_GetTextBeforePosition,
5163 dwritetextlayout_source_GetParagraphReadingDirection,
5164 dwritetextlayout_source_GetLocaleName,
5165 dwritetextlayout_source_GetNumberSubstitution,
5166 dwritetextlayout_source_GetVerticalGlyphOrientation
5169 static HRESULT layout_format_from_textformat(struct dwrite_textlayout *layout, IDWriteTextFormat *format)
5171 struct dwrite_textformat *textformat;
5172 IDWriteTextFormat1 *format1;
5173 IDWriteTextFormat3 *format3;
5174 UINT32 len;
5175 HRESULT hr;
5177 if ((textformat = unsafe_impl_from_IDWriteTextFormat(format))) {
5178 layout->format = textformat->format;
5180 layout->format.locale = wcsdup(textformat->format.locale);
5181 layout->format.family_name = wcsdup(textformat->format.family_name);
5182 if (!layout->format.locale || !layout->format.family_name)
5184 free(layout->format.locale);
5185 free(layout->format.family_name);
5186 return E_OUTOFMEMORY;
5189 if (layout->format.trimmingsign)
5190 IDWriteInlineObject_AddRef(layout->format.trimmingsign);
5191 if (layout->format.collection)
5192 IDWriteFontCollection_AddRef(layout->format.collection);
5193 if (layout->format.fallback)
5194 IDWriteFontFallback_AddRef(layout->format.fallback);
5196 return S_OK;
5199 layout->format.weight = IDWriteTextFormat_GetFontWeight(format);
5200 layout->format.style = IDWriteTextFormat_GetFontStyle(format);
5201 layout->format.stretch = IDWriteTextFormat_GetFontStretch(format);
5202 layout->format.fontsize= IDWriteTextFormat_GetFontSize(format);
5203 layout->format.tabstop = IDWriteTextFormat_GetIncrementalTabStop(format);
5204 layout->format.textalignment = IDWriteTextFormat_GetTextAlignment(format);
5205 layout->format.paralign = IDWriteTextFormat_GetParagraphAlignment(format);
5206 layout->format.wrapping = IDWriteTextFormat_GetWordWrapping(format);
5207 layout->format.readingdir = IDWriteTextFormat_GetReadingDirection(format);
5208 layout->format.flow = IDWriteTextFormat_GetFlowDirection(format);
5209 hr = IDWriteTextFormat_GetLineSpacing(format, &layout->format.spacing.method,
5210 &layout->format.spacing.height, &layout->format.spacing.baseline);
5211 if (FAILED(hr))
5212 return hr;
5214 hr = IDWriteTextFormat_GetTrimming(format, &layout->format.trimming, &layout->format.trimmingsign);
5215 if (FAILED(hr))
5216 return hr;
5218 /* locale name and length */
5219 len = IDWriteTextFormat_GetLocaleNameLength(format);
5220 if (!(layout->format.locale = malloc((len + 1) * sizeof(WCHAR))))
5221 return E_OUTOFMEMORY;
5223 hr = IDWriteTextFormat_GetLocaleName(format, layout->format.locale, len+1);
5224 if (FAILED(hr))
5225 return hr;
5226 layout->format.locale_len = len;
5228 /* font family name and length */
5229 len = IDWriteTextFormat_GetFontFamilyNameLength(format);
5230 if (!(layout->format.family_name = malloc((len + 1) * sizeof(WCHAR))))
5231 return E_OUTOFMEMORY;
5233 hr = IDWriteTextFormat_GetFontFamilyName(format, layout->format.family_name, len+1);
5234 if (FAILED(hr))
5235 return hr;
5236 layout->format.family_len = len;
5238 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
5239 if (hr == S_OK)
5241 IDWriteTextFormat2 *format2;
5243 layout->format.vertical_orientation = IDWriteTextFormat1_GetVerticalGlyphOrientation(format1);
5244 layout->format.optical_alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
5245 IDWriteTextFormat1_GetFontFallback(format1, &layout->format.fallback);
5247 if (IDWriteTextFormat1_QueryInterface(format1, &IID_IDWriteTextFormat2, (void**)&format2) == S_OK) {
5248 IDWriteTextFormat2_GetLineSpacing(format2, &layout->format.spacing);
5249 IDWriteTextFormat2_Release(format2);
5252 IDWriteTextFormat1_Release(format1);
5255 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat3, (void **)&format3);
5256 if (hr == S_OK)
5258 layout->format.automatic_axes = IDWriteTextFormat3_GetAutomaticFontAxes(format3);
5259 IDWriteTextFormat3_Release(format3);
5262 return IDWriteTextFormat_GetFontCollection(format, &layout->format.collection);
5265 static HRESULT init_textlayout(const struct textlayout_desc *desc, struct dwrite_textlayout *layout)
5267 struct layout_range_header *range, *strike, *underline, *effect, *spacing, *typography;
5268 static const DWRITE_TEXT_RANGE r = { 0, ~0u };
5269 HRESULT hr;
5271 layout->IDWriteTextLayout4_iface.lpVtbl = &dwritetextlayoutvtbl;
5272 layout->IDWriteTextFormat3_iface.lpVtbl = &dwritetextformat3_layout_vtbl;
5273 layout->IDWriteTextAnalysisSink1_iface.lpVtbl = &dwritetextlayoutsinkvtbl;
5274 layout->IDWriteTextAnalysisSource1_iface.lpVtbl = &dwritetextlayoutsourcevtbl;
5275 layout->refcount = 1;
5276 layout->len = desc->length;
5277 layout->recompute = RECOMPUTE_EVERYTHING;
5278 list_init(&layout->eruns);
5279 list_init(&layout->inlineobjects);
5280 list_init(&layout->underlines);
5281 list_init(&layout->strikethrough);
5282 list_init(&layout->runs);
5283 list_init(&layout->ranges);
5284 list_init(&layout->strike_ranges);
5285 list_init(&layout->underline_ranges);
5286 list_init(&layout->effects);
5287 list_init(&layout->spacing);
5288 list_init(&layout->typographies);
5289 layout->metrics.layoutWidth = desc->max_width;
5290 layout->metrics.layoutHeight = desc->max_height;
5292 layout->str = heap_strdupnW(desc->string, desc->length);
5293 if (desc->length && !layout->str) {
5294 hr = E_OUTOFMEMORY;
5295 goto fail;
5298 hr = layout_format_from_textformat(layout, desc->format);
5299 if (FAILED(hr))
5300 goto fail;
5302 range = alloc_layout_range(layout, &r, LAYOUT_RANGE_REGULAR);
5303 strike = alloc_layout_range(layout, &r, LAYOUT_RANGE_STRIKETHROUGH);
5304 underline = alloc_layout_range(layout, &r, LAYOUT_RANGE_UNDERLINE);
5305 effect = alloc_layout_range(layout, &r, LAYOUT_RANGE_EFFECT);
5306 spacing = alloc_layout_range(layout, &r, LAYOUT_RANGE_SPACING);
5307 typography = alloc_layout_range(layout, &r, LAYOUT_RANGE_TYPOGRAPHY);
5308 if (!range || !strike || !effect || !spacing || !typography || !underline) {
5309 free_layout_range(range);
5310 free_layout_range(strike);
5311 free_layout_range(underline);
5312 free_layout_range(effect);
5313 free_layout_range(spacing);
5314 free_layout_range(typography);
5315 hr = E_OUTOFMEMORY;
5316 goto fail;
5319 layout->measuringmode = desc->is_gdi_compatible ? (desc->use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL :
5320 DWRITE_MEASURING_MODE_GDI_CLASSIC) : DWRITE_MEASURING_MODE_NATURAL;
5321 layout->ppdip = desc->ppdip;
5322 layout->transform = desc->transform ? *desc->transform : identity;
5324 layout->factory = desc->factory;
5325 IDWriteFactory7_AddRef(layout->factory);
5326 list_add_head(&layout->ranges, &range->entry);
5327 list_add_head(&layout->strike_ranges, &strike->entry);
5328 list_add_head(&layout->underline_ranges, &underline->entry);
5329 list_add_head(&layout->effects, &effect->entry);
5330 list_add_head(&layout->spacing, &spacing->entry);
5331 list_add_head(&layout->typographies, &typography->entry);
5333 if (FAILED(hr = IDWriteFactory5_GetSystemFontCollection((IDWriteFactory5 *)layout->factory, FALSE,
5334 (IDWriteFontCollection1 **)&layout->system_collection, FALSE)))
5336 goto fail;
5339 return S_OK;
5341 fail:
5342 IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
5343 return hr;
5346 HRESULT create_textlayout(const struct textlayout_desc *desc, IDWriteTextLayout **layout)
5348 struct dwrite_textlayout *object;
5349 HRESULT hr;
5351 *layout = NULL;
5353 if (desc->max_width < 0.0f || desc->max_height < 0.0f)
5354 return E_INVALIDARG;
5356 if (!desc->format || !desc->string)
5357 return E_INVALIDARG;
5359 if (!(object = calloc(1, sizeof(*object))))
5360 return E_OUTOFMEMORY;
5362 hr = init_textlayout(desc, object);
5363 if (hr == S_OK)
5364 *layout = (IDWriteTextLayout *)&object->IDWriteTextLayout4_iface;
5366 return hr;
5369 static HRESULT WINAPI dwritetypography_QueryInterface(IDWriteTypography *iface, REFIID riid, void **obj)
5371 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5373 if (IsEqualIID(riid, &IID_IDWriteTypography) || IsEqualIID(riid, &IID_IUnknown)) {
5374 *obj = iface;
5375 IDWriteTypography_AddRef(iface);
5376 return S_OK;
5379 WARN("%s not implemented.\n", debugstr_guid(riid));
5381 *obj = NULL;
5383 return E_NOINTERFACE;
5386 static ULONG WINAPI dwritetypography_AddRef(IDWriteTypography *iface)
5388 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5389 ULONG refcount = InterlockedIncrement(&typography->refcount);
5391 TRACE("%p, refcount %ld.\n", iface, refcount);
5393 return refcount;
5396 static ULONG WINAPI dwritetypography_Release(IDWriteTypography *iface)
5398 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5399 ULONG refcount = InterlockedDecrement(&typography->refcount);
5401 TRACE("%p, refcount %ld.\n", iface, refcount);
5403 if (!refcount)
5405 free(typography->features);
5406 free(typography);
5409 return refcount;
5412 static HRESULT WINAPI dwritetypography_AddFontFeature(IDWriteTypography *iface, DWRITE_FONT_FEATURE feature)
5414 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5416 TRACE("%p, %s, %u.\n", iface, debugstr_tag(feature.nameTag), feature.parameter);
5418 if (!dwrite_array_reserve((void **)&typography->features, &typography->capacity, typography->count + 1,
5419 sizeof(*typography->features)))
5421 return E_OUTOFMEMORY;
5424 typography->features[typography->count++] = feature;
5426 return S_OK;
5429 static UINT32 WINAPI dwritetypography_GetFontFeatureCount(IDWriteTypography *iface)
5431 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5433 TRACE("%p.\n", iface);
5435 return typography->count;
5438 static HRESULT WINAPI dwritetypography_GetFontFeature(IDWriteTypography *iface, UINT32 index,
5439 DWRITE_FONT_FEATURE *feature)
5441 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5443 TRACE("%p, %u, %p.\n", iface, index, feature);
5445 if (index >= typography->count)
5446 return E_INVALIDARG;
5448 *feature = typography->features[index];
5449 return S_OK;
5452 static const IDWriteTypographyVtbl dwritetypographyvtbl = {
5453 dwritetypography_QueryInterface,
5454 dwritetypography_AddRef,
5455 dwritetypography_Release,
5456 dwritetypography_AddFontFeature,
5457 dwritetypography_GetFontFeatureCount,
5458 dwritetypography_GetFontFeature
5461 HRESULT create_typography(IDWriteTypography **ret)
5463 struct dwrite_typography *typography;
5465 *ret = NULL;
5467 if (!(typography = calloc(1, sizeof(*typography))))
5468 return E_OUTOFMEMORY;
5470 typography->IDWriteTypography_iface.lpVtbl = &dwritetypographyvtbl;
5471 typography->refcount = 1;
5473 *ret = &typography->IDWriteTypography_iface;
5475 return S_OK;