user32/tests: Fix test_listbox_messages() message sequences to support WinEvents.
[wine.git] / dlls / dwrite / layout.c
blob26744e1b303c29ccf1ea862690773f9972dc2ce3
1 /*
2 * Text format and layout
4 * Copyright 2012, 2014-2021 Nikolay Sivov for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <math.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "dwrite_private.h"
31 #include "scripts.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
35 struct dwrite_textformat_data
37 WCHAR *family_name;
38 UINT32 family_len;
39 WCHAR *locale;
40 UINT32 locale_len;
42 DWRITE_FONT_WEIGHT weight;
43 DWRITE_FONT_STYLE style;
44 DWRITE_FONT_STRETCH stretch;
46 DWRITE_PARAGRAPH_ALIGNMENT paralign;
47 DWRITE_READING_DIRECTION readingdir;
48 DWRITE_WORD_WRAPPING wrapping;
49 BOOL last_line_wrapping;
50 DWRITE_TEXT_ALIGNMENT textalignment;
51 DWRITE_FLOW_DIRECTION flow;
52 DWRITE_VERTICAL_GLYPH_ORIENTATION vertical_orientation;
53 DWRITE_OPTICAL_ALIGNMENT optical_alignment;
54 DWRITE_LINE_SPACING spacing;
55 DWRITE_AUTOMATIC_FONT_AXES automatic_axes;
57 FLOAT fontsize;
58 FLOAT tabstop;
60 DWRITE_TRIMMING trimming;
61 IDWriteInlineObject *trimmingsign;
63 IDWriteFontCollection *collection;
64 IDWriteFontFallback *fallback;
66 DWRITE_FONT_AXIS_VALUE *axis_values;
67 unsigned int axis_values_count;
70 enum layout_range_attr_kind {
71 LAYOUT_RANGE_ATTR_WEIGHT,
72 LAYOUT_RANGE_ATTR_STYLE,
73 LAYOUT_RANGE_ATTR_STRETCH,
74 LAYOUT_RANGE_ATTR_FONTSIZE,
75 LAYOUT_RANGE_ATTR_EFFECT,
76 LAYOUT_RANGE_ATTR_INLINE,
77 LAYOUT_RANGE_ATTR_UNDERLINE,
78 LAYOUT_RANGE_ATTR_STRIKETHROUGH,
79 LAYOUT_RANGE_ATTR_PAIR_KERNING,
80 LAYOUT_RANGE_ATTR_FONTCOLL,
81 LAYOUT_RANGE_ATTR_LOCALE,
82 LAYOUT_RANGE_ATTR_FONTFAMILY,
83 LAYOUT_RANGE_ATTR_SPACING,
84 LAYOUT_RANGE_ATTR_TYPOGRAPHY
87 struct layout_range_attr_value {
88 DWRITE_TEXT_RANGE range;
89 union {
90 DWRITE_FONT_WEIGHT weight;
91 DWRITE_FONT_STYLE style;
92 DWRITE_FONT_STRETCH stretch;
93 FLOAT fontsize;
94 IDWriteInlineObject *object;
95 IUnknown *effect;
96 BOOL underline;
97 BOOL strikethrough;
98 BOOL pair_kerning;
99 IDWriteFontCollection *collection;
100 const WCHAR *locale;
101 const WCHAR *fontfamily;
102 struct {
103 FLOAT leading;
104 FLOAT trailing;
105 FLOAT min_advance;
106 } spacing;
107 IDWriteTypography *typography;
108 } u;
111 enum layout_range_kind {
112 LAYOUT_RANGE_REGULAR,
113 LAYOUT_RANGE_UNDERLINE,
114 LAYOUT_RANGE_STRIKETHROUGH,
115 LAYOUT_RANGE_EFFECT,
116 LAYOUT_RANGE_SPACING,
117 LAYOUT_RANGE_TYPOGRAPHY
120 struct layout_range_header {
121 struct list entry;
122 enum layout_range_kind kind;
123 DWRITE_TEXT_RANGE range;
126 struct layout_range {
127 struct layout_range_header h;
128 DWRITE_FONT_WEIGHT weight;
129 DWRITE_FONT_STYLE style;
130 FLOAT fontsize;
131 DWRITE_FONT_STRETCH stretch;
132 IDWriteInlineObject *object;
133 BOOL pair_kerning;
134 IDWriteFontCollection *collection;
135 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
136 WCHAR *fontfamily;
139 struct layout_range_bool {
140 struct layout_range_header h;
141 BOOL value;
144 struct layout_range_iface {
145 struct layout_range_header h;
146 IUnknown *iface;
149 struct layout_range_spacing {
150 struct layout_range_header h;
151 FLOAT leading;
152 FLOAT trailing;
153 FLOAT min_advance;
156 enum layout_run_kind {
157 LAYOUT_RUN_REGULAR,
158 LAYOUT_RUN_INLINE
161 struct inline_object_run {
162 IDWriteInlineObject *object;
163 UINT16 length;
166 struct regular_layout_run {
167 DWRITE_GLYPH_RUN_DESCRIPTION descr;
168 DWRITE_GLYPH_RUN run;
169 DWRITE_SCRIPT_ANALYSIS sa;
170 UINT16 *glyphs;
171 UINT16 *clustermap;
172 FLOAT *advances;
173 DWRITE_GLYPH_OFFSET *offsets;
174 UINT32 glyphcount; /* actual glyph count after shaping, not necessarily the same as reported to Draw() */
177 struct layout_run
179 struct list entry;
180 enum layout_run_kind kind;
181 union
183 struct inline_object_run object;
184 struct regular_layout_run regular;
185 } u;
186 float baseline;
187 float height;
188 unsigned int start_position; /* run text position in range [0, layout-text-length) */
191 struct layout_effective_run {
192 struct list entry;
193 const struct layout_run *run; /* nominal run this one is based on */
194 UINT32 start; /* relative text position, 0 means first text position of a nominal run */
195 UINT32 length; /* length in codepoints that this run covers */
196 UINT32 glyphcount; /* total glyph count in this run */
197 IUnknown *effect; /* original reference is kept only at range level */
198 D2D1_POINT_2F origin; /* baseline origin */
199 FLOAT align_dx; /* adjustment from text alignment */
200 FLOAT width; /* run width */
201 UINT16 *clustermap; /* effective clustermap, allocated separately, is not reused from nominal map */
202 UINT32 line; /* 0-based line index in line metrics array */
203 BOOL underlined; /* set if this run is underlined */
204 D2D1_RECT_F bbox; /* ink run box, top == bottom means it wasn't estimated yet */
207 struct layout_effective_inline {
208 struct list entry;
209 IDWriteInlineObject *object; /* inline object, set explicitly or added when trimming a line */
210 IUnknown *effect; /* original reference is kept only at range level */
211 FLOAT baseline;
212 D2D1_POINT_2F origin; /* left top corner */
213 FLOAT align_dx; /* adjustment from text alignment */
214 FLOAT width; /* object width as it's reported it */
215 BOOL is_sideways; /* vertical flow direction flag passed to Draw */
216 BOOL is_rtl; /* bidi flag passed to Draw */
217 UINT32 line; /* 0-based line index in line metrics array */
220 struct layout_underline {
221 struct list entry;
222 const struct layout_effective_run *run;
223 DWRITE_UNDERLINE u;
226 struct layout_strikethrough {
227 struct list entry;
228 const struct layout_effective_run *run;
229 DWRITE_STRIKETHROUGH s;
232 struct layout_cluster {
233 const struct layout_run *run; /* link to nominal run this cluster belongs to */
234 UINT32 position; /* relative to run, first cluster has 0 position */
237 struct layout_line
239 float height; /* height based on content */
240 float baseline; /* baseline based on content */
241 DWRITE_LINE_METRICS1 metrics;
244 enum layout_recompute_mask {
245 RECOMPUTE_CLUSTERS = 1 << 0,
246 RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
247 RECOMPUTE_LINES = 1 << 2,
248 RECOMPUTE_OVERHANGS = 1 << 3,
249 RECOMPUTE_LINES_AND_OVERHANGS = RECOMPUTE_LINES | RECOMPUTE_OVERHANGS,
250 RECOMPUTE_EVERYTHING = 0xffff
253 struct dwrite_textlayout
255 IDWriteTextLayout4 IDWriteTextLayout4_iface;
256 IDWriteTextFormat3 IDWriteTextFormat3_iface;
257 IDWriteTextAnalysisSink1 IDWriteTextAnalysisSink1_iface;
258 IDWriteTextAnalysisSource1 IDWriteTextAnalysisSource1_iface;
259 LONG refcount;
261 IDWriteFactory7 *factory;
263 WCHAR *str;
264 UINT32 len;
265 struct dwrite_textformat_data format;
266 struct list strike_ranges;
267 struct list underline_ranges;
268 struct list typographies;
269 struct list effects;
270 struct list spacing;
271 struct list ranges;
272 struct list runs;
273 /* lists ready to use by Draw() */
274 struct list eruns;
275 struct list inlineobjects;
276 struct list underlines;
277 struct list strikethrough;
278 USHORT recompute;
280 DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
281 DWRITE_LINE_BREAKPOINT *actual_breakpoints;
283 struct layout_cluster *clusters;
284 DWRITE_CLUSTER_METRICS *clustermetrics;
285 UINT32 cluster_count;
286 FLOAT minwidth;
288 struct layout_line *lines;
289 size_t lines_size;
291 DWRITE_TEXT_METRICS1 metrics;
292 DWRITE_OVERHANG_METRICS overhangs;
294 DWRITE_MEASURING_MODE measuringmode;
296 /* gdi-compatible layout specifics */
297 FLOAT ppdip;
298 DWRITE_MATRIX transform;
301 struct dwrite_textformat
303 IDWriteTextFormat3 IDWriteTextFormat3_iface;
304 LONG refcount;
305 struct dwrite_textformat_data format;
308 struct dwrite_trimmingsign
310 IDWriteInlineObject IDWriteInlineObject_iface;
311 LONG refcount;
313 IDWriteTextLayout *layout;
316 struct dwrite_typography {
317 IDWriteTypography IDWriteTypography_iface;
318 LONG refcount;
320 DWRITE_FONT_FEATURE *features;
321 size_t capacity;
322 size_t count;
325 static const IDWriteTextFormat3Vtbl dwritetextformatvtbl;
327 static void release_format_data(struct dwrite_textformat_data *data)
329 if (data->collection) IDWriteFontCollection_Release(data->collection);
330 if (data->fallback) IDWriteFontFallback_Release(data->fallback);
331 if (data->trimmingsign) IDWriteInlineObject_Release(data->trimmingsign);
332 heap_free(data->family_name);
333 heap_free(data->locale);
334 heap_free(data->axis_values);
337 static inline struct dwrite_textlayout *impl_from_IDWriteTextLayout4(IDWriteTextLayout4 *iface)
339 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextLayout4_iface);
342 static inline struct dwrite_textlayout *impl_layout_from_IDWriteTextFormat3(IDWriteTextFormat3 *iface)
344 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextFormat3_iface);
347 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSink1(IDWriteTextAnalysisSink1 *iface)
349 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSink1_iface);
352 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSource1(IDWriteTextAnalysisSource1 *iface)
354 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSource1_iface);
357 static inline struct dwrite_textformat *impl_from_IDWriteTextFormat3(IDWriteTextFormat3 *iface)
359 return CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat3_iface);
362 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat*);
364 static inline struct dwrite_trimmingsign *impl_from_IDWriteInlineObject(IDWriteInlineObject *iface)
366 return CONTAINING_RECORD(iface, struct dwrite_trimmingsign, IDWriteInlineObject_iface);
369 static inline struct dwrite_typography *impl_from_IDWriteTypography(IDWriteTypography *iface)
371 return CONTAINING_RECORD(iface, struct dwrite_typography, IDWriteTypography_iface);
374 static inline const char *debugstr_rundescr(const DWRITE_GLYPH_RUN_DESCRIPTION *descr)
376 return wine_dbg_sprintf("[%u,%u)", descr->textPosition, descr->textPosition + descr->stringLength);
379 static inline BOOL is_layout_gdi_compatible(struct dwrite_textlayout *layout)
381 return layout->measuringmode != DWRITE_MEASURING_MODE_NATURAL;
384 static inline HRESULT format_set_textalignment(struct dwrite_textformat_data *format, DWRITE_TEXT_ALIGNMENT alignment,
385 BOOL *changed)
387 if ((UINT32)alignment > DWRITE_TEXT_ALIGNMENT_JUSTIFIED)
388 return E_INVALIDARG;
389 if (changed) *changed = format->textalignment != alignment;
390 format->textalignment = alignment;
391 return S_OK;
394 static inline HRESULT format_set_paralignment(struct dwrite_textformat_data *format,
395 DWRITE_PARAGRAPH_ALIGNMENT alignment, BOOL *changed)
397 if ((UINT32)alignment > DWRITE_PARAGRAPH_ALIGNMENT_CENTER)
398 return E_INVALIDARG;
399 if (changed) *changed = format->paralign != alignment;
400 format->paralign = alignment;
401 return S_OK;
404 static inline HRESULT format_set_readingdirection(struct dwrite_textformat_data *format,
405 DWRITE_READING_DIRECTION direction, BOOL *changed)
407 if ((UINT32)direction > DWRITE_READING_DIRECTION_BOTTOM_TO_TOP)
408 return E_INVALIDARG;
409 if (changed) *changed = format->readingdir != direction;
410 format->readingdir = direction;
411 return S_OK;
414 static inline HRESULT format_set_wordwrapping(struct dwrite_textformat_data *format,
415 DWRITE_WORD_WRAPPING wrapping, BOOL *changed)
417 if ((UINT32)wrapping > DWRITE_WORD_WRAPPING_CHARACTER)
418 return E_INVALIDARG;
419 if (changed) *changed = format->wrapping != wrapping;
420 format->wrapping = wrapping;
421 return S_OK;
424 static inline HRESULT format_set_flowdirection(struct dwrite_textformat_data *format,
425 DWRITE_FLOW_DIRECTION direction, BOOL *changed)
427 if ((UINT32)direction > DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT)
428 return E_INVALIDARG;
429 if (changed) *changed = format->flow != direction;
430 format->flow = direction;
431 return S_OK;
434 static inline HRESULT format_set_trimming(struct dwrite_textformat_data *format,
435 DWRITE_TRIMMING const *trimming, IDWriteInlineObject *trimming_sign, BOOL *changed)
437 if (changed)
438 *changed = FALSE;
440 if ((UINT32)trimming->granularity > DWRITE_TRIMMING_GRANULARITY_WORD)
441 return E_INVALIDARG;
443 if (changed) {
444 *changed = !!memcmp(&format->trimming, trimming, sizeof(*trimming));
445 if (format->trimmingsign != trimming_sign)
446 *changed = TRUE;
449 format->trimming = *trimming;
450 if (format->trimmingsign)
451 IDWriteInlineObject_Release(format->trimmingsign);
452 format->trimmingsign = trimming_sign;
453 if (format->trimmingsign)
454 IDWriteInlineObject_AddRef(format->trimmingsign);
455 return S_OK;
458 static inline HRESULT format_set_linespacing(struct dwrite_textformat_data *format,
459 DWRITE_LINE_SPACING const *spacing, BOOL *changed)
461 if (spacing->height < 0.0f || spacing->leadingBefore < 0.0f || spacing->leadingBefore > 1.0f ||
462 (UINT32)spacing->method > DWRITE_LINE_SPACING_METHOD_PROPORTIONAL)
463 return E_INVALIDARG;
465 if (changed)
466 *changed = memcmp(spacing, &format->spacing, sizeof(*spacing));
468 format->spacing = *spacing;
469 return S_OK;
472 static HRESULT format_set_font_axisvalues(struct dwrite_textformat_data *format,
473 DWRITE_FONT_AXIS_VALUE const *axis_values, unsigned int num_values)
475 heap_free(format->axis_values);
476 format->axis_values = NULL;
477 format->axis_values_count = 0;
479 if (num_values)
481 if (!(format->axis_values = heap_calloc(num_values, sizeof(*axis_values))))
482 return E_OUTOFMEMORY;
483 memcpy(format->axis_values, axis_values, num_values * sizeof(*axis_values));
484 format->axis_values_count = num_values;
487 return S_OK;
490 static HRESULT format_get_font_axisvalues(struct dwrite_textformat_data *format,
491 DWRITE_FONT_AXIS_VALUE *axis_values, unsigned int num_values)
493 if (!format->axis_values_count)
495 if (num_values) memset(axis_values, 0, num_values * sizeof(*axis_values));
496 return S_OK;
499 if (num_values < format->axis_values_count)
500 return E_NOT_SUFFICIENT_BUFFER;
502 memcpy(axis_values, format->axis_values, min(num_values, format->axis_values_count) * sizeof(*axis_values));
504 return S_OK;
507 static HRESULT get_fontfallback_from_format(const struct dwrite_textformat_data *format, IDWriteFontFallback **fallback)
509 *fallback = format->fallback;
510 if (*fallback)
511 IDWriteFontFallback_AddRef(*fallback);
512 return S_OK;
515 static HRESULT set_fontfallback_for_format(struct dwrite_textformat_data *format, IDWriteFontFallback *fallback)
517 if (format->fallback)
518 IDWriteFontFallback_Release(format->fallback);
519 format->fallback = fallback;
520 if (fallback)
521 IDWriteFontFallback_AddRef(fallback);
522 return S_OK;
525 static HRESULT format_set_optical_alignment(struct dwrite_textformat_data *format,
526 DWRITE_OPTICAL_ALIGNMENT alignment)
528 if ((UINT32)alignment > DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS)
529 return E_INVALIDARG;
530 format->optical_alignment = alignment;
531 return S_OK;
534 static HRESULT format_set_vertical_orientation(struct dwrite_textformat_data *format,
535 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation, BOOL *changed)
537 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
538 return E_INVALIDARG;
540 if (changed)
541 *changed = format->vertical_orientation != orientation;
543 format->vertical_orientation = orientation;
544 return S_OK;
547 static BOOL is_run_rtl(const struct layout_effective_run *run)
549 return run->run->u.regular.run.bidiLevel & 1;
552 static HRESULT alloc_layout_run(enum layout_run_kind kind, unsigned int start_position,
553 struct layout_run **run)
555 if (!(*run = heap_alloc_zero(sizeof(**run))))
556 return E_OUTOFMEMORY;
558 (*run)->kind = kind;
559 (*run)->start_position = start_position;
561 return S_OK;
564 static void free_layout_runs(struct dwrite_textlayout *layout)
566 struct layout_run *cur, *cur2;
567 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->runs, struct layout_run, entry) {
568 list_remove(&cur->entry);
569 if (cur->kind == LAYOUT_RUN_REGULAR) {
570 if (cur->u.regular.run.fontFace)
571 IDWriteFontFace_Release(cur->u.regular.run.fontFace);
572 heap_free(cur->u.regular.glyphs);
573 heap_free(cur->u.regular.clustermap);
574 heap_free(cur->u.regular.advances);
575 heap_free(cur->u.regular.offsets);
577 heap_free(cur);
581 static void free_layout_eruns(struct dwrite_textlayout *layout)
583 struct layout_effective_inline *in, *in2;
584 struct layout_effective_run *cur, *cur2;
585 struct layout_strikethrough *s, *s2;
586 struct layout_underline *u, *u2;
588 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->eruns, struct layout_effective_run, entry) {
589 list_remove(&cur->entry);
590 heap_free(cur->clustermap);
591 heap_free(cur);
594 LIST_FOR_EACH_ENTRY_SAFE(in, in2, &layout->inlineobjects, struct layout_effective_inline, entry) {
595 list_remove(&in->entry);
596 heap_free(in);
599 LIST_FOR_EACH_ENTRY_SAFE(u, u2, &layout->underlines, struct layout_underline, entry) {
600 list_remove(&u->entry);
601 heap_free(u);
604 LIST_FOR_EACH_ENTRY_SAFE(s, s2, &layout->strikethrough, struct layout_strikethrough, entry) {
605 list_remove(&s->entry);
606 heap_free(s);
610 /* Used to resolve break condition by forcing stronger condition over weaker. */
611 static inline DWRITE_BREAK_CONDITION override_break_condition(DWRITE_BREAK_CONDITION existingbreak, DWRITE_BREAK_CONDITION newbreak)
613 switch (existingbreak) {
614 case DWRITE_BREAK_CONDITION_NEUTRAL:
615 return newbreak;
616 case DWRITE_BREAK_CONDITION_CAN_BREAK:
617 return newbreak == DWRITE_BREAK_CONDITION_NEUTRAL ? existingbreak : newbreak;
618 /* let's keep stronger conditions as is */
619 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK:
620 case DWRITE_BREAK_CONDITION_MUST_BREAK:
621 break;
622 default:
623 ERR("unknown break condition %d\n", existingbreak);
626 return existingbreak;
629 /* This helper should be used to get effective range length, in other words it returns number of text
630 positions from range starting point to the end of the range, limited by layout text length */
631 static inline UINT32 get_clipped_range_length(const struct dwrite_textlayout *layout, const struct layout_range *range)
633 if (range->h.range.startPosition + range->h.range.length <= layout->len)
634 return range->h.range.length;
635 return layout->len - range->h.range.startPosition;
638 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
639 static HRESULT layout_update_breakpoints_range(struct dwrite_textlayout *layout, const struct layout_range *cur)
641 DWRITE_BREAK_CONDITION before, after;
642 UINT32 i, length;
643 HRESULT hr;
645 /* ignore returned conditions if failed */
646 hr = IDWriteInlineObject_GetBreakConditions(cur->object, &before, &after);
647 if (FAILED(hr))
648 after = before = DWRITE_BREAK_CONDITION_NEUTRAL;
650 if (!layout->actual_breakpoints) {
651 layout->actual_breakpoints = heap_calloc(layout->len, sizeof(*layout->actual_breakpoints));
652 if (!layout->actual_breakpoints)
653 return E_OUTOFMEMORY;
654 memcpy(layout->actual_breakpoints, layout->nominal_breakpoints, sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
657 length = get_clipped_range_length(layout, cur);
658 for (i = cur->h.range.startPosition; i < length + cur->h.range.startPosition; i++) {
659 /* for first codepoint check if there's anything before it and update accordingly */
660 if (i == cur->h.range.startPosition) {
661 if (i > 0)
662 layout->actual_breakpoints[i].breakConditionBefore = layout->actual_breakpoints[i-1].breakConditionAfter =
663 override_break_condition(layout->actual_breakpoints[i-1].breakConditionAfter, before);
664 else
665 layout->actual_breakpoints[i].breakConditionBefore = before;
666 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
668 /* similar check for last codepoint */
669 else if (i == cur->h.range.startPosition + length - 1) {
670 if (i == layout->len - 1)
671 layout->actual_breakpoints[i].breakConditionAfter = after;
672 else
673 layout->actual_breakpoints[i].breakConditionAfter = layout->actual_breakpoints[i+1].breakConditionBefore =
674 override_break_condition(layout->actual_breakpoints[i+1].breakConditionBefore, after);
675 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
677 /* for all positions within a range disable breaks */
678 else {
679 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
680 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
683 layout->actual_breakpoints[i].isWhitespace = 0;
684 layout->actual_breakpoints[i].isSoftHyphen = 0;
687 return S_OK;
690 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos)
692 struct layout_range *cur;
694 LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, h.entry)
696 DWRITE_TEXT_RANGE *r = &cur->h.range;
697 if (r->startPosition <= pos && pos < r->startPosition + r->length)
698 return cur;
701 return NULL;
704 static struct layout_range_header *get_layout_range_header_by_pos(struct list *ranges, UINT32 pos)
706 struct layout_range_header *cur;
708 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry)
710 DWRITE_TEXT_RANGE *r = &cur->range;
711 if (r->startPosition <= pos && pos < r->startPosition + r->length)
712 return cur;
715 return NULL;
718 static inline DWRITE_LINE_BREAKPOINT get_effective_breakpoint(const struct dwrite_textlayout *layout, UINT32 pos)
720 if (layout->actual_breakpoints)
721 return layout->actual_breakpoints[pos];
722 return layout->nominal_breakpoints[pos];
725 static inline void init_cluster_metrics(const struct dwrite_textlayout *layout, const struct regular_layout_run *run,
726 UINT16 start_glyph, UINT16 stop_glyph, UINT32 stop_position, UINT16 length, DWRITE_CLUSTER_METRICS *metrics)
728 UINT8 breakcondition;
729 UINT32 position;
730 UINT16 j;
732 /* For clusters made of control chars we report zero glyphs, and we need zero cluster
733 width as well; advances are already computed at this point and are not necessary zero. */
734 metrics->width = 0.0f;
735 if (run->run.glyphCount) {
736 for (j = start_glyph; j < stop_glyph; j++)
737 metrics->width += run->run.glyphAdvances[j];
739 metrics->length = length;
741 position = run->descr.textPosition + stop_position;
742 if (stop_glyph == run->glyphcount)
743 breakcondition = get_effective_breakpoint(layout, position).breakConditionAfter;
744 else {
745 breakcondition = get_effective_breakpoint(layout, position).breakConditionBefore;
746 if (stop_position) position -= 1;
749 metrics->canWrapLineAfter = breakcondition == DWRITE_BREAK_CONDITION_CAN_BREAK ||
750 breakcondition == DWRITE_BREAK_CONDITION_MUST_BREAK;
751 if (metrics->length == 1) {
752 DWRITE_LINE_BREAKPOINT bp = get_effective_breakpoint(layout, position);
753 metrics->isWhitespace = bp.isWhitespace;
754 metrics->isNewline = metrics->canWrapLineAfter && lb_is_newline_char(layout->str[position]);
755 metrics->isSoftHyphen = bp.isSoftHyphen;
757 else {
758 metrics->isWhitespace = 0;
759 metrics->isNewline = 0;
760 metrics->isSoftHyphen = 0;
762 metrics->isRightToLeft = run->run.bidiLevel & 1;
763 metrics->padding = 0;
768 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
769 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
770 Note that there's no need to reallocate anything at this point as we allocate one cluster per
771 codepoint initially.
774 static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 *cluster)
776 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[*cluster];
777 struct layout_cluster *c = &layout->clusters[*cluster];
778 const struct regular_layout_run *run = &r->u.regular;
779 UINT32 i, start = 0;
781 assert(r->kind == LAYOUT_RUN_REGULAR);
783 for (i = 0; i < run->descr.stringLength; i++) {
784 BOOL end = i == run->descr.stringLength - 1;
786 if (run->descr.clusterMap[start] != run->descr.clusterMap[i]) {
787 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->descr.clusterMap[i], i,
788 i - start, metrics);
789 c->position = start;
790 c->run = r;
792 *cluster += 1;
793 metrics++;
794 c++;
795 start = i;
798 if (end) {
799 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->glyphcount, i,
800 i - start + 1, metrics);
801 c->position = start;
802 c->run = r;
804 *cluster += 1;
805 return;
810 #define SCALE_FONT_METRIC(metric, emSize, metrics) ((FLOAT)(metric) * (emSize) / (FLOAT)(metrics)->designUnitsPerEm)
812 static void layout_get_font_metrics(struct dwrite_textlayout *layout, IDWriteFontFace *fontface, FLOAT emsize,
813 DWRITE_FONT_METRICS *fontmetrics)
815 if (is_layout_gdi_compatible(layout)) {
816 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(fontface, emsize, layout->ppdip, &layout->transform, fontmetrics);
817 if (FAILED(hr))
818 WARN("failed to get compat metrics, 0x%08x\n", hr);
820 else
821 IDWriteFontFace_GetMetrics(fontface, fontmetrics);
824 static void layout_get_font_height(FLOAT emsize, DWRITE_FONT_METRICS *fontmetrics, FLOAT *baseline, FLOAT *height)
826 *baseline = SCALE_FONT_METRIC(fontmetrics->ascent + fontmetrics->lineGap, emsize, fontmetrics);
827 *height = SCALE_FONT_METRIC(fontmetrics->ascent + fontmetrics->descent + fontmetrics->lineGap, emsize, fontmetrics);
830 static HRESULT layout_itemize(struct dwrite_textlayout *layout)
832 IDWriteTextAnalyzer2 *analyzer;
833 struct layout_range *range;
834 struct layout_run *r;
835 HRESULT hr = S_OK;
837 analyzer = get_text_analyzer();
839 LIST_FOR_EACH_ENTRY(range, &layout->ranges, struct layout_range, h.entry) {
840 /* We don't care about ranges that don't contain any text. */
841 if (range->h.range.startPosition >= layout->len)
842 break;
844 /* Inline objects override actual text in range. */
845 if (range->object) {
846 hr = layout_update_breakpoints_range(layout, range);
847 if (FAILED(hr))
848 return hr;
850 if (FAILED(hr = alloc_layout_run(LAYOUT_RUN_INLINE, range->h.range.startPosition, &r)))
851 return hr;
853 r->u.object.object = range->object;
854 r->u.object.length = get_clipped_range_length(layout, range);
855 list_add_tail(&layout->runs, &r->entry);
856 continue;
859 /* Initial splitting by script. */
860 hr = IDWriteTextAnalyzer2_AnalyzeScript(analyzer, (IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
861 range->h.range.startPosition, get_clipped_range_length(layout, range),
862 (IDWriteTextAnalysisSink *)&layout->IDWriteTextAnalysisSink1_iface);
863 if (FAILED(hr))
864 break;
866 /* Splitting further by bidi levels. */
867 hr = IDWriteTextAnalyzer2_AnalyzeBidi(analyzer, (IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
868 range->h.range.startPosition, get_clipped_range_length(layout, range),
869 (IDWriteTextAnalysisSink *)&layout->IDWriteTextAnalysisSink1_iface);
870 if (FAILED(hr))
871 break;
874 return hr;
877 static HRESULT layout_resolve_fonts(struct dwrite_textlayout *layout)
879 IDWriteFontCollection *sys_collection;
880 IDWriteFontFallback *fallback = NULL;
881 struct layout_range *range;
882 struct layout_run *r;
883 HRESULT hr;
885 if (FAILED(hr = IDWriteFactory5_GetSystemFontCollection((IDWriteFactory5 *)layout->factory, FALSE,
886 (IDWriteFontCollection1 **)&sys_collection, FALSE))) {
887 WARN("Failed to get system collection, hr %#x.\n", hr);
888 return hr;
891 if (layout->format.fallback) {
892 fallback = layout->format.fallback;
893 IDWriteFontFallback_AddRef(fallback);
895 else {
896 if (FAILED(hr = IDWriteFactory7_GetSystemFontFallback(layout->factory, &fallback))) {
897 WARN("Failed to get system fallback, hr %#x.\n", hr);
898 goto fatal;
902 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
903 struct regular_layout_run *run = &r->u.regular;
904 IDWriteFont *font;
905 UINT32 length;
907 if (r->kind == LAYOUT_RUN_INLINE)
908 continue;
910 range = get_layout_range_by_pos(layout, run->descr.textPosition);
912 if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL) {
913 IDWriteFontCollection *collection;
915 collection = range->collection ? range->collection : sys_collection;
917 if (FAILED(hr = create_matching_font(collection, range->fontfamily, range->weight, range->style,
918 range->stretch, &font))) {
919 WARN("%s: failed to create matching font for non visual run, family %s, collection %p\n",
920 debugstr_rundescr(&run->descr), debugstr_w(range->fontfamily), range->collection);
921 break;
924 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
925 IDWriteFont_Release(font);
926 if (FAILED(hr)) {
927 WARN("Failed to create font face, hr %#x.\n", hr);
928 break;
931 run->run.fontEmSize = range->fontsize;
932 continue;
935 length = run->descr.stringLength;
937 while (length) {
938 UINT32 mapped_length;
939 FLOAT scale;
941 run = &r->u.regular;
943 hr = IDWriteFontFallback_MapCharacters(fallback,
944 (IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
945 run->descr.textPosition,
946 run->descr.stringLength,
947 range->collection,
948 range->fontfamily,
949 range->weight,
950 range->style,
951 range->stretch,
952 &mapped_length,
953 &font,
954 &scale);
955 if (FAILED(hr)) {
956 WARN("%s: failed to map family %s, collection %p, hr %#x.\n", debugstr_rundescr(&run->descr),
957 debugstr_w(range->fontfamily), range->collection, hr);
958 goto fatal;
961 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
962 IDWriteFont_Release(font);
963 if (FAILED(hr)) {
964 WARN("Failed to create font face, hr %#x.\n", hr);
965 goto fatal;
968 run->run.fontEmSize = range->fontsize * scale;
970 if (mapped_length < length)
972 struct regular_layout_run *nextrun;
973 struct layout_run *nextr;
975 /* keep mapped part for current run, add another run for the rest */
976 if (FAILED(hr = alloc_layout_run(LAYOUT_RUN_REGULAR, 0, &nextr)))
977 goto fatal;
979 *nextr = *r;
980 nextr->start_position = run->descr.textPosition + mapped_length;
981 nextrun = &nextr->u.regular;
982 nextrun->descr.textPosition = nextr->start_position;
983 nextrun->descr.stringLength = run->descr.stringLength - mapped_length;
984 nextrun->descr.string = &layout->str[nextrun->descr.textPosition];
985 run->descr.stringLength = mapped_length;
986 list_add_after(&r->entry, &nextr->entry);
987 r = nextr;
990 length -= mapped_length;
994 fatal:
995 IDWriteFontCollection_Release(sys_collection);
996 if (fallback)
997 IDWriteFontFallback_Release(fallback);
999 return hr;
1002 struct shaping_context
1004 IDWriteTextAnalyzer2 *analyzer;
1005 struct regular_layout_run *run;
1006 DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props;
1007 DWRITE_SHAPING_TEXT_PROPERTIES *text_props;
1009 struct
1011 DWRITE_TYPOGRAPHIC_FEATURES **features;
1012 unsigned int *range_lengths;
1013 unsigned int range_count;
1014 } user_features;
1017 static void layout_shape_clear_user_features_context(struct shaping_context *context)
1019 unsigned int i;
1021 for (i = 0; i < context->user_features.range_count; ++i)
1023 heap_free(context->user_features.features[i]->features);
1024 heap_free(context->user_features.features[i]);
1026 heap_free(context->user_features.features);
1027 memset(&context->user_features, 0, sizeof(context->user_features));
1030 static void layout_shape_clear_context(struct shaping_context *context)
1032 layout_shape_clear_user_features_context(context);
1033 heap_free(context->glyph_props);
1034 heap_free(context->text_props);
1037 static HRESULT layout_shape_add_empty_user_features_range(struct shaping_context *context, unsigned int length)
1039 DWRITE_TYPOGRAPHIC_FEATURES *features;
1040 unsigned int r = context->user_features.range_count;
1042 if (!(context->user_features.features[r] = heap_alloc_zero(sizeof(*features))))
1043 return E_OUTOFMEMORY;
1045 context->user_features.range_lengths[r] = length;
1046 context->user_features.range_count++;
1048 return S_OK;
1051 static HRESULT layout_shape_get_user_features(struct dwrite_textlayout *layout, struct shaping_context *context)
1053 unsigned int i, f, start = 0, r, covered_length = 0, length, feature_count;
1054 struct regular_layout_run *run = context->run;
1055 DWRITE_TYPOGRAPHIC_FEATURES *features;
1056 struct layout_range_iface *range;
1057 IDWriteTypography *typography;
1058 HRESULT hr = E_OUTOFMEMORY;
1060 range = (struct layout_range_iface *)get_layout_range_header_by_pos(&layout->typographies, 0);
1061 if (range->h.range.length >= run->descr.stringLength && !range->iface)
1062 return S_OK;
1064 if (!(context->user_features.features = heap_calloc(run->descr.stringLength, sizeof(*context->user_features.features))))
1065 goto failed;
1066 if (!(context->user_features.range_lengths = heap_calloc(run->descr.stringLength, sizeof(*context->user_features.range_lengths))))
1067 goto failed;
1069 for (i = run->descr.textPosition; i < run->descr.textPosition + run->descr.stringLength; ++i)
1071 range = (struct layout_range_iface *)get_layout_range_header_by_pos(&layout->typographies, i);
1072 if (!range || !range->iface) continue;
1074 typography = (IDWriteTypography *)range->iface;
1075 feature_count = IDWriteTypography_GetFontFeatureCount(typography);
1076 if (!feature_count)
1078 i = range->h.range.length - i + 1;
1079 continue;
1082 if (start != i)
1084 if (FAILED(hr = layout_shape_add_empty_user_features_range(context, i - start))) goto failed;
1085 covered_length += i - start;
1086 start += range->h.range.length;
1089 r = context->user_features.range_count;
1090 if (!(features = context->user_features.features[r] = heap_alloc(sizeof(*features))))
1091 goto failed;
1093 context->user_features.range_lengths[r] = length = min(run->descr.textPosition + run->descr.stringLength,
1094 range->h.range.startPosition + range->h.range.length) - i;
1095 features->featureCount = feature_count;
1096 if (!(features->features = heap_calloc(feature_count, sizeof(*features->features))))
1097 goto failed;
1099 for (f = 0; f < feature_count; ++f)
1101 IDWriteTypography_GetFontFeature(typography, f, &features->features[f]);
1104 i += length;
1105 covered_length += length;
1106 context->user_features.range_count++;
1109 if (context->user_features.range_count && covered_length < run->descr.stringLength)
1111 if (FAILED(hr = layout_shape_add_empty_user_features_range(context, run->descr.stringLength - covered_length)))
1112 goto failed;
1115 hr = S_OK;
1117 failed:
1119 if (!context->user_features.range_count || FAILED(hr))
1120 layout_shape_clear_user_features_context(context);
1122 return hr;
1125 static HRESULT layout_shape_get_glyphs(struct dwrite_textlayout *layout, struct shaping_context *context)
1127 struct regular_layout_run *run = context->run;
1128 unsigned int max_count;
1129 HRESULT hr;
1131 run->descr.localeName = get_layout_range_by_pos(layout, run->descr.textPosition)->locale;
1132 run->clustermap = heap_calloc(run->descr.stringLength, sizeof(*run->clustermap));
1133 if (!run->clustermap)
1134 return E_OUTOFMEMORY;
1136 max_count = 3 * run->descr.stringLength / 2 + 16;
1137 run->glyphs = heap_calloc(max_count, sizeof(*run->glyphs));
1138 if (!run->glyphs)
1139 return E_OUTOFMEMORY;
1141 context->text_props = heap_calloc(run->descr.stringLength, sizeof(*context->text_props));
1142 context->glyph_props = heap_calloc(max_count, sizeof(*context->glyph_props));
1143 if (!context->text_props || !context->glyph_props)
1144 return E_OUTOFMEMORY;
1146 if (FAILED(hr = layout_shape_get_user_features(layout, context)))
1147 return hr;
1149 for (;;)
1151 hr = IDWriteTextAnalyzer2_GetGlyphs(context->analyzer, run->descr.string, run->descr.stringLength, run->run.fontFace,
1152 run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL /* FIXME */,
1153 (const DWRITE_TYPOGRAPHIC_FEATURES **)context->user_features.features, context->user_features.range_lengths,
1154 context->user_features.range_count, max_count, run->clustermap, context->text_props, run->glyphs,
1155 context->glyph_props, &run->glyphcount);
1156 if (hr == E_NOT_SUFFICIENT_BUFFER)
1158 heap_free(run->glyphs);
1159 heap_free(context->glyph_props);
1161 max_count *= 2;
1163 run->glyphs = heap_calloc(max_count, sizeof(*run->glyphs));
1164 context->glyph_props = heap_calloc(max_count, sizeof(*context->glyph_props));
1165 if (!run->glyphs || !context->glyph_props)
1167 hr = E_OUTOFMEMORY;
1168 break;
1171 continue;
1174 break;
1177 if (FAILED(hr))
1178 WARN("%s: shaping failed, hr %#x.\n", debugstr_rundescr(&run->descr), hr);
1180 run->run.glyphIndices = run->glyphs;
1181 run->descr.clusterMap = run->clustermap;
1183 return hr;
1186 static struct layout_range_spacing *layout_get_next_spacing_range(struct dwrite_textlayout *layout,
1187 struct layout_range_spacing *cur)
1189 return (struct layout_range_spacing *)LIST_ENTRY(list_next(&layout->spacing, &cur->h.entry),
1190 struct layout_range_header, entry);
1193 static HRESULT layout_shape_apply_character_spacing(struct dwrite_textlayout *layout, struct shaping_context *context)
1195 struct regular_layout_run *run = context->run;
1196 struct layout_range_spacing *first = NULL, *last = NULL, *cur;
1197 unsigned int i, length, pos, start, end, g0, glyph_count;
1198 struct layout_range_header *h;
1199 UINT16 *clustermap;
1201 LIST_FOR_EACH_ENTRY(h, &layout->spacing, struct layout_range_header, entry)
1203 if ((h->range.startPosition >= run->descr.textPosition &&
1204 h->range.startPosition <= run->descr.textPosition + run->descr.stringLength) ||
1205 (run->descr.textPosition >= h->range.startPosition &&
1206 run->descr.textPosition <= h->range.startPosition + h->range.length))
1208 if (!first) first = last = (struct layout_range_spacing *)h;
1210 else if (last) break;
1212 if (!first) return S_OK;
1214 if (!(clustermap = heap_calloc(run->descr.stringLength, sizeof(*clustermap)))) return E_OUTOFMEMORY;
1216 pos = run->descr.textPosition;
1218 for (cur = first;; cur = layout_get_next_spacing_range(layout, cur))
1220 float leading, trailing;
1222 /* The range current spacing settings apply to. */
1223 start = max(pos, cur->h.range.startPosition);
1224 pos = end = min(pos + run->descr.stringLength, cur->h.range.startPosition + cur->h.range.length);
1226 /* Back to run-relative index. */
1227 start -= run->descr.textPosition;
1228 end -= run->descr.textPosition;
1230 length = end - start;
1232 g0 = run->descr.clusterMap[start];
1234 for (i = 0; i < length; ++i)
1235 clustermap[i] = run->descr.clusterMap[start + i] - run->descr.clusterMap[start];
1237 glyph_count = (end < run->descr.stringLength ? run->descr.clusterMap[end] + 1 : run->glyphcount) - g0;
1239 /* There is no direction argument for spacing interface, we have to swap arguments here to get desired output. */
1240 if (run->run.bidiLevel & 1)
1242 leading = cur->trailing;
1243 trailing = cur->leading;
1245 else
1247 leading = cur->leading;
1248 trailing = cur->trailing;
1250 IDWriteTextAnalyzer2_ApplyCharacterSpacing(context->analyzer, leading, trailing, cur->min_advance,
1251 length, glyph_count, clustermap, &run->advances[g0], &run->offsets[g0], &context->glyph_props[g0],
1252 &run->advances[g0], &run->offsets[g0]);
1254 if (cur == last) break;
1257 heap_free(clustermap);
1259 return S_OK;
1262 static HRESULT layout_shape_get_positions(struct dwrite_textlayout *layout, struct shaping_context *context)
1264 struct regular_layout_run *run = context->run;
1265 HRESULT hr;
1267 run->advances = heap_calloc(run->glyphcount, sizeof(*run->advances));
1268 run->offsets = heap_calloc(run->glyphcount, sizeof(*run->offsets));
1269 if (!run->advances || !run->offsets)
1270 return E_OUTOFMEMORY;
1272 /* Get advances and offsets. */
1273 if (is_layout_gdi_compatible(layout))
1274 hr = IDWriteTextAnalyzer2_GetGdiCompatibleGlyphPlacements(context->analyzer, run->descr.string, run->descr.clusterMap,
1275 context->text_props, run->descr.stringLength, run->run.glyphIndices, context->glyph_props, run->glyphcount,
1276 run->run.fontFace, run->run.fontEmSize, layout->ppdip, &layout->transform,
1277 layout->measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->run.isSideways, run->run.bidiLevel & 1,
1278 &run->sa, run->descr.localeName, (const DWRITE_TYPOGRAPHIC_FEATURES **)context->user_features.features,
1279 context->user_features.range_lengths, context->user_features.range_count, run->advances, run->offsets);
1280 else
1281 hr = IDWriteTextAnalyzer2_GetGlyphPlacements(context->analyzer, run->descr.string, run->descr.clusterMap,
1282 context->text_props, run->descr.stringLength, run->run.glyphIndices, context->glyph_props, run->glyphcount,
1283 run->run.fontFace, run->run.fontEmSize, run->run.isSideways, run->run.bidiLevel & 1, &run->sa,
1284 run->descr.localeName, (const DWRITE_TYPOGRAPHIC_FEATURES **)context->user_features.features,
1285 context->user_features.range_lengths, context->user_features.range_count, run->advances, run->offsets);
1287 if (FAILED(hr))
1289 memset(run->advances, 0, run->glyphcount * sizeof(*run->advances));
1290 memset(run->offsets, 0, run->glyphcount * sizeof(*run->offsets));
1291 WARN("%s: failed to get glyph placement info, hr %#x.\n", debugstr_rundescr(&run->descr), hr);
1294 if (SUCCEEDED(hr))
1295 hr = layout_shape_apply_character_spacing(layout, context);
1297 run->run.glyphAdvances = run->advances;
1298 run->run.glyphOffsets = run->offsets;
1300 return hr;
1303 static HRESULT layout_shape_run(struct dwrite_textlayout *layout, struct regular_layout_run *run)
1305 struct shaping_context context = { 0 };
1306 HRESULT hr;
1308 context.analyzer = get_text_analyzer();
1309 context.run = run;
1311 if (SUCCEEDED(hr = layout_shape_get_glyphs(layout, &context)))
1312 hr = layout_shape_get_positions(layout, &context);
1314 layout_shape_clear_context(&context);
1316 /* Special treatment for runs that don't produce visual output, shaping code adds normal glyphs for them,
1317 with valid cluster map and potentially with non-zero advances; layout code exposes those as zero
1318 width clusters. */
1319 if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL)
1320 run->run.glyphCount = 0;
1321 else
1322 run->run.glyphCount = run->glyphcount;
1324 return hr;
1327 static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
1329 struct layout_run *r;
1330 UINT32 cluster = 0;
1331 HRESULT hr;
1333 free_layout_eruns(layout);
1334 free_layout_runs(layout);
1336 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
1337 if (!layout->clustermetrics && layout->len) {
1338 layout->clustermetrics = heap_calloc(layout->len, sizeof(*layout->clustermetrics));
1339 layout->clusters = heap_calloc(layout->len, sizeof(*layout->clusters));
1340 if (!layout->clustermetrics || !layout->clusters) {
1341 heap_free(layout->clustermetrics);
1342 heap_free(layout->clusters);
1343 return E_OUTOFMEMORY;
1346 layout->cluster_count = 0;
1348 if (FAILED(hr = layout_itemize(layout))) {
1349 WARN("Itemization failed, hr %#x.\n", hr);
1350 return hr;
1353 if (FAILED(hr = layout_resolve_fonts(layout))) {
1354 WARN("Failed to resolve layout fonts, hr %#x.\n", hr);
1355 return hr;
1358 /* fill run info */
1359 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
1360 struct regular_layout_run *run = &r->u.regular;
1361 DWRITE_FONT_METRICS fontmetrics = { 0 };
1363 /* we need to do very little in case of inline objects */
1364 if (r->kind == LAYOUT_RUN_INLINE) {
1365 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[cluster];
1366 struct layout_cluster *c = &layout->clusters[cluster];
1367 DWRITE_INLINE_OBJECT_METRICS inlinemetrics;
1369 metrics->width = 0.0f;
1370 metrics->length = r->u.object.length;
1371 metrics->canWrapLineAfter = 0;
1372 metrics->isWhitespace = 0;
1373 metrics->isNewline = 0;
1374 metrics->isSoftHyphen = 0;
1375 metrics->isRightToLeft = 0;
1376 metrics->padding = 0;
1377 c->run = r;
1378 c->position = 0; /* there's always one cluster per inline object, so 0 is valid value */
1379 cluster++;
1381 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
1382 hr = IDWriteInlineObject_GetMetrics(r->u.object.object, &inlinemetrics);
1383 if (FAILED(hr)) {
1384 memset(&inlinemetrics, 0, sizeof(inlinemetrics));
1385 hr = S_OK;
1387 metrics->width = inlinemetrics.width;
1388 r->baseline = inlinemetrics.baseline;
1389 r->height = inlinemetrics.height;
1391 /* FIXME: use resolved breakpoints in this case too */
1393 continue;
1396 if (FAILED(hr = layout_shape_run(layout, run)))
1397 WARN("%s: shaping failed, hr %#x.\n", debugstr_rundescr(&run->descr), hr);
1399 /* baseline derived from font metrics */
1400 layout_get_font_metrics(layout, run->run.fontFace, run->run.fontEmSize, &fontmetrics);
1401 layout_get_font_height(run->run.fontEmSize, &fontmetrics, &r->baseline, &r->height);
1403 layout_set_cluster_metrics(layout, r, &cluster);
1406 if (hr == S_OK) {
1407 layout->cluster_count = cluster;
1408 if (cluster)
1409 layout->clustermetrics[cluster-1].canWrapLineAfter = 1;
1412 return hr;
1415 static HRESULT layout_compute(struct dwrite_textlayout *layout)
1417 HRESULT hr;
1419 if (!(layout->recompute & RECOMPUTE_CLUSTERS))
1420 return S_OK;
1422 /* nominal breakpoints are evaluated only once, because string never changes */
1423 if (!layout->nominal_breakpoints)
1425 IDWriteTextAnalyzer2 *analyzer;
1427 layout->nominal_breakpoints = heap_calloc(layout->len, sizeof(*layout->nominal_breakpoints));
1428 if (!layout->nominal_breakpoints)
1429 return E_OUTOFMEMORY;
1431 analyzer = get_text_analyzer();
1433 if (FAILED(hr = IDWriteTextAnalyzer2_AnalyzeLineBreakpoints(analyzer,
1434 (IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
1435 0, layout->len, (IDWriteTextAnalysisSink *)&layout->IDWriteTextAnalysisSink1_iface)))
1436 WARN("Line breakpoints analysis failed, hr %#x.\n", hr);
1439 heap_free(layout->actual_breakpoints);
1440 layout->actual_breakpoints = NULL;
1442 hr = layout_compute_runs(layout);
1444 if (TRACE_ON(dwrite)) {
1445 struct layout_run *cur;
1447 LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
1448 if (cur->kind == LAYOUT_RUN_INLINE)
1449 TRACE("run inline object %p, len %u\n", cur->u.object.object, cur->u.object.length);
1450 else
1451 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur->u.regular.descr.textPosition, cur->u.regular.descr.textPosition +
1452 cur->u.regular.descr.stringLength-1, cur->u.regular.descr.stringLength, cur->u.regular.run.bidiLevel);
1456 layout->recompute &= ~RECOMPUTE_CLUSTERS;
1457 return hr;
1460 static inline FLOAT get_cluster_range_width(struct dwrite_textlayout *layout, UINT32 start, UINT32 end)
1462 FLOAT width = 0.0f;
1463 for (; start < end; start++)
1464 width += layout->clustermetrics[start].width;
1465 return width;
1468 static inline IUnknown *layout_get_effect_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1470 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->effects, pos);
1471 return ((struct layout_range_iface*)h)->iface;
1474 /* A set of parameters that additionally splits resulting runs. It happens after shaping and all text processing,
1475 no glyph changes are possible. It's understandable for drawing effects, because DrawGlyphRun() reports them as
1476 one of the arguments, but it also happens for decorations, so every effective run has uniform
1477 underline/strikethough/effect tuple. */
1478 struct layout_final_splitting_params {
1479 BOOL strikethrough;
1480 BOOL underline;
1481 IUnknown *effect;
1484 static inline BOOL layout_get_strikethrough_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1486 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->strike_ranges, pos);
1487 return ((struct layout_range_bool*)h)->value;
1490 static inline BOOL layout_get_underline_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1492 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->underline_ranges, pos);
1493 return ((struct layout_range_bool*)h)->value;
1496 static void layout_splitting_params_from_pos(struct dwrite_textlayout *layout, UINT32 pos,
1497 struct layout_final_splitting_params *params)
1499 params->strikethrough = layout_get_strikethrough_from_pos(layout, pos);
1500 params->underline = layout_get_underline_from_pos(layout, pos);
1501 params->effect = layout_get_effect_from_pos(layout, pos);
1504 static BOOL is_same_splitting_params(const struct layout_final_splitting_params *left,
1505 const struct layout_final_splitting_params *right)
1507 return left->strikethrough == right->strikethrough &&
1508 left->underline == right->underline &&
1509 left->effect == right->effect;
1512 static void layout_get_erun_font_metrics(struct dwrite_textlayout *layout, struct layout_effective_run *erun,
1513 DWRITE_FONT_METRICS *metrics)
1515 memset(metrics, 0, sizeof(*metrics));
1516 if (is_layout_gdi_compatible(layout)) {
1517 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(
1518 erun->run->u.regular.run.fontFace,
1519 erun->run->u.regular.run.fontEmSize,
1520 layout->ppdip,
1521 &layout->transform,
1522 metrics);
1523 if (FAILED(hr))
1524 WARN("failed to get font metrics, 0x%08x\n", hr);
1526 else
1527 IDWriteFontFace_GetMetrics(erun->run->u.regular.run.fontFace, metrics);
1530 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
1531 'cluster_count' indicates how many clusters to add, including first one. */
1532 static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 first_cluster,
1533 UINT32 cluster_count, UINT32 line, FLOAT origin_x, struct layout_final_splitting_params *params)
1535 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1536 UINT32 i, start, length, last_cluster;
1537 struct layout_effective_run *run;
1539 if (r->kind == LAYOUT_RUN_INLINE) {
1540 struct layout_effective_inline *inlineobject;
1542 inlineobject = heap_alloc(sizeof(*inlineobject));
1543 if (!inlineobject)
1544 return E_OUTOFMEMORY;
1546 inlineobject->object = r->u.object.object;
1547 inlineobject->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1548 inlineobject->origin.x = is_rtl ? origin_x - inlineobject->width : origin_x;
1549 inlineobject->origin.y = 0.0f; /* set after line is built */
1550 inlineobject->align_dx = 0.0f;
1551 inlineobject->baseline = r->baseline;
1553 /* It's not clear how these two are set, possibly directionality
1554 is derived from surrounding text (replaced text could have
1555 different ranges which differ in reading direction). */
1556 inlineobject->is_sideways = FALSE;
1557 inlineobject->is_rtl = FALSE;
1558 inlineobject->line = line;
1560 /* effect assigned from start position and on is used for inline objects */
1561 inlineobject->effect = layout_get_effect_from_pos(layout, layout->clusters[first_cluster].position +
1562 layout->clusters[first_cluster].run->start_position);
1564 list_add_tail(&layout->inlineobjects, &inlineobject->entry);
1565 return S_OK;
1568 run = heap_alloc(sizeof(*run));
1569 if (!run)
1570 return E_OUTOFMEMORY;
1572 /* No need to iterate for that, use simple fact that:
1573 <last cluster position> = <first cluster position> + <sum of cluster lengths not including last one> */
1574 last_cluster = first_cluster + cluster_count - 1;
1575 length = layout->clusters[last_cluster].position - layout->clusters[first_cluster].position +
1576 layout->clustermetrics[last_cluster].length;
1578 run->clustermap = heap_calloc(length, sizeof(*run->clustermap));
1579 if (!run->clustermap) {
1580 heap_free(run);
1581 return E_OUTOFMEMORY;
1584 run->run = r;
1585 run->start = start = layout->clusters[first_cluster].position;
1586 run->length = length;
1587 run->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1588 memset(&run->bbox, 0, sizeof(run->bbox));
1590 /* Check if run direction matches paragraph direction, if it doesn't adjust by
1591 run width */
1592 if (is_run_rtl(run) ^ is_rtl)
1593 run->origin.x = is_rtl ? origin_x - run->width : origin_x + run->width;
1594 else
1595 run->origin.x = origin_x;
1597 run->origin.y = 0.0f; /* set after line is built */
1598 run->align_dx = 0.0f;
1599 run->line = line;
1601 if (r->u.regular.run.glyphCount) {
1602 /* Trim leading and trailing clusters. */
1603 run->glyphcount = r->u.regular.run.glyphCount - r->u.regular.clustermap[start];
1604 if (start + length < r->u.regular.descr.stringLength)
1605 run->glyphcount -= r->u.regular.run.glyphCount - r->u.regular.clustermap[start + length];
1607 else
1608 run->glyphcount = 0;
1610 /* cluster map needs to be shifted */
1611 for (i = 0; i < length; i++)
1612 run->clustermap[i] = r->u.regular.clustermap[start + i] - r->u.regular.clustermap[start];
1614 run->effect = params->effect;
1615 run->underlined = params->underline;
1616 list_add_tail(&layout->eruns, &run->entry);
1618 /* Strikethrough style is guaranteed to be consistent within effective run,
1619 its width equals to run width, thickness and offset are derived from
1620 font metrics, rest of the values are from layout or run itself */
1621 if (params->strikethrough) {
1622 struct layout_strikethrough *s;
1623 DWRITE_FONT_METRICS metrics;
1625 s = heap_alloc(sizeof(*s));
1626 if (!s)
1627 return E_OUTOFMEMORY;
1629 layout_get_erun_font_metrics(layout, run, &metrics);
1630 s->s.width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1631 s->s.thickness = SCALE_FONT_METRIC(metrics.strikethroughThickness, r->u.regular.run.fontEmSize, &metrics);
1632 /* Negative offset moves it above baseline as Y coordinate grows downward. */
1633 s->s.offset = -SCALE_FONT_METRIC(metrics.strikethroughPosition, r->u.regular.run.fontEmSize, &metrics);
1634 s->s.readingDirection = layout->format.readingdir;
1635 s->s.flowDirection = layout->format.flow;
1636 s->s.localeName = r->u.regular.descr.localeName;
1637 s->s.measuringMode = layout->measuringmode;
1638 s->run = run;
1640 list_add_tail(&layout->strikethrough, &s->entry);
1643 return S_OK;
1646 static void layout_apply_line_spacing(struct dwrite_textlayout *layout, UINT32 line)
1648 switch (layout->format.spacing.method)
1650 case DWRITE_LINE_SPACING_METHOD_DEFAULT:
1651 layout->lines[line].metrics.height = layout->lines[line].height;
1652 layout->lines[line].metrics.baseline = layout->lines[line].baseline;
1653 break;
1654 case DWRITE_LINE_SPACING_METHOD_UNIFORM:
1655 layout->lines[line].metrics.height = layout->format.spacing.height;
1656 layout->lines[line].metrics.baseline = layout->format.spacing.baseline;
1657 break;
1658 case DWRITE_LINE_SPACING_METHOD_PROPORTIONAL:
1659 layout->lines[line].metrics.height = layout->lines[line].height * layout->format.spacing.height;
1660 layout->lines[line].metrics.baseline = layout->lines[line].baseline * layout->format.spacing.baseline;
1661 break;
1662 default:
1663 ERR("Unknown spacing method %u\n", layout->format.spacing.method);
1667 static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_LINE_METRICS1 *metrics)
1669 size_t i = layout->metrics.lineCount;
1671 if (!dwrite_array_reserve((void **)&layout->lines, &layout->lines_size, layout->metrics.lineCount + 1,
1672 sizeof(*layout->lines)))
1674 return E_OUTOFMEMORY;
1677 layout->lines[i].metrics = *metrics;
1678 layout->lines[i].height = metrics->height;
1679 layout->lines[i].baseline = metrics->baseline;
1681 if (layout->format.spacing.method != DWRITE_LINE_SPACING_METHOD_DEFAULT)
1682 layout_apply_line_spacing(layout, i);
1684 layout->metrics.lineCount++;
1685 return S_OK;
1688 static inline struct layout_effective_run *layout_get_next_erun(struct dwrite_textlayout *layout,
1689 const struct layout_effective_run *cur)
1691 struct list *e;
1693 if (!cur)
1694 e = list_head(&layout->eruns);
1695 else
1696 e = list_next(&layout->eruns, &cur->entry);
1697 if (!e)
1698 return NULL;
1699 return LIST_ENTRY(e, struct layout_effective_run, entry);
1702 static inline struct layout_effective_run *layout_get_prev_erun(struct dwrite_textlayout *layout,
1703 const struct layout_effective_run *cur)
1705 struct list *e;
1707 if (!cur)
1708 e = list_tail(&layout->eruns);
1709 else
1710 e = list_prev(&layout->eruns, &cur->entry);
1711 if (!e)
1712 return NULL;
1713 return LIST_ENTRY(e, struct layout_effective_run, entry);
1716 static inline struct layout_effective_inline *layout_get_next_inline_run(struct dwrite_textlayout *layout,
1717 const struct layout_effective_inline *cur)
1719 struct list *e;
1721 if (!cur)
1722 e = list_head(&layout->inlineobjects);
1723 else
1724 e = list_next(&layout->inlineobjects, &cur->entry);
1725 if (!e)
1726 return NULL;
1727 return LIST_ENTRY(e, struct layout_effective_inline, entry);
1730 static FLOAT layout_get_line_width(struct dwrite_textlayout *layout,
1731 struct layout_effective_run *erun, struct layout_effective_inline *inrun, UINT32 line)
1733 FLOAT width = 0.0f;
1735 while (erun && erun->line == line) {
1736 width += erun->width;
1737 erun = layout_get_next_erun(layout, erun);
1738 if (!erun)
1739 break;
1742 while (inrun && inrun->line == line) {
1743 width += inrun->width;
1744 inrun = layout_get_next_inline_run(layout, inrun);
1745 if (!inrun)
1746 break;
1749 return width;
1752 static inline BOOL should_skip_transform(const DWRITE_MATRIX *m, FLOAT *det)
1754 *det = m->m11 * m->m22 - m->m12 * m->m21;
1755 /* on certain conditions we can skip transform */
1756 return (!memcmp(m, &identity, sizeof(*m)) || fabsf(*det) <= 1e-10f);
1759 static inline void layout_apply_snapping(D2D1_POINT_2F *vec, BOOL skiptransform, FLOAT ppdip,
1760 const DWRITE_MATRIX *m, FLOAT det)
1762 if (!skiptransform) {
1763 D2D1_POINT_2F vec2;
1765 /* apply transform */
1766 vec->x *= ppdip;
1767 vec->y *= ppdip;
1769 vec2.x = m->m11 * vec->x + m->m21 * vec->y + m->dx;
1770 vec2.y = m->m12 * vec->x + m->m22 * vec->y + m->dy;
1772 /* snap */
1773 vec2.x = floorf(vec2.x + 0.5f);
1774 vec2.y = floorf(vec2.y + 0.5f);
1776 /* apply inverted transform, we don't care about X component at this point */
1777 vec->x = (m->m22 * vec2.x - m->m21 * vec2.y + m->m21 * m->dy - m->m22 * m->dx) / det;
1778 vec->x /= ppdip;
1780 vec->y = (-m->m12 * vec2.x + m->m11 * vec2.y - (m->m11 * m->dy - m->m12 * m->dx)) / det;
1781 vec->y /= ppdip;
1783 else {
1784 vec->x = floorf(vec->x * ppdip + 0.5f) / ppdip;
1785 vec->y = floorf(vec->y * ppdip + 0.5f) / ppdip;
1789 static void layout_apply_leading_alignment(struct dwrite_textlayout *layout)
1791 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1792 struct layout_effective_inline *inrun;
1793 struct layout_effective_run *erun;
1795 erun = layout_get_next_erun(layout, NULL);
1796 inrun = layout_get_next_inline_run(layout, NULL);
1798 while (erun) {
1799 erun->align_dx = 0.0f;
1800 erun = layout_get_next_erun(layout, erun);
1803 while (inrun) {
1804 inrun->align_dx = 0.0f;
1805 inrun = layout_get_next_inline_run(layout, inrun);
1808 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
1811 static void layout_apply_trailing_alignment(struct dwrite_textlayout *layout)
1813 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1814 struct layout_effective_inline *inrun;
1815 struct layout_effective_run *erun;
1816 UINT32 line;
1818 erun = layout_get_next_erun(layout, NULL);
1819 inrun = layout_get_next_inline_run(layout, NULL);
1821 for (line = 0; line < layout->metrics.lineCount; line++) {
1822 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1823 FLOAT shift = layout->metrics.layoutWidth - width;
1825 if (is_rtl)
1826 shift *= -1.0f;
1828 while (erun && erun->line == line) {
1829 erun->align_dx = shift;
1830 erun = layout_get_next_erun(layout, erun);
1833 while (inrun && inrun->line == line) {
1834 inrun->align_dx = shift;
1835 inrun = layout_get_next_inline_run(layout, inrun);
1839 layout->metrics.left = is_rtl ? 0.0f : layout->metrics.layoutWidth - layout->metrics.width;
1842 static inline FLOAT layout_get_centered_shift(struct dwrite_textlayout *layout, BOOL skiptransform,
1843 FLOAT width, FLOAT det)
1845 if (is_layout_gdi_compatible(layout)) {
1846 D2D1_POINT_2F vec = { layout->metrics.layoutWidth - width, 0.0f};
1847 layout_apply_snapping(&vec, skiptransform, layout->ppdip, &layout->transform, det);
1848 return floorf(vec.x / 2.0f);
1850 else
1851 return (layout->metrics.layoutWidth - width) / 2.0f;
1854 static void layout_apply_centered_alignment(struct dwrite_textlayout *layout)
1856 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1857 struct layout_effective_inline *inrun;
1858 struct layout_effective_run *erun;
1859 BOOL skiptransform;
1860 UINT32 line;
1861 FLOAT det;
1863 erun = layout_get_next_erun(layout, NULL);
1864 inrun = layout_get_next_inline_run(layout, NULL);
1866 skiptransform = should_skip_transform(&layout->transform, &det);
1868 for (line = 0; line < layout->metrics.lineCount; line++) {
1869 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1870 FLOAT shift = layout_get_centered_shift(layout, skiptransform, width, det);
1872 if (is_rtl)
1873 shift *= -1.0f;
1875 while (erun && erun->line == line) {
1876 erun->align_dx = shift;
1877 erun = layout_get_next_erun(layout, erun);
1880 while (inrun && inrun->line == line) {
1881 inrun->align_dx = shift;
1882 inrun = layout_get_next_inline_run(layout, inrun);
1886 layout->metrics.left = (layout->metrics.layoutWidth - layout->metrics.width) / 2.0f;
1889 static void layout_apply_text_alignment(struct dwrite_textlayout *layout)
1891 switch (layout->format.textalignment)
1893 case DWRITE_TEXT_ALIGNMENT_LEADING:
1894 layout_apply_leading_alignment(layout);
1895 break;
1896 case DWRITE_TEXT_ALIGNMENT_TRAILING:
1897 layout_apply_trailing_alignment(layout);
1898 break;
1899 case DWRITE_TEXT_ALIGNMENT_CENTER:
1900 layout_apply_centered_alignment(layout);
1901 break;
1902 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED:
1903 FIXME("alignment %d not implemented\n", layout->format.textalignment);
1904 break;
1905 default:
1910 static void layout_apply_par_alignment(struct dwrite_textlayout *layout)
1912 struct layout_effective_inline *inrun;
1913 struct layout_effective_run *erun;
1914 FLOAT origin_y = 0.0f;
1915 UINT32 line;
1917 /* alignment mode defines origin, after that all run origins are updated
1918 the same way */
1920 switch (layout->format.paralign)
1922 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR:
1923 origin_y = 0.0f;
1924 break;
1925 case DWRITE_PARAGRAPH_ALIGNMENT_FAR:
1926 origin_y = layout->metrics.layoutHeight - layout->metrics.height;
1927 break;
1928 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER:
1929 origin_y = (layout->metrics.layoutHeight - layout->metrics.height) / 2.0f;
1930 break;
1931 default:
1935 layout->metrics.top = origin_y;
1937 erun = layout_get_next_erun(layout, NULL);
1938 inrun = layout_get_next_inline_run(layout, NULL);
1939 for (line = 0; line < layout->metrics.lineCount; line++)
1941 float pos_y = origin_y + layout->lines[line].metrics.baseline;
1943 while (erun && erun->line == line) {
1944 erun->origin.y = pos_y;
1945 erun = layout_get_next_erun(layout, erun);
1948 while (inrun && inrun->line == line) {
1949 inrun->origin.y = pos_y - inrun->baseline;
1950 inrun = layout_get_next_inline_run(layout, inrun);
1953 origin_y += layout->lines[line].metrics.height;
1957 struct layout_underline_splitting_params {
1958 const WCHAR *locale; /* points to range data, no additional allocation */
1959 IUnknown *effect; /* does not hold another reference */
1962 static void init_u_splitting_params_from_erun(struct layout_effective_run *erun,
1963 struct layout_underline_splitting_params *params)
1965 params->locale = erun->run->u.regular.descr.localeName;
1966 params->effect = erun->effect;
1969 static BOOL is_same_u_splitting(struct layout_underline_splitting_params *left,
1970 struct layout_underline_splitting_params *right)
1972 return left->effect == right->effect && !wcsicmp(left->locale, right->locale);
1975 static HRESULT layout_add_underline(struct dwrite_textlayout *layout, struct layout_effective_run *first,
1976 struct layout_effective_run *last)
1978 FLOAT thickness, offset, runheight;
1979 struct layout_effective_run *cur;
1980 DWRITE_FONT_METRICS metrics;
1982 if (first == layout_get_prev_erun(layout, last)) {
1983 layout_get_erun_font_metrics(layout, first, &metrics);
1984 thickness = SCALE_FONT_METRIC(metrics.underlineThickness, first->run->u.regular.run.fontEmSize, &metrics);
1985 offset = SCALE_FONT_METRIC(metrics.underlinePosition, first->run->u.regular.run.fontEmSize, &metrics);
1986 runheight = SCALE_FONT_METRIC(metrics.capHeight, first->run->u.regular.run.fontEmSize, &metrics);
1988 else {
1989 FLOAT width = 0.0f;
1991 /* Single underline is added for consecutive underlined runs. In this case underline parameters are
1992 calculated as weighted average, where run width acts as a weight. */
1993 thickness = offset = runheight = 0.0f;
1994 cur = first;
1995 do {
1996 layout_get_erun_font_metrics(layout, cur, &metrics);
1998 thickness += SCALE_FONT_METRIC(metrics.underlineThickness, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
1999 offset += SCALE_FONT_METRIC(metrics.underlinePosition, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
2000 runheight = max(SCALE_FONT_METRIC(metrics.capHeight, cur->run->u.regular.run.fontEmSize, &metrics), runheight);
2001 width += cur->width;
2003 cur = layout_get_next_erun(layout, cur);
2004 } while (cur != last);
2006 thickness /= width;
2007 offset /= width;
2010 cur = first;
2011 do {
2012 struct layout_underline_splitting_params params, prev_params;
2013 struct layout_effective_run *next, *w;
2014 struct layout_underline *u;
2016 init_u_splitting_params_from_erun(cur, &prev_params);
2017 while ((next = layout_get_next_erun(layout, cur)) != last) {
2018 init_u_splitting_params_from_erun(next, &params);
2019 if (!is_same_u_splitting(&prev_params, &params))
2020 break;
2021 cur = next;
2024 u = heap_alloc(sizeof(*u));
2025 if (!u)
2026 return E_OUTOFMEMORY;
2028 w = cur;
2029 u->u.width = 0.0f;
2030 while (w != next) {
2031 u->u.width += w->width;
2032 w = layout_get_next_erun(layout, w);
2035 u->u.thickness = thickness;
2036 /* Font metrics convention is to have it negative when below baseline, for rendering
2037 however Y grows from baseline down for horizontal baseline. */
2038 u->u.offset = -offset;
2039 u->u.runHeight = runheight;
2040 u->u.readingDirection = is_run_rtl(cur) ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
2041 DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
2042 u->u.flowDirection = layout->format.flow;
2043 u->u.localeName = cur->run->u.regular.descr.localeName;
2044 u->u.measuringMode = layout->measuringmode;
2045 u->run = cur;
2046 list_add_tail(&layout->underlines, &u->entry);
2048 cur = next;
2049 } while (cur != last);
2051 return S_OK;
2054 /* Adds zero width line, metrics are derived from font at specified text position. */
2055 static HRESULT layout_set_dummy_line_metrics(struct dwrite_textlayout *layout, UINT32 pos)
2057 DWRITE_LINE_METRICS1 metrics = { 0 };
2058 DWRITE_FONT_METRICS fontmetrics;
2059 struct layout_range *range;
2060 IDWriteFontFace *fontface;
2061 IDWriteFont *font;
2062 HRESULT hr;
2064 range = get_layout_range_by_pos(layout, pos);
2065 hr = create_matching_font(range->collection,
2066 range->fontfamily,
2067 range->weight,
2068 range->style,
2069 range->stretch,
2070 &font);
2071 if (FAILED(hr))
2072 return hr;
2073 hr = IDWriteFont_CreateFontFace(font, &fontface);
2074 IDWriteFont_Release(font);
2075 if (FAILED(hr))
2076 return hr;
2078 layout_get_font_metrics(layout, fontface, range->fontsize, &fontmetrics);
2079 layout_get_font_height(range->fontsize, &fontmetrics, &metrics.baseline, &metrics.height);
2080 IDWriteFontFace_Release(fontface);
2082 return layout_set_line_metrics(layout, &metrics);
2085 static void layout_add_line(struct dwrite_textlayout *layout, UINT32 first_cluster, UINT32 last_cluster,
2086 UINT32 *textpos)
2088 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
2089 struct layout_final_splitting_params params, prev_params;
2090 DWRITE_INLINE_OBJECT_METRICS sign_metrics = { 0 };
2091 UINT32 line = layout->metrics.lineCount, i;
2092 DWRITE_LINE_METRICS1 metrics = { 0 };
2093 UINT32 index, start, pos = *textpos;
2094 FLOAT descent, trailingspacewidth;
2095 BOOL append_trimming_run = FALSE;
2096 const struct layout_run *run;
2097 float width = 0.0f, origin_x;
2098 HRESULT hr;
2100 /* Take a look at clusters we got for this line in reverse order to set trailing properties for current line */
2101 for (index = last_cluster, trailingspacewidth = 0.0f; index >= first_cluster; index--) {
2102 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
2103 struct layout_cluster *lc = &layout->clusters[index];
2104 WCHAR ch;
2106 /* This also filters out clusters added from inline objects, those are never
2107 treated as a white space. */
2108 if (!cluster->isWhitespace)
2109 break;
2111 /* Every isNewline cluster is also isWhitespace, but not every
2112 newline character cluster has isNewline set, so go back to original string. */
2113 ch = lc->run->u.regular.descr.string[lc->position];
2114 if (cluster->length == 1 && lb_is_newline_char(ch))
2115 metrics.newlineLength += cluster->length;
2117 metrics.trailingWhitespaceLength += cluster->length;
2118 trailingspacewidth += cluster->width;
2120 if (index == 0)
2121 break;
2124 /* Line metrics length includes trailing whitespace length too */
2125 for (i = first_cluster; i <= last_cluster; i++)
2126 metrics.length += layout->clustermetrics[i].length;
2128 /* Ignore trailing whitespaces */
2129 while (last_cluster > first_cluster) {
2130 if (!layout->clustermetrics[last_cluster].isWhitespace)
2131 break;
2133 last_cluster--;
2136 /* Does not include trailing space width */
2137 if (!layout->clustermetrics[last_cluster].isWhitespace)
2138 width = get_cluster_range_width(layout, first_cluster, last_cluster + 1);
2140 /* Append trimming run if necessary */
2141 if (width > layout->metrics.layoutWidth && layout->format.trimmingsign != NULL &&
2142 layout->format.trimming.granularity != DWRITE_TRIMMING_GRANULARITY_NONE) {
2143 FLOAT trimmed_width = width;
2145 hr = IDWriteInlineObject_GetMetrics(layout->format.trimmingsign, &sign_metrics);
2146 if (SUCCEEDED(hr)) {
2147 while (last_cluster > first_cluster) {
2148 if (trimmed_width + sign_metrics.width <= layout->metrics.layoutWidth)
2149 break;
2150 if (layout->format.trimming.granularity == DWRITE_TRIMMING_GRANULARITY_CHARACTER)
2151 trimmed_width -= layout->clustermetrics[last_cluster--].width;
2152 else {
2153 while (last_cluster > first_cluster) {
2154 trimmed_width -= layout->clustermetrics[last_cluster].width;
2155 if (layout->clustermetrics[last_cluster--].canWrapLineAfter)
2156 break;
2160 append_trimming_run = TRUE;
2162 else
2163 WARN("Failed to get trimming sign metrics, lines won't be trimmed, hr %#x.\n", hr);
2165 width = trimmed_width + sign_metrics.width;
2168 layout_splitting_params_from_pos(layout, pos, &params);
2169 prev_params = params;
2170 run = layout->clusters[first_cluster].run;
2172 /* Form runs from a range of clusters; this is what will be reported with DrawGlyphRun() */
2173 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0f;
2174 for (start = first_cluster, i = first_cluster; i <= last_cluster; i++) {
2175 layout_splitting_params_from_pos(layout, pos, &params);
2177 if (run != layout->clusters[i].run || !is_same_splitting_params(&prev_params, &params)) {
2178 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, &prev_params);
2179 if (FAILED(hr))
2180 return;
2182 origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) :
2183 get_cluster_range_width(layout, start, i);
2184 run = layout->clusters[i].run;
2185 start = i;
2188 prev_params = params;
2189 pos += layout->clustermetrics[i].length;
2192 /* Final run from what's left from cluster range */
2193 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, &prev_params);
2194 if (FAILED(hr))
2195 return;
2197 if (get_cluster_range_width(layout, start, i) + sign_metrics.width > layout->metrics.layoutWidth)
2198 append_trimming_run = FALSE;
2200 if (append_trimming_run) {
2201 struct layout_effective_inline *trimming_sign;
2203 trimming_sign = heap_alloc(sizeof(*trimming_sign));
2204 if (!trimming_sign)
2205 return;
2207 trimming_sign->object = layout->format.trimmingsign;
2208 trimming_sign->width = sign_metrics.width;
2209 origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) : get_cluster_range_width(layout, start, i);
2210 trimming_sign->origin.x = is_rtl ? origin_x - trimming_sign->width : origin_x;
2211 trimming_sign->origin.y = 0.0f; /* set after line is built */
2212 trimming_sign->align_dx = 0.0f;
2213 trimming_sign->baseline = sign_metrics.baseline;
2215 trimming_sign->is_sideways = FALSE;
2216 trimming_sign->is_rtl = FALSE;
2217 trimming_sign->line = line;
2219 trimming_sign->effect = layout_get_effect_from_pos(layout, layout->clusters[i].position +
2220 layout->clusters[i].run->start_position);
2222 list_add_tail(&layout->inlineobjects, &trimming_sign->entry);
2225 /* Look for max baseline and descent for this line */
2226 for (index = first_cluster, metrics.baseline = 0.0f, descent = 0.0f; index <= last_cluster; index++) {
2227 const struct layout_run *cur = layout->clusters[index].run;
2228 FLOAT cur_descent = cur->height - cur->baseline;
2230 if (cur->baseline > metrics.baseline)
2231 metrics.baseline = cur->baseline;
2232 if (cur_descent > descent)
2233 descent = cur_descent;
2236 layout->metrics.width = max(width, layout->metrics.width);
2237 layout->metrics.widthIncludingTrailingWhitespace = max(width + trailingspacewidth,
2238 layout->metrics.widthIncludingTrailingWhitespace);
2240 metrics.height = descent + metrics.baseline;
2241 metrics.isTrimmed = append_trimming_run || width > layout->metrics.layoutWidth;
2242 layout_set_line_metrics(layout, &metrics);
2244 *textpos += metrics.length;
2247 static void layout_set_line_positions(struct dwrite_textlayout *layout)
2249 struct layout_effective_inline *inrun;
2250 struct layout_effective_run *erun;
2251 FLOAT origin_y;
2252 UINT32 line;
2254 /* Now all line info is here, update effective runs positions in flow direction */
2255 erun = layout_get_next_erun(layout, NULL);
2256 inrun = layout_get_next_inline_run(layout, NULL);
2258 for (line = 0, origin_y = 0.0f; line < layout->metrics.lineCount; line++)
2260 float pos_y = origin_y + layout->lines[line].metrics.baseline;
2262 /* For all runs on this line */
2263 while (erun && erun->line == line) {
2264 erun->origin.y = pos_y;
2265 erun = layout_get_next_erun(layout, erun);
2268 /* Same for inline runs */
2269 while (inrun && inrun->line == line) {
2270 inrun->origin.y = pos_y - inrun->baseline;
2271 inrun = layout_get_next_inline_run(layout, inrun);
2274 origin_y += layout->lines[line].metrics.height;
2277 layout->metrics.height = origin_y;
2279 /* Initial paragraph alignment is always near */
2280 if (layout->format.paralign != DWRITE_PARAGRAPH_ALIGNMENT_NEAR)
2281 layout_apply_par_alignment(layout);
2284 static BOOL layout_can_wrap_after(const struct dwrite_textlayout *layout, UINT32 cluster)
2286 if (layout->format.wrapping == DWRITE_WORD_WRAPPING_CHARACTER)
2287 return TRUE;
2289 return layout->clustermetrics[cluster].canWrapLineAfter;
2292 static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
2294 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
2295 struct layout_effective_run *erun, *first_underlined;
2296 UINT32 i, start, textpos, last_breaking_point;
2297 DWRITE_LINE_METRICS1 metrics;
2298 FLOAT width;
2299 UINT32 line;
2300 HRESULT hr;
2302 if (!(layout->recompute & RECOMPUTE_LINES))
2303 return S_OK;
2305 free_layout_eruns(layout);
2307 hr = layout_compute(layout);
2308 if (FAILED(hr))
2309 return hr;
2311 layout->metrics.lineCount = 0;
2312 memset(&metrics, 0, sizeof(metrics));
2314 layout->metrics.height = 0.0f;
2315 layout->metrics.width = 0.0f;
2316 layout->metrics.widthIncludingTrailingWhitespace = 0.0f;
2318 last_breaking_point = ~0u;
2320 for (i = 0, start = 0, width = 0.0f, textpos = 0; i < layout->cluster_count; i++) {
2321 BOOL overflow = FALSE;
2323 while (i < layout->cluster_count && !layout->clustermetrics[i].isNewline) {
2324 /* Check for overflow */
2325 overflow = ((width + layout->clustermetrics[i].width > layout->metrics.layoutWidth) &&
2326 (layout->format.wrapping != DWRITE_WORD_WRAPPING_NO_WRAP));
2327 if (overflow)
2328 break;
2330 if (layout_can_wrap_after(layout, i))
2331 last_breaking_point = i;
2332 width += layout->clustermetrics[i].width;
2333 i++;
2335 i = min(i, layout->cluster_count - 1);
2337 /* Ignore if overflown on whitespace */
2338 if (overflow && !(layout->clustermetrics[i].isWhitespace && layout_can_wrap_after(layout, i))) {
2339 /* Use most recently found breaking point */
2340 if (last_breaking_point != ~0u) {
2341 i = last_breaking_point;
2342 last_breaking_point = ~0u;
2344 else {
2345 /* Otherwise proceed forward to next newline or breaking point */
2346 for (; i < layout->cluster_count; i++)
2347 if (layout_can_wrap_after(layout, i) || layout->clustermetrics[i].isNewline)
2348 break;
2351 i = min(i, layout->cluster_count - 1);
2353 layout_add_line(layout, start, i, &textpos);
2354 start = i + 1;
2355 width = 0.0f;
2358 /* Add dummy line if:
2359 - there's no text, metrics come from first range in this case;
2360 - last ended with a mandatory break, metrics come from last text position.
2362 if (layout->len == 0)
2363 hr = layout_set_dummy_line_metrics(layout, 0);
2364 else if (layout->cluster_count && layout->clustermetrics[layout->cluster_count - 1].isNewline)
2365 hr = layout_set_dummy_line_metrics(layout, layout->len - 1);
2366 if (FAILED(hr))
2367 return hr;
2369 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
2370 layout->metrics.top = 0.0f;
2371 layout->metrics.maxBidiReorderingDepth = 1; /* FIXME */
2373 /* Add explicit underlined runs */
2374 erun = layout_get_next_erun(layout, NULL);
2375 first_underlined = erun && erun->underlined ? erun : NULL;
2376 for (line = 0; line < layout->metrics.lineCount; line++) {
2377 while (erun && erun->line == line) {
2378 erun = layout_get_next_erun(layout, erun);
2380 if (first_underlined && (!erun || !erun->underlined)) {
2381 layout_add_underline(layout, first_underlined, erun);
2382 first_underlined = NULL;
2384 else if (!first_underlined && erun && erun->underlined)
2385 first_underlined = erun;
2389 /* Position runs in flow direction */
2390 layout_set_line_positions(layout);
2392 /* Initial alignment is always leading */
2393 if (layout->format.textalignment != DWRITE_TEXT_ALIGNMENT_LEADING)
2394 layout_apply_text_alignment(layout);
2396 layout->recompute &= ~RECOMPUTE_LINES;
2397 return hr;
2400 static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum layout_range_attr_kind attr,
2401 struct layout_range_attr_value *value)
2403 struct layout_range_spacing const *range_spacing = (struct layout_range_spacing*)h;
2404 struct layout_range_iface const *range_iface = (struct layout_range_iface*)h;
2405 struct layout_range_bool const *range_bool = (struct layout_range_bool*)h;
2406 struct layout_range const *range = (struct layout_range*)h;
2408 switch (attr) {
2409 case LAYOUT_RANGE_ATTR_WEIGHT:
2410 return range->weight == value->u.weight;
2411 case LAYOUT_RANGE_ATTR_STYLE:
2412 return range->style == value->u.style;
2413 case LAYOUT_RANGE_ATTR_STRETCH:
2414 return range->stretch == value->u.stretch;
2415 case LAYOUT_RANGE_ATTR_FONTSIZE:
2416 return range->fontsize == value->u.fontsize;
2417 case LAYOUT_RANGE_ATTR_INLINE:
2418 return range->object == value->u.object;
2419 case LAYOUT_RANGE_ATTR_EFFECT:
2420 return range_iface->iface == value->u.effect;
2421 case LAYOUT_RANGE_ATTR_UNDERLINE:
2422 return range_bool->value == value->u.underline;
2423 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2424 return range_bool->value == value->u.strikethrough;
2425 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2426 return range->pair_kerning == value->u.pair_kerning;
2427 case LAYOUT_RANGE_ATTR_FONTCOLL:
2428 return range->collection == value->u.collection;
2429 case LAYOUT_RANGE_ATTR_LOCALE:
2430 return !wcsicmp(range->locale, value->u.locale);
2431 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2432 return !wcscmp(range->fontfamily, value->u.fontfamily);
2433 case LAYOUT_RANGE_ATTR_SPACING:
2434 return range_spacing->leading == value->u.spacing.leading &&
2435 range_spacing->trailing == value->u.spacing.trailing &&
2436 range_spacing->min_advance == value->u.spacing.min_advance;
2437 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2438 return range_iface->iface == (IUnknown*)value->u.typography;
2439 default:
2443 return FALSE;
2446 static inline BOOL is_same_layout_attributes(struct layout_range_header const *hleft, struct layout_range_header const *hright)
2448 switch (hleft->kind)
2450 case LAYOUT_RANGE_REGULAR:
2452 struct layout_range const *left = (struct layout_range const*)hleft;
2453 struct layout_range const *right = (struct layout_range const*)hright;
2454 return left->weight == right->weight &&
2455 left->style == right->style &&
2456 left->stretch == right->stretch &&
2457 left->fontsize == right->fontsize &&
2458 left->object == right->object &&
2459 left->pair_kerning == right->pair_kerning &&
2460 left->collection == right->collection &&
2461 !wcsicmp(left->locale, right->locale) &&
2462 !wcscmp(left->fontfamily, right->fontfamily);
2464 case LAYOUT_RANGE_UNDERLINE:
2465 case LAYOUT_RANGE_STRIKETHROUGH:
2467 struct layout_range_bool const *left = (struct layout_range_bool const*)hleft;
2468 struct layout_range_bool const *right = (struct layout_range_bool const*)hright;
2469 return left->value == right->value;
2471 case LAYOUT_RANGE_EFFECT:
2472 case LAYOUT_RANGE_TYPOGRAPHY:
2474 struct layout_range_iface const *left = (struct layout_range_iface const*)hleft;
2475 struct layout_range_iface const *right = (struct layout_range_iface const*)hright;
2476 return left->iface == right->iface;
2478 case LAYOUT_RANGE_SPACING:
2480 struct layout_range_spacing const *left = (struct layout_range_spacing const*)hleft;
2481 struct layout_range_spacing const *right = (struct layout_range_spacing const*)hright;
2482 return left->leading == right->leading &&
2483 left->trailing == right->trailing &&
2484 left->min_advance == right->min_advance;
2486 default:
2487 FIXME("unknown range kind %d\n", hleft->kind);
2488 return FALSE;
2492 static inline BOOL is_same_text_range(const DWRITE_TEXT_RANGE *left, const DWRITE_TEXT_RANGE *right)
2494 return left->startPosition == right->startPosition && left->length == right->length;
2497 /* Allocates range and inits it with default values from text format. */
2498 static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout *layout, const DWRITE_TEXT_RANGE *r,
2499 enum layout_range_kind kind)
2501 struct layout_range_header *h;
2503 switch (kind)
2505 case LAYOUT_RANGE_REGULAR:
2507 struct layout_range *range;
2509 range = heap_alloc_zero(sizeof(*range));
2510 if (!range) return NULL;
2512 range->weight = layout->format.weight;
2513 range->style = layout->format.style;
2514 range->stretch = layout->format.stretch;
2515 range->fontsize = layout->format.fontsize;
2517 range->fontfamily = heap_strdupW(layout->format.family_name);
2518 if (!range->fontfamily)
2520 heap_free(range);
2521 return NULL;
2524 range->collection = layout->format.collection;
2525 if (range->collection)
2526 IDWriteFontCollection_AddRef(range->collection);
2527 wcscpy(range->locale, layout->format.locale);
2529 h = &range->h;
2530 break;
2532 case LAYOUT_RANGE_UNDERLINE:
2533 case LAYOUT_RANGE_STRIKETHROUGH:
2535 struct layout_range_bool *range;
2537 range = heap_alloc_zero(sizeof(*range));
2538 if (!range) return NULL;
2540 h = &range->h;
2541 break;
2543 case LAYOUT_RANGE_EFFECT:
2544 case LAYOUT_RANGE_TYPOGRAPHY:
2546 struct layout_range_iface *range;
2548 range = heap_alloc_zero(sizeof(*range));
2549 if (!range) return NULL;
2551 h = &range->h;
2552 break;
2554 case LAYOUT_RANGE_SPACING:
2556 struct layout_range_spacing *range;
2558 range = heap_alloc_zero(sizeof(*range));
2559 if (!range) return NULL;
2561 h = &range->h;
2562 break;
2564 default:
2565 FIXME("unknown range kind %d\n", kind);
2566 return NULL;
2569 h->kind = kind;
2570 h->range = *r;
2571 return h;
2574 static struct layout_range_header *alloc_layout_range_from(struct layout_range_header *h, const DWRITE_TEXT_RANGE *r)
2576 struct layout_range_header *ret;
2578 switch (h->kind)
2580 case LAYOUT_RANGE_REGULAR:
2582 struct layout_range *from = (struct layout_range*)h;
2584 struct layout_range *range = heap_alloc(sizeof(*range));
2585 if (!range) return NULL;
2587 *range = *from;
2588 range->fontfamily = heap_strdupW(from->fontfamily);
2589 if (!range->fontfamily) {
2590 heap_free(range);
2591 return NULL;
2594 /* update refcounts */
2595 if (range->object)
2596 IDWriteInlineObject_AddRef(range->object);
2597 if (range->collection)
2598 IDWriteFontCollection_AddRef(range->collection);
2599 ret = &range->h;
2600 break;
2602 case LAYOUT_RANGE_UNDERLINE:
2603 case LAYOUT_RANGE_STRIKETHROUGH:
2605 struct layout_range_bool *strike = heap_alloc(sizeof(*strike));
2606 if (!strike) return NULL;
2608 *strike = *(struct layout_range_bool*)h;
2609 ret = &strike->h;
2610 break;
2612 case LAYOUT_RANGE_EFFECT:
2613 case LAYOUT_RANGE_TYPOGRAPHY:
2615 struct layout_range_iface *effect = heap_alloc(sizeof(*effect));
2616 if (!effect) return NULL;
2618 *effect = *(struct layout_range_iface*)h;
2619 if (effect->iface)
2620 IUnknown_AddRef(effect->iface);
2621 ret = &effect->h;
2622 break;
2624 case LAYOUT_RANGE_SPACING:
2626 struct layout_range_spacing *spacing = heap_alloc(sizeof(*spacing));
2627 if (!spacing) return NULL;
2629 *spacing = *(struct layout_range_spacing*)h;
2630 ret = &spacing->h;
2631 break;
2633 default:
2634 FIXME("unknown range kind %d\n", h->kind);
2635 return NULL;
2638 ret->range = *r;
2639 return ret;
2642 static void free_layout_range(struct layout_range_header *h)
2644 if (!h)
2645 return;
2647 switch (h->kind)
2649 case LAYOUT_RANGE_REGULAR:
2651 struct layout_range *range = (struct layout_range*)h;
2653 if (range->object)
2654 IDWriteInlineObject_Release(range->object);
2655 if (range->collection)
2656 IDWriteFontCollection_Release(range->collection);
2657 heap_free(range->fontfamily);
2658 break;
2660 case LAYOUT_RANGE_EFFECT:
2661 case LAYOUT_RANGE_TYPOGRAPHY:
2663 struct layout_range_iface *range = (struct layout_range_iface*)h;
2664 if (range->iface)
2665 IUnknown_Release(range->iface);
2666 break;
2668 default:
2672 heap_free(h);
2675 static void free_layout_ranges_list(struct dwrite_textlayout *layout)
2677 struct layout_range_header *cur, *cur2;
2679 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->ranges, struct layout_range_header, entry) {
2680 list_remove(&cur->entry);
2681 free_layout_range(cur);
2684 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->underline_ranges, struct layout_range_header, entry) {
2685 list_remove(&cur->entry);
2686 free_layout_range(cur);
2689 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->strike_ranges, struct layout_range_header, entry) {
2690 list_remove(&cur->entry);
2691 free_layout_range(cur);
2694 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->effects, struct layout_range_header, entry) {
2695 list_remove(&cur->entry);
2696 free_layout_range(cur);
2699 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->spacing, struct layout_range_header, entry) {
2700 list_remove(&cur->entry);
2701 free_layout_range(cur);
2704 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->typographies, struct layout_range_header, entry) {
2705 list_remove(&cur->entry);
2706 free_layout_range(cur);
2710 static struct layout_range_header *find_outer_range(struct list *ranges, const DWRITE_TEXT_RANGE *range)
2712 struct layout_range_header *cur;
2714 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
2716 if (cur->range.startPosition > range->startPosition)
2717 return NULL;
2719 if ((cur->range.startPosition + cur->range.length < range->startPosition + range->length) &&
2720 (range->startPosition < cur->range.startPosition + cur->range.length))
2721 return NULL;
2722 if (cur->range.startPosition + cur->range.length >= range->startPosition + range->length)
2723 return cur;
2726 return NULL;
2729 static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
2731 if (*dest == value) return FALSE;
2733 if (*dest)
2734 IUnknown_Release(*dest);
2735 *dest = value;
2736 if (*dest)
2737 IUnknown_AddRef(*dest);
2739 return TRUE;
2742 static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2744 struct layout_range_spacing *dest_spacing = (struct layout_range_spacing*)h;
2745 struct layout_range_iface *dest_iface = (struct layout_range_iface*)h;
2746 struct layout_range_bool *dest_bool = (struct layout_range_bool*)h;
2747 struct layout_range *dest = (struct layout_range*)h;
2749 BOOL changed = FALSE;
2751 switch (attr) {
2752 case LAYOUT_RANGE_ATTR_WEIGHT:
2753 changed = dest->weight != value->u.weight;
2754 dest->weight = value->u.weight;
2755 break;
2756 case LAYOUT_RANGE_ATTR_STYLE:
2757 changed = dest->style != value->u.style;
2758 dest->style = value->u.style;
2759 break;
2760 case LAYOUT_RANGE_ATTR_STRETCH:
2761 changed = dest->stretch != value->u.stretch;
2762 dest->stretch = value->u.stretch;
2763 break;
2764 case LAYOUT_RANGE_ATTR_FONTSIZE:
2765 changed = dest->fontsize != value->u.fontsize;
2766 dest->fontsize = value->u.fontsize;
2767 break;
2768 case LAYOUT_RANGE_ATTR_INLINE:
2769 changed = set_layout_range_iface_attr((IUnknown**)&dest->object, (IUnknown*)value->u.object);
2770 break;
2771 case LAYOUT_RANGE_ATTR_EFFECT:
2772 changed = set_layout_range_iface_attr(&dest_iface->iface, value->u.effect);
2773 break;
2774 case LAYOUT_RANGE_ATTR_UNDERLINE:
2775 changed = dest_bool->value != value->u.underline;
2776 dest_bool->value = value->u.underline;
2777 break;
2778 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2779 changed = dest_bool->value != value->u.strikethrough;
2780 dest_bool->value = value->u.strikethrough;
2781 break;
2782 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2783 changed = dest->pair_kerning != value->u.pair_kerning;
2784 dest->pair_kerning = value->u.pair_kerning;
2785 break;
2786 case LAYOUT_RANGE_ATTR_FONTCOLL:
2787 changed = set_layout_range_iface_attr((IUnknown**)&dest->collection, (IUnknown*)value->u.collection);
2788 break;
2789 case LAYOUT_RANGE_ATTR_LOCALE:
2790 changed = !!wcsicmp(dest->locale, value->u.locale);
2791 if (changed)
2793 wcscpy(dest->locale, value->u.locale);
2794 wcslwr(dest->locale);
2796 break;
2797 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2798 changed = !!wcscmp(dest->fontfamily, value->u.fontfamily);
2799 if (changed)
2801 heap_free(dest->fontfamily);
2802 dest->fontfamily = heap_strdupW(value->u.fontfamily);
2804 break;
2805 case LAYOUT_RANGE_ATTR_SPACING:
2806 changed = dest_spacing->leading != value->u.spacing.leading ||
2807 dest_spacing->trailing != value->u.spacing.trailing ||
2808 dest_spacing->min_advance != value->u.spacing.min_advance;
2809 dest_spacing->leading = value->u.spacing.leading;
2810 dest_spacing->trailing = value->u.spacing.trailing;
2811 dest_spacing->min_advance = value->u.spacing.min_advance;
2812 break;
2813 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2814 changed = set_layout_range_iface_attr(&dest_iface->iface, (IUnknown*)value->u.typography);
2815 break;
2816 default:
2820 return changed;
2823 static inline BOOL is_in_layout_range(const DWRITE_TEXT_RANGE *outer, const DWRITE_TEXT_RANGE *inner)
2825 return (inner->startPosition >= outer->startPosition) &&
2826 (inner->startPosition + inner->length <= outer->startPosition + outer->length);
2829 static inline HRESULT return_range(const struct layout_range_header *h, DWRITE_TEXT_RANGE *r)
2831 if (r) *r = h->range;
2832 return S_OK;
2835 /* Sets attribute value for given range, does all needed splitting/merging of existing ranges. */
2836 static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2838 struct layout_range_header *cur, *right, *left, *outer;
2839 BOOL changed = FALSE;
2840 struct list *ranges;
2841 DWRITE_TEXT_RANGE r;
2843 /* ignore zero length ranges */
2844 if (value->range.length == 0)
2845 return S_OK;
2847 if (~0u - value->range.startPosition < value->range.length)
2848 return E_INVALIDARG;
2850 /* select from ranges lists */
2851 switch (attr)
2853 case LAYOUT_RANGE_ATTR_WEIGHT:
2854 case LAYOUT_RANGE_ATTR_STYLE:
2855 case LAYOUT_RANGE_ATTR_STRETCH:
2856 case LAYOUT_RANGE_ATTR_FONTSIZE:
2857 case LAYOUT_RANGE_ATTR_INLINE:
2858 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2859 case LAYOUT_RANGE_ATTR_FONTCOLL:
2860 case LAYOUT_RANGE_ATTR_LOCALE:
2861 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2862 ranges = &layout->ranges;
2863 break;
2864 case LAYOUT_RANGE_ATTR_UNDERLINE:
2865 ranges = &layout->underline_ranges;
2866 break;
2867 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2868 ranges = &layout->strike_ranges;
2869 break;
2870 case LAYOUT_RANGE_ATTR_EFFECT:
2871 ranges = &layout->effects;
2872 break;
2873 case LAYOUT_RANGE_ATTR_SPACING:
2874 ranges = &layout->spacing;
2875 break;
2876 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2877 ranges = &layout->typographies;
2878 break;
2879 default:
2880 FIXME("unknown attr kind %d\n", attr);
2881 return E_FAIL;
2884 /* If new range is completely within existing range, split existing range in two */
2885 if ((outer = find_outer_range(ranges, &value->range))) {
2887 /* no need to add same range */
2888 if (is_same_layout_attrvalue(outer, attr, value))
2889 return S_OK;
2891 /* for matching range bounds just replace data */
2892 if (is_same_text_range(&outer->range, &value->range)) {
2893 changed = set_layout_range_attrval(outer, attr, value);
2894 goto done;
2897 /* add new range to the left */
2898 if (value->range.startPosition == outer->range.startPosition) {
2899 left = alloc_layout_range_from(outer, &value->range);
2900 if (!left) return E_OUTOFMEMORY;
2902 changed = set_layout_range_attrval(left, attr, value);
2903 list_add_before(&outer->entry, &left->entry);
2904 outer->range.startPosition += value->range.length;
2905 outer->range.length -= value->range.length;
2906 goto done;
2909 /* add new range to the right */
2910 if (value->range.startPosition + value->range.length == outer->range.startPosition + outer->range.length) {
2911 right = alloc_layout_range_from(outer, &value->range);
2912 if (!right) return E_OUTOFMEMORY;
2914 changed = set_layout_range_attrval(right, attr, value);
2915 list_add_after(&outer->entry, &right->entry);
2916 outer->range.length -= value->range.length;
2917 goto done;
2920 r.startPosition = value->range.startPosition + value->range.length;
2921 r.length = outer->range.length + outer->range.startPosition - r.startPosition;
2923 /* right part */
2924 right = alloc_layout_range_from(outer, &r);
2925 /* new range in the middle */
2926 cur = alloc_layout_range_from(outer, &value->range);
2927 if (!right || !cur) {
2928 free_layout_range(right);
2929 free_layout_range(cur);
2930 return E_OUTOFMEMORY;
2933 /* reuse container range as a left part */
2934 outer->range.length = value->range.startPosition - outer->range.startPosition;
2936 /* new part */
2937 set_layout_range_attrval(cur, attr, value);
2939 list_add_after(&outer->entry, &cur->entry);
2940 list_add_after(&cur->entry, &right->entry);
2942 layout->recompute = RECOMPUTE_EVERYTHING;
2943 return S_OK;
2946 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2947 Update all of them. */
2948 left = get_layout_range_header_by_pos(ranges, value->range.startPosition);
2949 if (left->range.startPosition == value->range.startPosition)
2950 changed = set_layout_range_attrval(left, attr, value);
2951 else /* need to split */ {
2952 r.startPosition = value->range.startPosition;
2953 r.length = left->range.length - value->range.startPosition + left->range.startPosition;
2954 left->range.length -= r.length;
2955 cur = alloc_layout_range_from(left, &r);
2956 changed = set_layout_range_attrval(cur, attr, value);
2957 list_add_after(&left->entry, &cur->entry);
2959 cur = LIST_ENTRY(list_next(ranges, &left->entry), struct layout_range_header, entry);
2961 /* for all existing ranges covered by new one update value */
2962 while (cur && is_in_layout_range(&value->range, &cur->range)) {
2963 changed |= set_layout_range_attrval(cur, attr, value);
2964 cur = LIST_ENTRY(list_next(ranges, &cur->entry), struct layout_range_header, entry);
2967 /* it's possible rightmost range intersects */
2968 if (cur && (cur->range.startPosition < value->range.startPosition + value->range.length)) {
2969 r.startPosition = cur->range.startPosition;
2970 r.length = value->range.startPosition + value->range.length - cur->range.startPosition;
2971 left = alloc_layout_range_from(cur, &r);
2972 changed |= set_layout_range_attrval(left, attr, value);
2973 cur->range.startPosition += left->range.length;
2974 cur->range.length -= left->range.length;
2975 list_add_before(&cur->entry, &left->entry);
2978 done:
2979 if (changed) {
2980 struct list *next, *i;
2982 layout->recompute = RECOMPUTE_EVERYTHING;
2983 i = list_head(ranges);
2984 while ((next = list_next(ranges, i))) {
2985 struct layout_range_header *next_range = LIST_ENTRY(next, struct layout_range_header, entry);
2987 cur = LIST_ENTRY(i, struct layout_range_header, entry);
2988 if (is_same_layout_attributes(cur, next_range)) {
2989 /* remove similar range */
2990 cur->range.length += next_range->range.length;
2991 list_remove(next);
2992 free_layout_range(next_range);
2994 else
2995 i = list_next(ranges, i);
2999 return S_OK;
3002 static inline const WCHAR *get_string_attribute_ptr(struct layout_range *range, enum layout_range_attr_kind kind)
3004 const WCHAR *str;
3006 switch (kind) {
3007 case LAYOUT_RANGE_ATTR_LOCALE:
3008 str = range->locale;
3009 break;
3010 case LAYOUT_RANGE_ATTR_FONTFAMILY:
3011 str = range->fontfamily;
3012 break;
3013 default:
3014 str = NULL;
3017 return str;
3020 static HRESULT get_string_attribute_length(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
3021 UINT32 *length, DWRITE_TEXT_RANGE *r)
3023 struct layout_range *range;
3024 const WCHAR *str;
3026 range = get_layout_range_by_pos(layout, position);
3027 if (!range) {
3028 *length = 0;
3029 return S_OK;
3032 str = get_string_attribute_ptr(range, kind);
3033 *length = wcslen(str);
3034 return return_range(&range->h, r);
3037 static HRESULT get_string_attribute_value(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
3038 WCHAR *ret, UINT32 length, DWRITE_TEXT_RANGE *r)
3040 struct layout_range *range;
3041 const WCHAR *str;
3043 if (length == 0)
3044 return E_INVALIDARG;
3046 ret[0] = 0;
3047 range = get_layout_range_by_pos(layout, position);
3048 if (!range)
3049 return E_INVALIDARG;
3051 str = get_string_attribute_ptr(range, kind);
3052 if (length < wcslen(str) + 1)
3053 return E_NOT_SUFFICIENT_BUFFER;
3055 wcscpy(ret, str);
3056 return return_range(&range->h, r);
3059 static HRESULT WINAPI dwritetextlayout_QueryInterface(IDWriteTextLayout4 *iface, REFIID riid, void **obj)
3061 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3063 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
3065 *obj = NULL;
3067 if (IsEqualIID(riid, &IID_IDWriteTextLayout4) ||
3068 IsEqualIID(riid, &IID_IDWriteTextLayout3) ||
3069 IsEqualIID(riid, &IID_IDWriteTextLayout2) ||
3070 IsEqualIID(riid, &IID_IDWriteTextLayout1) ||
3071 IsEqualIID(riid, &IID_IDWriteTextLayout) ||
3072 IsEqualIID(riid, &IID_IUnknown))
3074 *obj = iface;
3076 else if (IsEqualIID(riid, &IID_IDWriteTextFormat3) ||
3077 IsEqualIID(riid, &IID_IDWriteTextFormat2) ||
3078 IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
3079 IsEqualIID(riid, &IID_IDWriteTextFormat))
3081 *obj = &layout->IDWriteTextFormat3_iface;
3084 if (*obj) {
3085 IDWriteTextLayout4_AddRef(iface);
3086 return S_OK;
3089 WARN("%s not implemented.\n", debugstr_guid(riid));
3091 return E_NOINTERFACE;
3094 static ULONG WINAPI dwritetextlayout_AddRef(IDWriteTextLayout4 *iface)
3096 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3097 ULONG refcount = InterlockedIncrement(&layout->refcount);
3099 TRACE("%p, refcount %u.\n", iface, refcount);
3101 return refcount;
3104 static ULONG WINAPI dwritetextlayout_Release(IDWriteTextLayout4 *iface)
3106 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3107 ULONG refcount = InterlockedDecrement(&layout->refcount);
3109 TRACE("%p, refcount %u.\n", iface, refcount);
3111 if (!refcount)
3113 IDWriteFactory7_Release(layout->factory);
3114 free_layout_ranges_list(layout);
3115 free_layout_eruns(layout);
3116 free_layout_runs(layout);
3117 release_format_data(&layout->format);
3118 heap_free(layout->nominal_breakpoints);
3119 heap_free(layout->actual_breakpoints);
3120 heap_free(layout->clustermetrics);
3121 heap_free(layout->clusters);
3122 heap_free(layout->lines);
3123 heap_free(layout->str);
3124 heap_free(layout);
3127 return refcount;
3130 static HRESULT WINAPI dwritetextlayout_SetTextAlignment(IDWriteTextLayout4 *iface, DWRITE_TEXT_ALIGNMENT alignment)
3132 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3133 return IDWriteTextFormat3_SetTextAlignment(&layout->IDWriteTextFormat3_iface, alignment);
3136 static HRESULT WINAPI dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout4 *iface,
3137 DWRITE_PARAGRAPH_ALIGNMENT alignment)
3139 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3140 return IDWriteTextFormat3_SetParagraphAlignment(&layout->IDWriteTextFormat3_iface, alignment);
3143 static HRESULT WINAPI dwritetextlayout_SetWordWrapping(IDWriteTextLayout4 *iface, DWRITE_WORD_WRAPPING wrapping)
3145 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3146 return IDWriteTextFormat3_SetWordWrapping(&layout->IDWriteTextFormat3_iface, wrapping);
3149 static HRESULT WINAPI dwritetextlayout_SetReadingDirection(IDWriteTextLayout4 *iface,
3150 DWRITE_READING_DIRECTION direction)
3152 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3153 return IDWriteTextFormat3_SetReadingDirection(&layout->IDWriteTextFormat3_iface, direction);
3156 static HRESULT WINAPI dwritetextlayout_SetFlowDirection(IDWriteTextLayout4 *iface, DWRITE_FLOW_DIRECTION direction)
3158 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3159 return IDWriteTextFormat3_SetFlowDirection(&layout->IDWriteTextFormat3_iface, direction);
3162 static HRESULT WINAPI dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout4 *iface, FLOAT tabstop)
3164 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3165 return IDWriteTextFormat3_SetIncrementalTabStop(&layout->IDWriteTextFormat3_iface, tabstop);
3168 static HRESULT WINAPI dwritetextlayout_SetTrimming(IDWriteTextLayout4 *iface, DWRITE_TRIMMING const *trimming,
3169 IDWriteInlineObject *trimming_sign)
3171 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3172 return IDWriteTextFormat3_SetTrimming(&layout->IDWriteTextFormat3_iface, trimming, trimming_sign);
3175 static HRESULT WINAPI dwritetextlayout_SetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING_METHOD spacing,
3176 FLOAT line_spacing, FLOAT baseline)
3178 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3179 return IDWriteTextFormat1_SetLineSpacing((IDWriteTextFormat1 *)&layout->IDWriteTextFormat3_iface, spacing,
3180 line_spacing, baseline);
3183 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextlayout_GetTextAlignment(IDWriteTextLayout4 *iface)
3185 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3186 return IDWriteTextFormat3_GetTextAlignment(&layout->IDWriteTextFormat3_iface);
3189 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout4 *iface)
3191 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3192 return IDWriteTextFormat3_GetParagraphAlignment(&layout->IDWriteTextFormat3_iface);
3195 static DWRITE_WORD_WRAPPING WINAPI dwritetextlayout_GetWordWrapping(IDWriteTextLayout4 *iface)
3197 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3198 return IDWriteTextFormat3_GetWordWrapping(&layout->IDWriteTextFormat3_iface);
3201 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_GetReadingDirection(IDWriteTextLayout4 *iface)
3203 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3204 return IDWriteTextFormat3_GetReadingDirection(&layout->IDWriteTextFormat3_iface);
3207 static DWRITE_FLOW_DIRECTION WINAPI dwritetextlayout_GetFlowDirection(IDWriteTextLayout4 *iface)
3209 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3210 return IDWriteTextFormat3_GetFlowDirection(&layout->IDWriteTextFormat3_iface);
3213 static FLOAT WINAPI dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout4 *iface)
3215 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3216 return IDWriteTextFormat3_GetIncrementalTabStop(&layout->IDWriteTextFormat3_iface);
3219 static HRESULT WINAPI dwritetextlayout_GetTrimming(IDWriteTextLayout4 *iface, DWRITE_TRIMMING *options,
3220 IDWriteInlineObject **trimming_sign)
3222 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3223 return IDWriteTextFormat3_GetTrimming(&layout->IDWriteTextFormat3_iface, options, trimming_sign);
3226 static HRESULT WINAPI dwritetextlayout_GetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING_METHOD *method,
3227 FLOAT *spacing, FLOAT *baseline)
3229 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3230 return IDWriteTextFormat_GetLineSpacing((IDWriteTextFormat *)&layout->IDWriteTextFormat3_iface, method,
3231 spacing, baseline);
3234 static HRESULT WINAPI dwritetextlayout_GetFontCollection(IDWriteTextLayout4 *iface, IDWriteFontCollection **collection)
3236 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3237 return IDWriteTextFormat3_GetFontCollection(&layout->IDWriteTextFormat3_iface, collection);
3240 static UINT32 WINAPI dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout4 *iface)
3242 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3243 return IDWriteTextFormat3_GetFontFamilyNameLength(&layout->IDWriteTextFormat3_iface);
3246 static HRESULT WINAPI dwritetextlayout_GetFontFamilyName(IDWriteTextLayout4 *iface, WCHAR *name, UINT32 size)
3248 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3249 return IDWriteTextFormat3_GetFontFamilyName(&layout->IDWriteTextFormat3_iface, name, size);
3252 static DWRITE_FONT_WEIGHT WINAPI dwritetextlayout_GetFontWeight(IDWriteTextLayout4 *iface)
3254 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3255 return IDWriteTextFormat3_GetFontWeight(&layout->IDWriteTextFormat3_iface);
3258 static DWRITE_FONT_STYLE WINAPI dwritetextlayout_GetFontStyle(IDWriteTextLayout4 *iface)
3260 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3261 return IDWriteTextFormat3_GetFontStyle(&layout->IDWriteTextFormat3_iface);
3264 static DWRITE_FONT_STRETCH WINAPI dwritetextlayout_GetFontStretch(IDWriteTextLayout4 *iface)
3266 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3267 return IDWriteTextFormat3_GetFontStretch(&layout->IDWriteTextFormat3_iface);
3270 static FLOAT WINAPI dwritetextlayout_GetFontSize(IDWriteTextLayout4 *iface)
3272 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3273 return IDWriteTextFormat3_GetFontSize(&layout->IDWriteTextFormat3_iface);
3276 static UINT32 WINAPI dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout4 *iface)
3278 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3279 return IDWriteTextFormat3_GetLocaleNameLength(&layout->IDWriteTextFormat3_iface);
3282 static HRESULT WINAPI dwritetextlayout_GetLocaleName(IDWriteTextLayout4 *iface, WCHAR *name, UINT32 size)
3284 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3285 return IDWriteTextFormat3_GetLocaleName(&layout->IDWriteTextFormat3_iface, name, size);
3288 static HRESULT WINAPI dwritetextlayout_SetMaxWidth(IDWriteTextLayout4 *iface, FLOAT maxWidth)
3290 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3291 BOOL changed;
3293 TRACE("%p, %.8e.\n", iface, maxWidth);
3295 if (maxWidth < 0.0f)
3296 return E_INVALIDARG;
3298 changed = layout->metrics.layoutWidth != maxWidth;
3299 layout->metrics.layoutWidth = maxWidth;
3301 if (changed)
3302 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
3303 return S_OK;
3306 static HRESULT WINAPI dwritetextlayout_SetMaxHeight(IDWriteTextLayout4 *iface, FLOAT maxHeight)
3308 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3309 BOOL changed;
3311 TRACE("%p, %.8e.\n", iface, maxHeight);
3313 if (maxHeight < 0.0f)
3314 return E_INVALIDARG;
3316 changed = layout->metrics.layoutHeight != maxHeight;
3317 layout->metrics.layoutHeight = maxHeight;
3319 if (changed)
3320 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
3321 return S_OK;
3324 static HRESULT WINAPI dwritetextlayout_SetFontCollection(IDWriteTextLayout4 *iface, IDWriteFontCollection *collection,
3325 DWRITE_TEXT_RANGE range)
3327 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3328 struct layout_range_attr_value value;
3330 TRACE("%p, %p, %s.\n", iface, collection, debugstr_range(&range));
3332 value.range = range;
3333 value.u.collection = collection;
3334 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_FONTCOLL, &value);
3337 static HRESULT WINAPI dwritetextlayout_SetFontFamilyName(IDWriteTextLayout4 *iface, WCHAR const *name,
3338 DWRITE_TEXT_RANGE range)
3340 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3341 struct layout_range_attr_value value;
3343 TRACE("%p, %s, %s.\n", iface, debugstr_w(name), debugstr_range(&range));
3345 if (!name)
3346 return E_INVALIDARG;
3348 value.range = range;
3349 value.u.fontfamily = name;
3350 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_FONTFAMILY, &value);
3353 static HRESULT WINAPI dwritetextlayout_SetFontWeight(IDWriteTextLayout4 *iface, DWRITE_FONT_WEIGHT weight,
3354 DWRITE_TEXT_RANGE range)
3356 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3357 struct layout_range_attr_value value;
3359 TRACE("%p, %d, %s.\n", iface, weight, debugstr_range(&range));
3361 if ((UINT32)weight > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
3362 return E_INVALIDARG;
3364 value.range = range;
3365 value.u.weight = weight;
3366 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_WEIGHT, &value);
3369 static HRESULT WINAPI dwritetextlayout_SetFontStyle(IDWriteTextLayout4 *iface, DWRITE_FONT_STYLE style,
3370 DWRITE_TEXT_RANGE range)
3372 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3373 struct layout_range_attr_value value;
3375 TRACE("%p, %d, %s.\n", iface, style, debugstr_range(&range));
3377 if ((UINT32)style > DWRITE_FONT_STYLE_ITALIC)
3378 return E_INVALIDARG;
3380 value.range = range;
3381 value.u.style = style;
3382 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_STYLE, &value);
3385 static HRESULT WINAPI dwritetextlayout_SetFontStretch(IDWriteTextLayout4 *iface, DWRITE_FONT_STRETCH stretch,
3386 DWRITE_TEXT_RANGE range)
3388 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3389 struct layout_range_attr_value value;
3391 TRACE("%p, %d, %s.\n", iface, stretch, debugstr_range(&range));
3393 if (stretch == DWRITE_FONT_STRETCH_UNDEFINED || (UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
3394 return E_INVALIDARG;
3396 value.range = range;
3397 value.u.stretch = stretch;
3398 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_STRETCH, &value);
3401 static HRESULT WINAPI dwritetextlayout_SetFontSize(IDWriteTextLayout4 *iface, FLOAT size, DWRITE_TEXT_RANGE range)
3403 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3404 struct layout_range_attr_value value;
3406 TRACE("%p, %.8e, %s.\n", iface, size, debugstr_range(&range));
3408 if (size <= 0.0f)
3409 return E_INVALIDARG;
3411 value.range = range;
3412 value.u.fontsize = size;
3413 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_FONTSIZE, &value);
3416 static HRESULT WINAPI dwritetextlayout_SetUnderline(IDWriteTextLayout4 *iface, BOOL underline, DWRITE_TEXT_RANGE range)
3418 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3419 struct layout_range_attr_value value;
3421 TRACE("%p, %d, %s.\n", iface, underline, debugstr_range(&range));
3423 value.range = range;
3424 value.u.underline = underline;
3425 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_UNDERLINE, &value);
3428 static HRESULT WINAPI dwritetextlayout_SetStrikethrough(IDWriteTextLayout4 *iface, BOOL strikethrough,
3429 DWRITE_TEXT_RANGE range)
3431 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3432 struct layout_range_attr_value value;
3434 TRACE("%p, %d, %s.\n", iface, strikethrough, debugstr_range(&range));
3436 value.range = range;
3437 value.u.strikethrough = strikethrough;
3438 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_STRIKETHROUGH, &value);
3441 static HRESULT WINAPI dwritetextlayout_SetDrawingEffect(IDWriteTextLayout4 *iface, IUnknown* effect,
3442 DWRITE_TEXT_RANGE range)
3444 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3445 struct layout_range_attr_value value;
3447 TRACE("%p, %p, %s.\n", iface, effect, debugstr_range(&range));
3449 value.range = range;
3450 value.u.effect = effect;
3451 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_EFFECT, &value);
3454 static HRESULT WINAPI dwritetextlayout_SetInlineObject(IDWriteTextLayout4 *iface, IDWriteInlineObject *object,
3455 DWRITE_TEXT_RANGE range)
3457 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3458 struct layout_range_attr_value value;
3460 TRACE("%p, %p, %s.\n", iface, object, debugstr_range(&range));
3462 value.range = range;
3463 value.u.object = object;
3464 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_INLINE, &value);
3467 static HRESULT WINAPI dwritetextlayout_SetTypography(IDWriteTextLayout4 *iface, IDWriteTypography *typography,
3468 DWRITE_TEXT_RANGE range)
3470 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3471 struct layout_range_attr_value value;
3473 TRACE("%p, %p, %s.\n", iface, typography, debugstr_range(&range));
3475 value.range = range;
3476 value.u.typography = typography;
3477 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_TYPOGRAPHY, &value);
3480 static HRESULT WINAPI dwritetextlayout_SetLocaleName(IDWriteTextLayout4 *iface, WCHAR const* locale,
3481 DWRITE_TEXT_RANGE range)
3483 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3484 struct layout_range_attr_value value;
3486 TRACE("%p, %s, %s.\n", iface, debugstr_w(locale), debugstr_range(&range));
3488 if (!locale || wcslen(locale) > LOCALE_NAME_MAX_LENGTH-1)
3489 return E_INVALIDARG;
3491 value.range = range;
3492 value.u.locale = locale;
3493 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_LOCALE, &value);
3496 static FLOAT WINAPI dwritetextlayout_GetMaxWidth(IDWriteTextLayout4 *iface)
3498 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3500 TRACE("%p.\n", iface);
3502 return layout->metrics.layoutWidth;
3505 static FLOAT WINAPI dwritetextlayout_GetMaxHeight(IDWriteTextLayout4 *iface)
3507 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3509 TRACE("%p.\n", iface);
3511 return layout->metrics.layoutHeight;
3514 static HRESULT WINAPI dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout4 *iface, UINT32 position,
3515 IDWriteFontCollection **collection, DWRITE_TEXT_RANGE *r)
3517 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3518 struct layout_range *range;
3520 TRACE("%p, %u, %p, %p.\n", iface, position, collection, r);
3522 range = get_layout_range_by_pos(layout, position);
3523 *collection = range->collection;
3524 if (*collection)
3525 IDWriteFontCollection_AddRef(*collection);
3527 return return_range(&range->h, r);
3530 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout4 *iface,
3531 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
3533 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3535 TRACE("%p, %d, %p, %p.\n", iface, position, length, r);
3537 return get_string_attribute_length(layout, LAYOUT_RANGE_ATTR_FONTFAMILY, position, length, r);
3540 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout4 *iface,
3541 UINT32 position, WCHAR *name, UINT32 length, DWRITE_TEXT_RANGE *r)
3543 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3545 TRACE("%p, %u, %p, %u, %p.\n", iface, position, name, length, r);
3547 return get_string_attribute_value(layout, LAYOUT_RANGE_ATTR_FONTFAMILY, position, name, length, r);
3550 static HRESULT WINAPI dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout4 *iface,
3551 UINT32 position, DWRITE_FONT_WEIGHT *weight, DWRITE_TEXT_RANGE *r)
3553 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3554 struct layout_range *range;
3556 TRACE("%p, %u, %p, %p.\n", iface, position, weight, r);
3558 range = get_layout_range_by_pos(layout, position);
3559 *weight = range->weight;
3561 return return_range(&range->h, r);
3564 static HRESULT WINAPI dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout4 *iface,
3565 UINT32 position, DWRITE_FONT_STYLE *style, DWRITE_TEXT_RANGE *r)
3567 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3568 struct layout_range *range;
3570 TRACE("%p, %u, %p, %p.\n", iface, position, style, r);
3572 range = get_layout_range_by_pos(layout, position);
3573 *style = range->style;
3574 return return_range(&range->h, r);
3577 static HRESULT WINAPI dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout4 *iface,
3578 UINT32 position, DWRITE_FONT_STRETCH *stretch, DWRITE_TEXT_RANGE *r)
3580 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3581 struct layout_range *range;
3583 TRACE("%p, %u, %p, %p.\n", iface, position, stretch, r);
3585 range = get_layout_range_by_pos(layout, position);
3586 *stretch = range->stretch;
3587 return return_range(&range->h, r);
3590 static HRESULT WINAPI dwritetextlayout_layout_GetFontSize(IDWriteTextLayout4 *iface,
3591 UINT32 position, FLOAT *size, DWRITE_TEXT_RANGE *r)
3593 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3594 struct layout_range *range;
3596 TRACE("%p, %u, %p, %p.\n", iface, position, size, r);
3598 range = get_layout_range_by_pos(layout, position);
3599 *size = range->fontsize;
3600 return return_range(&range->h, r);
3603 static HRESULT WINAPI dwritetextlayout_GetUnderline(IDWriteTextLayout4 *iface,
3604 UINT32 position, BOOL *underline, DWRITE_TEXT_RANGE *r)
3606 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3607 struct layout_range_bool *range;
3609 TRACE("%p, %u, %p, %p.\n", iface, position, underline, r);
3611 range = (struct layout_range_bool *)get_layout_range_header_by_pos(&layout->underline_ranges, position);
3612 *underline = range->value;
3614 return return_range(&range->h, r);
3617 static HRESULT WINAPI dwritetextlayout_GetStrikethrough(IDWriteTextLayout4 *iface,
3618 UINT32 position, BOOL *strikethrough, DWRITE_TEXT_RANGE *r)
3620 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3621 struct layout_range_bool *range;
3623 TRACE("%p, %u, %p, %p.\n", iface, position, strikethrough, r);
3625 range = (struct layout_range_bool *)get_layout_range_header_by_pos(&layout->strike_ranges, position);
3626 *strikethrough = range->value;
3628 return return_range(&range->h, r);
3631 static HRESULT WINAPI dwritetextlayout_GetDrawingEffect(IDWriteTextLayout4 *iface,
3632 UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r)
3634 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3635 struct layout_range_iface *range;
3637 TRACE("%p, %u, %p, %p.\n", iface, position, effect, r);
3639 range = (struct layout_range_iface *)get_layout_range_header_by_pos(&layout->effects, position);
3640 *effect = range->iface;
3641 if (*effect)
3642 IUnknown_AddRef(*effect);
3644 return return_range(&range->h, r);
3647 static HRESULT WINAPI dwritetextlayout_GetInlineObject(IDWriteTextLayout4 *iface,
3648 UINT32 position, IDWriteInlineObject **object, DWRITE_TEXT_RANGE *r)
3650 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3651 struct layout_range *range;
3653 TRACE("%p, %u, %p, %p.\n", iface, position, object, r);
3655 range = get_layout_range_by_pos(layout, position);
3656 *object = range->object;
3657 if (*object)
3658 IDWriteInlineObject_AddRef(*object);
3660 return return_range(&range->h, r);
3663 static HRESULT WINAPI dwritetextlayout_GetTypography(IDWriteTextLayout4 *iface,
3664 UINT32 position, IDWriteTypography** typography, DWRITE_TEXT_RANGE *r)
3666 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3667 struct layout_range_iface *range;
3669 TRACE("%p, %u, %p, %p.\n", iface, position, typography, r);
3671 range = (struct layout_range_iface *)get_layout_range_header_by_pos(&layout->typographies, position);
3672 *typography = (IDWriteTypography *)range->iface;
3673 if (*typography)
3674 IDWriteTypography_AddRef(*typography);
3676 return return_range(&range->h, r);
3679 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout4 *iface,
3680 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
3682 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3684 TRACE("%p, %u, %p, %p.\n", iface, position, length, r);
3686 return get_string_attribute_length(layout, LAYOUT_RANGE_ATTR_LOCALE, position, length, r);
3689 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout4 *iface,
3690 UINT32 position, WCHAR *locale, UINT32 length, DWRITE_TEXT_RANGE *r)
3692 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3694 TRACE("%p, %u, %p, %u, %p.\n", iface, position, locale, length, r);
3696 return get_string_attribute_value(layout, LAYOUT_RANGE_ATTR_LOCALE, position, locale, length, r);
3699 static inline FLOAT renderer_apply_snapping(FLOAT coord, BOOL skiptransform, FLOAT ppdip, FLOAT det,
3700 const DWRITE_MATRIX *m)
3702 D2D1_POINT_2F vec, vec2;
3704 if (!skiptransform) {
3705 /* apply transform */
3706 vec.x = 0.0f;
3707 vec.y = coord * ppdip;
3709 vec2.x = m->m11 * vec.x + m->m21 * vec.y + m->dx;
3710 vec2.y = m->m12 * vec.x + m->m22 * vec.y + m->dy;
3712 /* snap */
3713 vec2.x = floorf(vec2.x + 0.5f);
3714 vec2.y = floorf(vec2.y + 0.5f);
3716 /* apply inverted transform, we don't care about X component at this point */
3717 vec.y = (-m->m12 * vec2.x + m->m11 * vec2.y - (m->m11 * m->dy - m->m12 * m->dx)) / det;
3718 vec.y /= ppdip;
3720 else
3721 vec.y = floorf(coord * ppdip + 0.5f) / ppdip;
3723 return vec.y;
3726 static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout4 *iface,
3727 void *context, IDWriteTextRenderer* renderer, FLOAT origin_x, FLOAT origin_y)
3729 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3730 BOOL disabled = FALSE, skiptransform = FALSE;
3731 struct layout_effective_inline *inlineobject;
3732 struct layout_effective_run *run;
3733 struct layout_strikethrough *s;
3734 struct layout_underline *u;
3735 FLOAT det = 0.0f, ppdip = 0.0f;
3736 DWRITE_MATRIX m = { 0 };
3737 HRESULT hr;
3739 TRACE("%p, %p, %p, %.8e, %.8e.\n", iface, context, renderer, origin_x, origin_y);
3741 hr = layout_compute_effective_runs(layout);
3742 if (FAILED(hr))
3743 return hr;
3745 hr = IDWriteTextRenderer_IsPixelSnappingDisabled(renderer, context, &disabled);
3746 if (FAILED(hr))
3747 return hr;
3749 if (!disabled) {
3750 hr = IDWriteTextRenderer_GetPixelsPerDip(renderer, context, &ppdip);
3751 if (FAILED(hr))
3752 return hr;
3754 hr = IDWriteTextRenderer_GetCurrentTransform(renderer, context, &m);
3755 if (FAILED(hr))
3756 return hr;
3758 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
3759 if (ppdip <= 0.0f ||
3760 (m.m11 * m.m22 != 0.0f && (m.m12 != 0.0f || m.m21 != 0.0f)) ||
3761 (m.m12 * m.m21 != 0.0f && (m.m11 != 0.0f || m.m22 != 0.0f)))
3762 disabled = TRUE;
3763 else
3764 skiptransform = should_skip_transform(&m, &det);
3767 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
3768 /* 1. Regular runs */
3769 LIST_FOR_EACH_ENTRY(run, &layout->eruns, struct layout_effective_run, entry)
3771 const struct regular_layout_run *regular = &run->run->u.regular;
3772 UINT32 start_glyph = regular->clustermap[run->start];
3773 DWRITE_GLYPH_RUN_DESCRIPTION descr;
3774 DWRITE_GLYPH_RUN glyph_run;
3776 /* Everything but cluster map will be reused from nominal run, as we only need
3777 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
3778 it can't be reused because it has to start with 0 index for each reported run. */
3779 glyph_run = regular->run;
3780 glyph_run.glyphCount = run->glyphcount;
3782 /* fixup glyph data arrays */
3783 glyph_run.glyphIndices += start_glyph;
3784 glyph_run.glyphAdvances += start_glyph;
3785 glyph_run.glyphOffsets += start_glyph;
3787 /* description */
3788 descr = regular->descr;
3789 descr.stringLength = run->length;
3790 descr.string += run->start;
3791 descr.clusterMap = run->clustermap;
3792 descr.textPosition += run->start;
3794 /* return value is ignored */
3795 IDWriteTextRenderer_DrawGlyphRun(renderer,
3796 context,
3797 run->origin.x + run->align_dx + origin_x,
3798 SNAP_COORD(run->origin.y + origin_y),
3799 layout->measuringmode,
3800 &glyph_run,
3801 &descr,
3802 run->effect);
3805 /* 2. Inline objects */
3806 LIST_FOR_EACH_ENTRY(inlineobject, &layout->inlineobjects, struct layout_effective_inline, entry)
3808 IDWriteTextRenderer_DrawInlineObject(renderer,
3809 context,
3810 inlineobject->origin.x + inlineobject->align_dx + origin_x,
3811 SNAP_COORD(inlineobject->origin.y + origin_y),
3812 inlineobject->object,
3813 inlineobject->is_sideways,
3814 inlineobject->is_rtl,
3815 inlineobject->effect);
3818 /* 3. Underlines */
3819 LIST_FOR_EACH_ENTRY(u, &layout->underlines, struct layout_underline, entry)
3821 IDWriteTextRenderer_DrawUnderline(renderer,
3822 context,
3823 /* horizontal underline always grows from left to right, width is always added to origin regardless of run direction */
3824 (is_run_rtl(u->run) ? u->run->origin.x - u->run->width : u->run->origin.x) + u->run->align_dx + origin_x,
3825 SNAP_COORD(u->run->origin.y + origin_y),
3826 &u->u,
3827 u->run->effect);
3830 /* 4. Strikethrough */
3831 LIST_FOR_EACH_ENTRY(s, &layout->strikethrough, struct layout_strikethrough, entry)
3833 IDWriteTextRenderer_DrawStrikethrough(renderer,
3834 context,
3835 s->run->origin.x + s->run->align_dx + origin_x,
3836 SNAP_COORD(s->run->origin.y + origin_y),
3837 &s->s,
3838 s->run->effect);
3840 #undef SNAP_COORD
3842 return S_OK;
3845 static HRESULT WINAPI dwritetextlayout_GetLineMetrics(IDWriteTextLayout4 *iface,
3846 DWRITE_LINE_METRICS *metrics, UINT32 max_count, UINT32 *count)
3848 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3849 unsigned int line_count;
3850 HRESULT hr;
3851 size_t i;
3853 TRACE("%p, %p, %u, %p.\n", iface, metrics, max_count, count);
3855 if (FAILED(hr = layout_compute_effective_runs(layout)))
3856 return hr;
3858 if (metrics)
3860 line_count = min(max_count, layout->metrics.lineCount);
3861 for (i = 0; i < line_count; ++i)
3862 memcpy(&metrics[i], &layout->lines[i].metrics, sizeof(*metrics));
3865 *count = layout->metrics.lineCount;
3866 return max_count >= layout->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3869 static HRESULT layout_update_metrics(struct dwrite_textlayout *layout)
3871 return layout_compute_effective_runs(layout);
3874 static HRESULT WINAPI dwritetextlayout_GetMetrics(IDWriteTextLayout4 *iface, DWRITE_TEXT_METRICS *metrics)
3876 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3877 HRESULT hr;
3879 TRACE("%p, %p.\n", iface, metrics);
3881 hr = layout_update_metrics(layout);
3882 if (hr == S_OK)
3883 memcpy(metrics, &layout->metrics, sizeof(*metrics));
3885 return hr;
3888 static void d2d_rect_offset(D2D1_RECT_F *rect, FLOAT x, FLOAT y)
3890 rect->left += x;
3891 rect->right += x;
3892 rect->top += y;
3893 rect->bottom += y;
3896 static BOOL d2d_rect_is_empty(const D2D1_RECT_F *rect)
3898 return ((rect->left >= rect->right) || (rect->top >= rect->bottom));
3901 static void d2d_rect_union(D2D1_RECT_F *dst, const D2D1_RECT_F *src)
3903 if (d2d_rect_is_empty(dst)) {
3904 if (d2d_rect_is_empty(src)) {
3905 dst->left = dst->right = dst->top = dst->bottom = 0.0f;
3906 return;
3908 else
3909 *dst = *src;
3911 else {
3912 if (!d2d_rect_is_empty(src)) {
3913 dst->left = min(dst->left, src->left);
3914 dst->right = max(dst->right, src->right);
3915 dst->top = min(dst->top, src->top);
3916 dst->bottom = max(dst->bottom, src->bottom);
3921 static void layout_get_erun_bbox(struct dwrite_textlayout *layout, struct layout_effective_run *run, D2D1_RECT_F *bbox)
3923 const struct regular_layout_run *regular = &run->run->u.regular;
3924 UINT32 start_glyph = regular->clustermap[run->start];
3925 D2D1_POINT_2F baseline_origin = { 0 }, *origins;
3926 DWRITE_GLYPH_RUN glyph_run;
3927 unsigned int i;
3928 HRESULT hr;
3930 if (run->bbox.top == run->bbox.bottom)
3932 struct dwrite_glyphbitmap glyph_bitmap;
3933 RECT *bbox;
3935 glyph_run = regular->run;
3936 glyph_run.glyphCount = run->glyphcount;
3937 glyph_run.glyphIndices = &regular->run.glyphIndices[start_glyph];
3938 glyph_run.glyphAdvances = &regular->run.glyphAdvances[start_glyph];
3939 glyph_run.glyphOffsets = &regular->run.glyphOffsets[start_glyph];
3941 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
3942 glyph_bitmap.key = glyph_run.fontFace;
3943 glyph_bitmap.simulations = IDWriteFontFace_GetSimulations(glyph_run.fontFace);
3944 glyph_bitmap.emsize = glyph_run.fontEmSize;
3945 glyph_bitmap.nohint = layout->measuringmode == DWRITE_MEASURING_MODE_NATURAL;
3947 bbox = &glyph_bitmap.bbox;
3949 if (!(origins = heap_calloc(glyph_run.glyphCount, sizeof(*origins))))
3950 return;
3952 if (FAILED(hr = compute_glyph_origins(&glyph_run, layout->measuringmode, baseline_origin, &layout->transform, origins)))
3954 WARN("Failed to compute glyph origins, hr %#x.\n", hr);
3955 heap_free(origins);
3956 return;
3959 for (i = 0; i < glyph_run.glyphCount; ++i)
3961 D2D1_RECT_F glyph_bbox;
3963 glyph_bitmap.glyph = glyph_run.glyphIndices[i];
3964 dwrite_fontface_get_glyph_bbox(&glyph_bitmap);
3966 glyph_bbox.left = bbox->left;
3967 glyph_bbox.top = bbox->top;
3968 glyph_bbox.right = bbox->right;
3969 glyph_bbox.bottom = bbox->bottom;
3971 d2d_rect_offset(&glyph_bbox, origins[i].x, origins[i].y);
3972 d2d_rect_union(&run->bbox, &glyph_bbox);
3975 heap_free(origins);
3978 *bbox = run->bbox;
3979 d2d_rect_offset(bbox, run->origin.x + run->align_dx, run->origin.y);
3982 static void layout_get_inlineobj_bbox(struct dwrite_textlayout *layout, struct layout_effective_inline *run,
3983 D2D1_RECT_F *bbox)
3985 DWRITE_OVERHANG_METRICS overhang_metrics = { 0 };
3986 DWRITE_INLINE_OBJECT_METRICS metrics = { 0 };
3987 HRESULT hr;
3989 if (FAILED(hr = IDWriteInlineObject_GetMetrics(run->object, &metrics))) {
3990 WARN("Failed to get inline object metrics, hr %#x.\n", hr);
3991 memset(bbox, 0, sizeof(*bbox));
3992 return;
3995 bbox->left = run->origin.x + run->align_dx;
3996 bbox->right = bbox->left + metrics.width;
3997 bbox->top = run->origin.y;
3998 bbox->bottom = bbox->top + metrics.height;
4000 IDWriteInlineObject_GetOverhangMetrics(run->object, &overhang_metrics);
4002 bbox->left -= overhang_metrics.left;
4003 bbox->right += overhang_metrics.right;
4004 bbox->top -= overhang_metrics.top;
4005 bbox->bottom += overhang_metrics.bottom;
4008 static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout4 *iface,
4009 DWRITE_OVERHANG_METRICS *overhangs)
4011 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4012 struct layout_effective_inline *inline_run;
4013 struct layout_effective_run *run;
4014 D2D1_RECT_F bbox = { 0 };
4015 HRESULT hr;
4017 TRACE("%p, %p.\n", iface, overhangs);
4019 memset(overhangs, 0, sizeof(*overhangs));
4021 if (!(layout->recompute & RECOMPUTE_OVERHANGS))
4023 *overhangs = layout->overhangs;
4024 return S_OK;
4027 hr = layout_compute_effective_runs(layout);
4028 if (FAILED(hr))
4029 return hr;
4031 LIST_FOR_EACH_ENTRY(run, &layout->eruns, struct layout_effective_run, entry)
4033 D2D1_RECT_F run_bbox;
4035 layout_get_erun_bbox(layout, run, &run_bbox);
4036 d2d_rect_union(&bbox, &run_bbox);
4039 LIST_FOR_EACH_ENTRY(inline_run, &layout->inlineobjects, struct layout_effective_inline, entry)
4041 D2D1_RECT_F object_bbox;
4043 layout_get_inlineobj_bbox(layout, inline_run, &object_bbox);
4044 d2d_rect_union(&bbox, &object_bbox);
4047 /* Deltas from layout box. */
4048 layout->overhangs.left = -bbox.left;
4049 layout->overhangs.top = -bbox.top;
4050 layout->overhangs.right = bbox.right - layout->metrics.layoutWidth;
4051 layout->overhangs.bottom = bbox.bottom - layout->metrics.layoutHeight;
4052 layout->recompute &= ~RECOMPUTE_OVERHANGS;
4054 *overhangs = layout->overhangs;
4056 return S_OK;
4059 static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout4 *iface,
4060 DWRITE_CLUSTER_METRICS *metrics, UINT32 max_count, UINT32 *count)
4062 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4063 HRESULT hr;
4065 TRACE("%p, %p, %u, %p.\n", iface, metrics, max_count, count);
4067 hr = layout_compute(layout);
4068 if (FAILED(hr))
4069 return hr;
4071 if (metrics)
4072 memcpy(metrics, layout->clustermetrics, sizeof(DWRITE_CLUSTER_METRICS) * min(max_count, layout->cluster_count));
4074 *count = layout->cluster_count;
4075 return max_count >= layout->cluster_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
4078 static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout4 *iface, FLOAT* min_width)
4080 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4081 UINT32 start;
4082 FLOAT width;
4083 HRESULT hr;
4085 TRACE("%p, %p.\n", iface, min_width);
4087 if (!min_width)
4088 return E_INVALIDARG;
4090 if (!(layout->recompute & RECOMPUTE_MINIMAL_WIDTH))
4091 goto width_done;
4093 *min_width = 0.0f;
4094 hr = layout_compute(layout);
4095 if (FAILED(hr))
4096 return hr;
4098 /* Find widest word without emergency breaking between clusters, trailing whitespaces
4099 preceding breaking point do not contribute to word width. */
4100 for (start = 0; start < layout->cluster_count;)
4102 UINT32 end = start, j, next;
4104 /* Last cluster always could be wrapped after. */
4105 while (!layout->clustermetrics[end].canWrapLineAfter)
4106 end++;
4107 /* make is so current cluster range that we can wrap after is [start,end) */
4108 end++;
4110 next = end;
4112 /* Ignore trailing whitespace clusters, in case of single space range will
4113 be reduced to empty range, or [start,start+1). */
4114 while (end > start && layout->clustermetrics[end-1].isWhitespace)
4115 end--;
4117 /* check if cluster range exceeds last minimal width */
4118 width = 0.0f;
4119 for (j = start; j < end; j++)
4120 width += layout->clustermetrics[j].width;
4122 start = next;
4124 if (width > layout->minwidth)
4125 layout->minwidth = width;
4127 layout->recompute &= ~RECOMPUTE_MINIMAL_WIDTH;
4129 width_done:
4130 *min_width = layout->minwidth;
4131 return S_OK;
4134 static HRESULT WINAPI dwritetextlayout_HitTestPoint(IDWriteTextLayout4 *iface,
4135 FLOAT pointX, FLOAT pointY, BOOL* is_trailinghit, BOOL* is_inside, DWRITE_HIT_TEST_METRICS *metrics)
4137 FIXME("%p, %.8e, %.8e, %p, %p, %p): stub\n", iface, pointX, pointY, is_trailinghit, is_inside, metrics);
4139 return E_NOTIMPL;
4142 static HRESULT WINAPI dwritetextlayout_HitTestTextPosition(IDWriteTextLayout4 *iface,
4143 UINT32 textPosition, BOOL is_trailinghit, FLOAT *pointX, FLOAT *pointY, DWRITE_HIT_TEST_METRICS *metrics)
4145 FIXME("%p, %u, %d, %p, %p, %p): stub\n", iface, textPosition, is_trailinghit, pointX, pointY, metrics);
4147 return E_NOTIMPL;
4150 static HRESULT WINAPI dwritetextlayout_HitTestTextRange(IDWriteTextLayout4 *iface,
4151 UINT32 textPosition, UINT32 textLength, FLOAT originX, FLOAT originY,
4152 DWRITE_HIT_TEST_METRICS *metrics, UINT32 max_metricscount, UINT32* actual_metricscount)
4154 FIXME("%p, %u, %u, %f, %f, %p, %u, %p): stub\n", iface, textPosition, textLength, originX, originY, metrics,
4155 max_metricscount, actual_metricscount);
4157 return E_NOTIMPL;
4160 static HRESULT WINAPI dwritetextlayout1_SetPairKerning(IDWriteTextLayout4 *iface, BOOL is_pairkerning_enabled,
4161 DWRITE_TEXT_RANGE range)
4163 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4164 struct layout_range_attr_value value;
4166 TRACE("%p, %d, %s.\n", iface, is_pairkerning_enabled, debugstr_range(&range));
4168 value.range = range;
4169 value.u.pair_kerning = !!is_pairkerning_enabled;
4170 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_PAIR_KERNING, &value);
4173 static HRESULT WINAPI dwritetextlayout1_GetPairKerning(IDWriteTextLayout4 *iface, UINT32 position,
4174 BOOL *is_pairkerning_enabled, DWRITE_TEXT_RANGE *r)
4176 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4177 struct layout_range *range;
4179 TRACE("%p, %u, %p, %p.\n", iface, position, is_pairkerning_enabled, r);
4181 range = get_layout_range_by_pos(layout, position);
4182 *is_pairkerning_enabled = range->pair_kerning;
4184 return return_range(&range->h, r);
4187 static HRESULT WINAPI dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout4 *iface, FLOAT leading, FLOAT trailing,
4188 FLOAT min_advance, DWRITE_TEXT_RANGE range)
4190 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4191 struct layout_range_attr_value value;
4193 TRACE("%p, %.8e, %.8e, %.8e, %s.\n", iface, leading, trailing, min_advance, debugstr_range(&range));
4195 if (min_advance < 0.0f)
4196 return E_INVALIDARG;
4198 value.range = range;
4199 value.u.spacing.leading = leading;
4200 value.u.spacing.trailing = trailing;
4201 value.u.spacing.min_advance = min_advance;
4202 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_SPACING, &value);
4205 static HRESULT WINAPI dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout4 *iface, UINT32 position, FLOAT *leading,
4206 FLOAT *trailing, FLOAT *min_advance, DWRITE_TEXT_RANGE *r)
4208 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4209 struct layout_range_spacing *range;
4211 TRACE("%p, %u, %p, %p, %p, %p.\n", iface, position, leading, trailing, min_advance, r);
4213 range = (struct layout_range_spacing *)get_layout_range_header_by_pos(&layout->spacing, position);
4214 *leading = range->leading;
4215 *trailing = range->trailing;
4216 *min_advance = range->min_advance;
4218 return return_range(&range->h, r);
4221 static HRESULT WINAPI dwritetextlayout2_GetMetrics(IDWriteTextLayout4 *iface, DWRITE_TEXT_METRICS1 *metrics)
4223 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4224 HRESULT hr;
4226 TRACE("%p, %p.\n", iface, metrics);
4228 if (SUCCEEDED(hr = layout_update_metrics(layout)))
4229 *metrics = layout->metrics;
4231 return hr;
4234 static HRESULT layout_set_vertical_orientation(struct dwrite_textlayout *layout,
4235 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4237 BOOL changed;
4238 HRESULT hr;
4240 if (FAILED(hr = format_set_vertical_orientation(&layout->format, orientation, &changed)))
4241 return hr;
4243 if (changed)
4244 layout->recompute = RECOMPUTE_EVERYTHING;
4246 return S_OK;
4249 static HRESULT WINAPI dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout4 *iface,
4250 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4252 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4254 TRACE("%p, %d.\n", iface, orientation);
4256 return layout_set_vertical_orientation(layout, orientation);
4259 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout4 *iface)
4261 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4263 TRACE("%p.\n", iface);
4265 return layout->format.vertical_orientation;
4268 static HRESULT WINAPI dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout4 *iface, BOOL lastline_wrapping_enabled)
4270 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4272 TRACE("%p, %d.\n", iface, lastline_wrapping_enabled);
4274 return IDWriteTextFormat3_SetLastLineWrapping(&layout->IDWriteTextFormat3_iface, lastline_wrapping_enabled);
4277 static BOOL WINAPI dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout4 *iface)
4279 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4281 TRACE("%p.\n", iface);
4283 return IDWriteTextFormat3_GetLastLineWrapping(&layout->IDWriteTextFormat3_iface);
4286 static HRESULT WINAPI dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout4 *iface,
4287 DWRITE_OPTICAL_ALIGNMENT alignment)
4289 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4291 TRACE("%p, %d.\n", iface, alignment);
4293 return IDWriteTextFormat3_SetOpticalAlignment(&layout->IDWriteTextFormat3_iface, alignment);
4296 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout4 *iface)
4298 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4300 TRACE("%p.\n", iface);
4302 return IDWriteTextFormat3_GetOpticalAlignment(&layout->IDWriteTextFormat3_iface);
4305 static HRESULT WINAPI dwritetextlayout2_SetFontFallback(IDWriteTextLayout4 *iface, IDWriteFontFallback *fallback)
4307 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4309 TRACE("%p, %p.\n", iface, fallback);
4311 return set_fontfallback_for_format(&layout->format, fallback);
4314 static HRESULT WINAPI dwritetextlayout2_GetFontFallback(IDWriteTextLayout4 *iface, IDWriteFontFallback **fallback)
4316 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4318 TRACE("%p, %p.\n", iface, fallback);
4320 return get_fontfallback_from_format(&layout->format, fallback);
4323 static HRESULT WINAPI dwritetextlayout3_InvalidateLayout(IDWriteTextLayout4 *iface)
4325 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4327 TRACE("%p.\n", iface);
4329 layout->recompute = RECOMPUTE_EVERYTHING;
4330 return S_OK;
4333 static HRESULT WINAPI dwritetextlayout3_SetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING const *spacing)
4335 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4336 BOOL changed;
4337 HRESULT hr;
4339 TRACE("%p, %p.\n", iface, spacing);
4341 hr = format_set_linespacing(&layout->format, spacing, &changed);
4342 if (FAILED(hr))
4343 return hr;
4345 if (changed)
4347 if (!(layout->recompute & RECOMPUTE_LINES))
4349 UINT32 line;
4351 for (line = 0; line < layout->metrics.lineCount; line++)
4352 layout_apply_line_spacing(layout, line);
4354 layout_set_line_positions(layout);
4357 layout->recompute |= RECOMPUTE_OVERHANGS;
4360 return S_OK;
4363 static HRESULT WINAPI dwritetextlayout3_GetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING *spacing)
4365 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4367 TRACE("%p, %p.\n", iface, spacing);
4369 *spacing = layout->format.spacing;
4370 return S_OK;
4373 static HRESULT WINAPI dwritetextlayout3_GetLineMetrics(IDWriteTextLayout4 *iface, DWRITE_LINE_METRICS1 *metrics,
4374 UINT32 max_count, UINT32 *count)
4376 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4377 unsigned int line_count;
4378 HRESULT hr;
4379 size_t i;
4381 TRACE("%p, %p, %u, %p.\n", iface, metrics, max_count, count);
4383 if (FAILED(hr = layout_compute_effective_runs(layout)))
4384 return hr;
4386 if (metrics)
4388 line_count = min(max_count, layout->metrics.lineCount);
4389 for (i = 0; i < line_count; ++i)
4390 metrics[i] = layout->lines[i].metrics;
4393 *count = layout->metrics.lineCount;
4394 return max_count >= layout->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
4397 static HRESULT WINAPI dwritetextlayout4_SetFontAxisValues(IDWriteTextLayout4 *iface,
4398 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, DWRITE_TEXT_RANGE range)
4400 FIXME("%p, %p, %u, %s.\n", iface, axis_values, num_values, debugstr_range(&range));
4402 return E_NOTIMPL;
4405 static UINT32 WINAPI dwritetextlayout4_GetFontAxisValueCount(IDWriteTextLayout4 *iface, UINT32 pos)
4407 FIXME("%p, %u.\n", iface, pos);
4409 return 0;
4412 static HRESULT WINAPI dwritetextlayout4_GetFontAxisValues(IDWriteTextLayout4 *iface, UINT32 pos,
4413 DWRITE_FONT_AXIS_VALUE *values, UINT32 num_values, DWRITE_TEXT_RANGE *range)
4415 FIXME("%p, %u, %p, %u, %p.\n", iface, pos, values, num_values, range);
4417 return E_NOTIMPL;
4420 static DWRITE_AUTOMATIC_FONT_AXES WINAPI dwritetextlayout4_GetAutomaticFontAxes(IDWriteTextLayout4 *iface)
4422 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4424 TRACE("%p.\n", iface);
4426 return layout->format.automatic_axes;
4429 static HRESULT WINAPI dwritetextlayout4_SetAutomaticFontAxes(IDWriteTextLayout4 *iface,
4430 DWRITE_AUTOMATIC_FONT_AXES axes)
4432 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4434 TRACE("%p, %d.\n", iface, axes);
4436 if ((unsigned int)axes > DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE)
4437 return E_INVALIDARG;
4439 layout->format.automatic_axes = axes;
4440 return S_OK;
4443 static const IDWriteTextLayout4Vtbl dwritetextlayoutvtbl =
4445 dwritetextlayout_QueryInterface,
4446 dwritetextlayout_AddRef,
4447 dwritetextlayout_Release,
4448 dwritetextlayout_SetTextAlignment,
4449 dwritetextlayout_SetParagraphAlignment,
4450 dwritetextlayout_SetWordWrapping,
4451 dwritetextlayout_SetReadingDirection,
4452 dwritetextlayout_SetFlowDirection,
4453 dwritetextlayout_SetIncrementalTabStop,
4454 dwritetextlayout_SetTrimming,
4455 dwritetextlayout_SetLineSpacing,
4456 dwritetextlayout_GetTextAlignment,
4457 dwritetextlayout_GetParagraphAlignment,
4458 dwritetextlayout_GetWordWrapping,
4459 dwritetextlayout_GetReadingDirection,
4460 dwritetextlayout_GetFlowDirection,
4461 dwritetextlayout_GetIncrementalTabStop,
4462 dwritetextlayout_GetTrimming,
4463 dwritetextlayout_GetLineSpacing,
4464 dwritetextlayout_GetFontCollection,
4465 dwritetextlayout_GetFontFamilyNameLength,
4466 dwritetextlayout_GetFontFamilyName,
4467 dwritetextlayout_GetFontWeight,
4468 dwritetextlayout_GetFontStyle,
4469 dwritetextlayout_GetFontStretch,
4470 dwritetextlayout_GetFontSize,
4471 dwritetextlayout_GetLocaleNameLength,
4472 dwritetextlayout_GetLocaleName,
4473 dwritetextlayout_SetMaxWidth,
4474 dwritetextlayout_SetMaxHeight,
4475 dwritetextlayout_SetFontCollection,
4476 dwritetextlayout_SetFontFamilyName,
4477 dwritetextlayout_SetFontWeight,
4478 dwritetextlayout_SetFontStyle,
4479 dwritetextlayout_SetFontStretch,
4480 dwritetextlayout_SetFontSize,
4481 dwritetextlayout_SetUnderline,
4482 dwritetextlayout_SetStrikethrough,
4483 dwritetextlayout_SetDrawingEffect,
4484 dwritetextlayout_SetInlineObject,
4485 dwritetextlayout_SetTypography,
4486 dwritetextlayout_SetLocaleName,
4487 dwritetextlayout_GetMaxWidth,
4488 dwritetextlayout_GetMaxHeight,
4489 dwritetextlayout_layout_GetFontCollection,
4490 dwritetextlayout_layout_GetFontFamilyNameLength,
4491 dwritetextlayout_layout_GetFontFamilyName,
4492 dwritetextlayout_layout_GetFontWeight,
4493 dwritetextlayout_layout_GetFontStyle,
4494 dwritetextlayout_layout_GetFontStretch,
4495 dwritetextlayout_layout_GetFontSize,
4496 dwritetextlayout_GetUnderline,
4497 dwritetextlayout_GetStrikethrough,
4498 dwritetextlayout_GetDrawingEffect,
4499 dwritetextlayout_GetInlineObject,
4500 dwritetextlayout_GetTypography,
4501 dwritetextlayout_layout_GetLocaleNameLength,
4502 dwritetextlayout_layout_GetLocaleName,
4503 dwritetextlayout_Draw,
4504 dwritetextlayout_GetLineMetrics,
4505 dwritetextlayout_GetMetrics,
4506 dwritetextlayout_GetOverhangMetrics,
4507 dwritetextlayout_GetClusterMetrics,
4508 dwritetextlayout_DetermineMinWidth,
4509 dwritetextlayout_HitTestPoint,
4510 dwritetextlayout_HitTestTextPosition,
4511 dwritetextlayout_HitTestTextRange,
4512 dwritetextlayout1_SetPairKerning,
4513 dwritetextlayout1_GetPairKerning,
4514 dwritetextlayout1_SetCharacterSpacing,
4515 dwritetextlayout1_GetCharacterSpacing,
4516 dwritetextlayout2_GetMetrics,
4517 dwritetextlayout2_SetVerticalGlyphOrientation,
4518 dwritetextlayout2_GetVerticalGlyphOrientation,
4519 dwritetextlayout2_SetLastLineWrapping,
4520 dwritetextlayout2_GetLastLineWrapping,
4521 dwritetextlayout2_SetOpticalAlignment,
4522 dwritetextlayout2_GetOpticalAlignment,
4523 dwritetextlayout2_SetFontFallback,
4524 dwritetextlayout2_GetFontFallback,
4525 dwritetextlayout3_InvalidateLayout,
4526 dwritetextlayout3_SetLineSpacing,
4527 dwritetextlayout3_GetLineSpacing,
4528 dwritetextlayout3_GetLineMetrics,
4529 dwritetextlayout4_SetFontAxisValues,
4530 dwritetextlayout4_GetFontAxisValueCount,
4531 dwritetextlayout4_GetFontAxisValues,
4532 dwritetextlayout4_GetAutomaticFontAxes,
4533 dwritetextlayout4_SetAutomaticFontAxes,
4536 static HRESULT WINAPI dwritetextformat_layout_QueryInterface(IDWriteTextFormat3 *iface, REFIID riid, void **obj)
4538 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4540 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
4542 return IDWriteTextLayout4_QueryInterface(&layout->IDWriteTextLayout4_iface, riid, obj);
4545 static ULONG WINAPI dwritetextformat_layout_AddRef(IDWriteTextFormat3 *iface)
4547 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4548 return IDWriteTextLayout4_AddRef(&layout->IDWriteTextLayout4_iface);
4551 static ULONG WINAPI dwritetextformat_layout_Release(IDWriteTextFormat3 *iface)
4553 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4554 return IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
4557 static HRESULT WINAPI dwritetextformat_layout_SetTextAlignment(IDWriteTextFormat3 *iface,
4558 DWRITE_TEXT_ALIGNMENT alignment)
4560 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4561 BOOL changed;
4562 HRESULT hr;
4564 TRACE("%p, %d.\n", iface, alignment);
4566 hr = format_set_textalignment(&layout->format, alignment, &changed);
4567 if (FAILED(hr))
4568 return hr;
4570 if (changed)
4572 /* if layout is not ready there's nothing to align */
4573 if (!(layout->recompute & RECOMPUTE_LINES))
4574 layout_apply_text_alignment(layout);
4575 layout->recompute |= RECOMPUTE_OVERHANGS;
4578 return S_OK;
4581 static HRESULT WINAPI dwritetextformat_layout_SetParagraphAlignment(IDWriteTextFormat3 *iface,
4582 DWRITE_PARAGRAPH_ALIGNMENT alignment)
4584 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4585 BOOL changed;
4586 HRESULT hr;
4588 TRACE("%p, %d.\n", iface, alignment);
4590 hr = format_set_paralignment(&layout->format, alignment, &changed);
4591 if (FAILED(hr))
4592 return hr;
4594 if (changed)
4596 /* if layout is not ready there's nothing to align */
4597 if (!(layout->recompute & RECOMPUTE_LINES))
4598 layout_apply_par_alignment(layout);
4599 layout->recompute |= RECOMPUTE_OVERHANGS;
4602 return S_OK;
4605 static HRESULT WINAPI dwritetextformat_layout_SetWordWrapping(IDWriteTextFormat3 *iface, DWRITE_WORD_WRAPPING wrapping)
4607 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4608 BOOL changed;
4609 HRESULT hr;
4611 TRACE("%p, %d.\n", iface, wrapping);
4613 hr = format_set_wordwrapping(&layout->format, wrapping, &changed);
4614 if (FAILED(hr))
4615 return hr;
4617 if (changed)
4618 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
4620 return S_OK;
4623 static HRESULT WINAPI dwritetextformat_layout_SetReadingDirection(IDWriteTextFormat3 *iface,
4624 DWRITE_READING_DIRECTION direction)
4626 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4627 BOOL changed;
4628 HRESULT hr;
4630 TRACE("%p, %d.\n", iface, direction);
4632 hr = format_set_readingdirection(&layout->format, direction, &changed);
4633 if (FAILED(hr))
4634 return hr;
4636 if (changed)
4637 layout->recompute = RECOMPUTE_EVERYTHING;
4639 return S_OK;
4642 static HRESULT WINAPI dwritetextformat_layout_SetFlowDirection(IDWriteTextFormat3 *iface,
4643 DWRITE_FLOW_DIRECTION direction)
4645 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4646 BOOL changed;
4647 HRESULT hr;
4649 TRACE("%p, %d.\n", iface, direction);
4651 hr = format_set_flowdirection(&layout->format, direction, &changed);
4652 if (FAILED(hr))
4653 return hr;
4655 if (changed)
4656 layout->recompute = RECOMPUTE_EVERYTHING;
4658 return S_OK;
4661 static HRESULT WINAPI dwritetextformat_layout_SetIncrementalTabStop(IDWriteTextFormat3 *iface, FLOAT tabstop)
4663 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4665 TRACE("%p, %.8e.\n", iface, tabstop);
4667 if (tabstop <= 0.0f)
4668 return E_INVALIDARG;
4670 layout->format.tabstop = tabstop;
4671 return S_OK;
4674 static HRESULT WINAPI dwritetextformat_layout_SetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING const *trimming,
4675 IDWriteInlineObject *trimming_sign)
4677 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4678 BOOL changed;
4679 HRESULT hr;
4681 TRACE("%p, %p, %p.\n", iface, trimming, trimming_sign);
4683 hr = format_set_trimming(&layout->format, trimming, trimming_sign, &changed);
4685 if (changed)
4686 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
4688 return hr;
4691 static HRESULT WINAPI dwritetextformat_layout_SetLineSpacing(IDWriteTextFormat3 *iface,
4692 DWRITE_LINE_SPACING_METHOD method, FLOAT height, FLOAT baseline)
4694 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4695 DWRITE_LINE_SPACING spacing;
4697 TRACE("%p, %d, %.8e, %.8e.\n", iface, method, height, baseline);
4699 spacing = layout->format.spacing;
4700 spacing.method = method;
4701 spacing.height = height;
4702 spacing.baseline = baseline;
4703 return IDWriteTextLayout4_SetLineSpacing(&layout->IDWriteTextLayout4_iface, &spacing);
4706 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_layout_GetTextAlignment(IDWriteTextFormat3 *iface)
4708 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4710 TRACE("%p.\n", iface);
4712 return layout->format.textalignment;
4715 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_layout_GetParagraphAlignment(IDWriteTextFormat3 *iface)
4717 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4719 TRACE("%p.\n", iface);
4721 return layout->format.paralign;
4724 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_layout_GetWordWrapping(IDWriteTextFormat3 *iface)
4726 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4728 TRACE("%p.\n", iface);
4730 return layout->format.wrapping;
4733 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_layout_GetReadingDirection(IDWriteTextFormat3 *iface)
4735 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4737 TRACE("%p.\n", iface);
4739 return layout->format.readingdir;
4742 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_layout_GetFlowDirection(IDWriteTextFormat3 *iface)
4744 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4746 TRACE("%p.\n", iface);
4748 return layout->format.flow;
4751 static FLOAT WINAPI dwritetextformat_layout_GetIncrementalTabStop(IDWriteTextFormat3 *iface)
4753 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4755 TRACE("%p.\n", iface);
4757 return layout->format.tabstop;
4760 static HRESULT WINAPI dwritetextformat_layout_GetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING *options,
4761 IDWriteInlineObject **trimming_sign)
4763 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4765 TRACE("%p, %p, %p.\n", iface, options, trimming_sign);
4767 *options = layout->format.trimming;
4768 *trimming_sign = layout->format.trimmingsign;
4769 if (*trimming_sign)
4770 IDWriteInlineObject_AddRef(*trimming_sign);
4771 return S_OK;
4774 static HRESULT WINAPI dwritetextformat_layout_GetLineSpacing(IDWriteTextFormat3 *iface,
4775 DWRITE_LINE_SPACING_METHOD *method, FLOAT *spacing, FLOAT *baseline)
4777 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4779 TRACE("%p, %p, %p, %p.\n", iface, method, spacing, baseline);
4781 *method = layout->format.spacing.method;
4782 *spacing = layout->format.spacing.height;
4783 *baseline = layout->format.spacing.baseline;
4784 return S_OK;
4787 static HRESULT WINAPI dwritetextformat_layout_GetFontCollection(IDWriteTextFormat3 *iface,
4788 IDWriteFontCollection **collection)
4790 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4792 TRACE("%p, %p.\n", iface, collection);
4794 *collection = layout->format.collection;
4795 if (*collection)
4796 IDWriteFontCollection_AddRef(*collection);
4797 return S_OK;
4800 static UINT32 WINAPI dwritetextformat_layout_GetFontFamilyNameLength(IDWriteTextFormat3 *iface)
4802 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4804 TRACE("%p.\n", iface);
4806 return layout->format.family_len;
4809 static HRESULT WINAPI dwritetextformat_layout_GetFontFamilyName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
4811 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4813 TRACE("%p, %p, %u.\n", iface, name, size);
4815 if (size <= layout->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
4816 wcscpy(name, layout->format.family_name);
4817 return S_OK;
4820 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_layout_GetFontWeight(IDWriteTextFormat3 *iface)
4822 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4824 TRACE("%p.\n", iface);
4826 return layout->format.weight;
4829 static DWRITE_FONT_STYLE WINAPI dwritetextformat_layout_GetFontStyle(IDWriteTextFormat3 *iface)
4831 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4833 TRACE("%p.\n", iface);
4835 return layout->format.style;
4838 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_layout_GetFontStretch(IDWriteTextFormat3 *iface)
4840 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4842 TRACE("%p.\n", iface);
4844 return layout->format.stretch;
4847 static FLOAT WINAPI dwritetextformat_layout_GetFontSize(IDWriteTextFormat3 *iface)
4849 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4851 TRACE("%p.\n", iface);
4853 return layout->format.fontsize;
4856 static UINT32 WINAPI dwritetextformat_layout_GetLocaleNameLength(IDWriteTextFormat3 *iface)
4858 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4860 TRACE("%p.\n", iface);
4862 return layout->format.locale_len;
4865 static HRESULT WINAPI dwritetextformat_layout_GetLocaleName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
4867 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4869 TRACE("%p, %p, %u.\n", iface, name, size);
4871 if (size <= layout->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
4872 wcscpy(name, layout->format.locale);
4873 return S_OK;
4876 static HRESULT WINAPI dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat3 *iface,
4877 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4879 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4881 TRACE("%p, %d.\n", iface, orientation);
4883 return layout_set_vertical_orientation(layout, orientation);
4886 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat3 *iface)
4888 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4890 TRACE("%p.\n", iface);
4892 return layout->format.vertical_orientation;
4895 static HRESULT WINAPI dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat3 *iface,
4896 BOOL lastline_wrapping_enabled)
4898 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4900 TRACE("%p, %d.\n", iface, lastline_wrapping_enabled);
4902 layout->format.last_line_wrapping = !!lastline_wrapping_enabled;
4903 return S_OK;
4906 static BOOL WINAPI dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat3 *iface)
4908 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4910 TRACE("%p.\n", iface);
4912 return layout->format.last_line_wrapping;
4915 static HRESULT WINAPI dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat3 *iface,
4916 DWRITE_OPTICAL_ALIGNMENT alignment)
4918 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4920 TRACE("%p, %d.\n", iface, alignment);
4922 return format_set_optical_alignment(&layout->format, alignment);
4925 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat3 *iface)
4927 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4929 TRACE("%p.\n", iface);
4931 return layout->format.optical_alignment;
4934 static HRESULT WINAPI dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat3 *iface,
4935 IDWriteFontFallback *fallback)
4937 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4939 TRACE("%p, %p.\n", iface, fallback);
4941 return IDWriteTextLayout4_SetFontFallback(&layout->IDWriteTextLayout4_iface, fallback);
4944 static HRESULT WINAPI dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat3 *iface,
4945 IDWriteFontFallback **fallback)
4947 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4949 TRACE("%p, %p.\n", iface, fallback);
4951 return IDWriteTextLayout4_GetFontFallback(&layout->IDWriteTextLayout4_iface, fallback);
4954 static HRESULT WINAPI dwritetextformat2_layout_SetLineSpacing(IDWriteTextFormat3 *iface,
4955 DWRITE_LINE_SPACING const *spacing)
4957 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4958 return IDWriteTextLayout4_SetLineSpacing(&layout->IDWriteTextLayout4_iface, spacing);
4961 static HRESULT WINAPI dwritetextformat2_layout_GetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING *spacing)
4963 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4964 return IDWriteTextLayout4_GetLineSpacing(&layout->IDWriteTextLayout4_iface, spacing);
4967 static HRESULT WINAPI dwritetextformat3_layout_SetFontAxisValues(IDWriteTextFormat3 *iface,
4968 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values)
4970 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4972 TRACE("%p, %p, %u.\n", iface, axis_values, num_values);
4974 return format_set_font_axisvalues(&layout->format, axis_values, num_values);
4977 static UINT32 WINAPI dwritetextformat3_layout_GetFontAxisValueCount(IDWriteTextFormat3 *iface)
4979 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4981 TRACE("%p.\n", iface);
4983 return layout->format.axis_values_count;
4986 static HRESULT WINAPI dwritetextformat3_layout_GetFontAxisValues(IDWriteTextFormat3 *iface,
4987 DWRITE_FONT_AXIS_VALUE *axis_values, UINT32 num_values)
4989 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4991 TRACE("%p, %p, %u.\n", iface, axis_values, num_values);
4993 return format_get_font_axisvalues(&layout->format, axis_values, num_values);
4996 static DWRITE_AUTOMATIC_FONT_AXES WINAPI dwritetextformat3_layout_GetAutomaticFontAxes(IDWriteTextFormat3 *iface)
4998 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4999 return IDWriteTextLayout4_GetAutomaticFontAxes(&layout->IDWriteTextLayout4_iface);
5002 static HRESULT WINAPI dwritetextformat3_layout_SetAutomaticFontAxes(IDWriteTextFormat3 *iface,
5003 DWRITE_AUTOMATIC_FONT_AXES axes)
5005 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
5006 return IDWriteTextLayout4_SetAutomaticFontAxes(&layout->IDWriteTextLayout4_iface, axes);
5009 static const IDWriteTextFormat3Vtbl dwritetextformat3_layout_vtbl =
5011 dwritetextformat_layout_QueryInterface,
5012 dwritetextformat_layout_AddRef,
5013 dwritetextformat_layout_Release,
5014 dwritetextformat_layout_SetTextAlignment,
5015 dwritetextformat_layout_SetParagraphAlignment,
5016 dwritetextformat_layout_SetWordWrapping,
5017 dwritetextformat_layout_SetReadingDirection,
5018 dwritetextformat_layout_SetFlowDirection,
5019 dwritetextformat_layout_SetIncrementalTabStop,
5020 dwritetextformat_layout_SetTrimming,
5021 dwritetextformat_layout_SetLineSpacing,
5022 dwritetextformat_layout_GetTextAlignment,
5023 dwritetextformat_layout_GetParagraphAlignment,
5024 dwritetextformat_layout_GetWordWrapping,
5025 dwritetextformat_layout_GetReadingDirection,
5026 dwritetextformat_layout_GetFlowDirection,
5027 dwritetextformat_layout_GetIncrementalTabStop,
5028 dwritetextformat_layout_GetTrimming,
5029 dwritetextformat_layout_GetLineSpacing,
5030 dwritetextformat_layout_GetFontCollection,
5031 dwritetextformat_layout_GetFontFamilyNameLength,
5032 dwritetextformat_layout_GetFontFamilyName,
5033 dwritetextformat_layout_GetFontWeight,
5034 dwritetextformat_layout_GetFontStyle,
5035 dwritetextformat_layout_GetFontStretch,
5036 dwritetextformat_layout_GetFontSize,
5037 dwritetextformat_layout_GetLocaleNameLength,
5038 dwritetextformat_layout_GetLocaleName,
5039 dwritetextformat1_layout_SetVerticalGlyphOrientation,
5040 dwritetextformat1_layout_GetVerticalGlyphOrientation,
5041 dwritetextformat1_layout_SetLastLineWrapping,
5042 dwritetextformat1_layout_GetLastLineWrapping,
5043 dwritetextformat1_layout_SetOpticalAlignment,
5044 dwritetextformat1_layout_GetOpticalAlignment,
5045 dwritetextformat1_layout_SetFontFallback,
5046 dwritetextformat1_layout_GetFontFallback,
5047 dwritetextformat2_layout_SetLineSpacing,
5048 dwritetextformat2_layout_GetLineSpacing,
5049 dwritetextformat3_layout_SetFontAxisValues,
5050 dwritetextformat3_layout_GetFontAxisValueCount,
5051 dwritetextformat3_layout_GetFontAxisValues,
5052 dwritetextformat3_layout_GetAutomaticFontAxes,
5053 dwritetextformat3_layout_SetAutomaticFontAxes,
5056 static HRESULT WINAPI dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink1 *iface,
5057 REFIID riid, void **obj)
5059 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink1) ||
5060 IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) ||
5061 IsEqualIID(riid, &IID_IUnknown))
5063 *obj = iface;
5064 IDWriteTextAnalysisSink1_AddRef(iface);
5065 return S_OK;
5068 WARN("%s not implemented.\n", debugstr_guid(riid));
5070 *obj = NULL;
5071 return E_NOINTERFACE;
5074 static ULONG WINAPI dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink1 *iface)
5076 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
5077 return IDWriteTextLayout4_AddRef(&layout->IDWriteTextLayout4_iface);
5080 static ULONG WINAPI dwritetextlayout_sink_Release(IDWriteTextAnalysisSink1 *iface)
5082 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
5083 return IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
5086 static HRESULT WINAPI dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink1 *iface,
5087 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
5089 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
5090 struct layout_run *run;
5091 HRESULT hr;
5093 TRACE("[%u,%u) script=%u:%s\n", position, position + length, sa->script, debugstr_sa_script(sa->script));
5095 if (FAILED(hr = alloc_layout_run(LAYOUT_RUN_REGULAR, position, &run)))
5096 return hr;
5098 run->u.regular.descr.string = &layout->str[position];
5099 run->u.regular.descr.stringLength = length;
5100 run->u.regular.descr.textPosition = position;
5101 run->u.regular.sa = *sa;
5102 list_add_tail(&layout->runs, &run->entry);
5103 return S_OK;
5106 static HRESULT WINAPI dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink1 *iface,
5107 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
5109 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
5111 if (position + length > layout->len)
5112 return E_FAIL;
5114 memcpy(&layout->nominal_breakpoints[position], breakpoints, length*sizeof(DWRITE_LINE_BREAKPOINT));
5115 return S_OK;
5118 static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink1 *iface, UINT32 position,
5119 UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
5121 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
5122 struct layout_run *cur_run;
5123 HRESULT hr;
5125 TRACE("[%u,%u) %u %u\n", position, position + length, explicitLevel, resolvedLevel);
5127 LIST_FOR_EACH_ENTRY(cur_run, &layout->runs, struct layout_run, entry) {
5128 struct regular_layout_run *cur = &cur_run->u.regular;
5129 struct layout_run *run;
5131 if (cur_run->kind == LAYOUT_RUN_INLINE)
5132 continue;
5134 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
5135 if (position < cur->descr.textPosition || position >= cur->descr.textPosition + cur->descr.stringLength)
5136 continue;
5138 /* full hit - just set run level */
5139 if (cur->descr.textPosition == position && cur->descr.stringLength == length) {
5140 cur->run.bidiLevel = resolvedLevel;
5141 break;
5144 /* current run is fully covered, move to next one */
5145 if (cur->descr.textPosition == position && cur->descr.stringLength < length) {
5146 cur->run.bidiLevel = resolvedLevel;
5147 position += cur->descr.stringLength;
5148 length -= cur->descr.stringLength;
5149 continue;
5152 /* all fully covered runs are processed at this point, reuse existing run for remaining
5153 reported bidi range and add another run for the rest of original one */
5155 if (FAILED(hr = alloc_layout_run(LAYOUT_RUN_REGULAR, position + length, &run)))
5156 return hr;
5158 *run = *cur_run;
5159 run->u.regular.descr.textPosition = position + length;
5160 run->u.regular.descr.stringLength = cur->descr.stringLength - length;
5161 run->u.regular.descr.string = &layout->str[position + length];
5163 /* reduce existing run */
5164 cur->run.bidiLevel = resolvedLevel;
5165 cur->descr.stringLength = length;
5167 list_add_after(&cur_run->entry, &run->entry);
5168 break;
5171 return S_OK;
5174 static HRESULT WINAPI dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink1 *iface,
5175 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
5177 return E_NOTIMPL;
5180 static HRESULT WINAPI dwritetextlayout_sink_SetGlyphOrientation(IDWriteTextAnalysisSink1 *iface,
5181 UINT32 position, UINT32 length, DWRITE_GLYPH_ORIENTATION_ANGLE angle, UINT8 adjusted_bidi_level,
5182 BOOL is_sideways, BOOL is_rtl)
5184 return E_NOTIMPL;
5187 static const IDWriteTextAnalysisSink1Vtbl dwritetextlayoutsinkvtbl = {
5188 dwritetextlayout_sink_QueryInterface,
5189 dwritetextlayout_sink_AddRef,
5190 dwritetextlayout_sink_Release,
5191 dwritetextlayout_sink_SetScriptAnalysis,
5192 dwritetextlayout_sink_SetLineBreakpoints,
5193 dwritetextlayout_sink_SetBidiLevel,
5194 dwritetextlayout_sink_SetNumberSubstitution,
5195 dwritetextlayout_sink_SetGlyphOrientation
5198 static HRESULT WINAPI dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource1 *iface,
5199 REFIID riid, void **obj)
5201 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource1) ||
5202 IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) ||
5203 IsEqualIID(riid, &IID_IUnknown))
5205 *obj = iface;
5206 IDWriteTextAnalysisSource1_AddRef(iface);
5207 return S_OK;
5210 WARN("%s not implemented.\n", debugstr_guid(riid));
5212 *obj = NULL;
5213 return E_NOINTERFACE;
5216 static ULONG WINAPI dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource1 *iface)
5218 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5219 return IDWriteTextLayout4_AddRef(&layout->IDWriteTextLayout4_iface);
5222 static ULONG WINAPI dwritetextlayout_source_Release(IDWriteTextAnalysisSource1 *iface)
5224 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5225 return IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
5228 static HRESULT WINAPI dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource1 *iface,
5229 UINT32 position, WCHAR const** text, UINT32* text_len)
5231 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5233 TRACE("%p, %u, %p, %p.\n", iface, position, text, text_len);
5235 if (position < layout->len) {
5236 *text = &layout->str[position];
5237 *text_len = layout->len - position;
5239 else {
5240 *text = NULL;
5241 *text_len = 0;
5244 return S_OK;
5247 static HRESULT WINAPI dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource1 *iface,
5248 UINT32 position, WCHAR const** text, UINT32* text_len)
5250 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5252 TRACE("%p, %u, %p, %p.\n", iface, position, text, text_len);
5254 if (position > 0 && position < layout->len) {
5255 *text = layout->str;
5256 *text_len = position;
5258 else {
5259 *text = NULL;
5260 *text_len = 0;
5263 return S_OK;
5266 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource1 *iface)
5268 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5269 return IDWriteTextLayout4_GetReadingDirection(&layout->IDWriteTextLayout4_iface);
5272 static HRESULT WINAPI dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource1 *iface,
5273 UINT32 position, UINT32* text_len, WCHAR const** locale)
5275 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5276 struct layout_range *range = get_layout_range_by_pos(layout, position);
5278 if (position < layout->len) {
5279 struct layout_range *next;
5281 *locale = range->locale;
5282 *text_len = range->h.range.length - position;
5284 next = LIST_ENTRY(list_next(&layout->ranges, &range->h.entry), struct layout_range, h.entry);
5285 while (next && next->h.range.startPosition < layout->len && !wcscmp(range->locale, next->locale))
5287 *text_len += next->h.range.length;
5288 next = LIST_ENTRY(list_next(&layout->ranges, &next->h.entry), struct layout_range, h.entry);
5291 *text_len = min(*text_len, layout->len - position);
5293 else {
5294 *locale = NULL;
5295 *text_len = 0;
5298 return S_OK;
5301 static HRESULT WINAPI dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource1 *iface,
5302 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
5304 FIXME("%u %p %p: stub\n", position, text_len, substitution);
5305 return E_NOTIMPL;
5308 static HRESULT WINAPI dwritetextlayout_source_GetVerticalGlyphOrientation(IDWriteTextAnalysisSource1 *iface,
5309 UINT32 position, UINT32 *length, DWRITE_VERTICAL_GLYPH_ORIENTATION *orientation, UINT8 *bidi_level)
5311 FIXME("%u %p %p %p: stub\n", position, length, orientation, bidi_level);
5312 return E_NOTIMPL;
5315 static const IDWriteTextAnalysisSource1Vtbl dwritetextlayoutsourcevtbl = {
5316 dwritetextlayout_source_QueryInterface,
5317 dwritetextlayout_source_AddRef,
5318 dwritetextlayout_source_Release,
5319 dwritetextlayout_source_GetTextAtPosition,
5320 dwritetextlayout_source_GetTextBeforePosition,
5321 dwritetextlayout_source_GetParagraphReadingDirection,
5322 dwritetextlayout_source_GetLocaleName,
5323 dwritetextlayout_source_GetNumberSubstitution,
5324 dwritetextlayout_source_GetVerticalGlyphOrientation
5327 static HRESULT layout_format_from_textformat(struct dwrite_textlayout *layout, IDWriteTextFormat *format)
5329 struct dwrite_textformat *textformat;
5330 IDWriteTextFormat1 *format1;
5331 IDWriteTextFormat3 *format3;
5332 UINT32 len;
5333 HRESULT hr;
5335 if ((textformat = unsafe_impl_from_IDWriteTextFormat(format))) {
5336 layout->format = textformat->format;
5338 layout->format.locale = heap_strdupW(textformat->format.locale);
5339 layout->format.family_name = heap_strdupW(textformat->format.family_name);
5340 if (!layout->format.locale || !layout->format.family_name)
5342 heap_free(layout->format.locale);
5343 heap_free(layout->format.family_name);
5344 return E_OUTOFMEMORY;
5347 if (layout->format.trimmingsign)
5348 IDWriteInlineObject_AddRef(layout->format.trimmingsign);
5349 if (layout->format.collection)
5350 IDWriteFontCollection_AddRef(layout->format.collection);
5351 if (layout->format.fallback)
5352 IDWriteFontFallback_AddRef(layout->format.fallback);
5354 return S_OK;
5357 layout->format.weight = IDWriteTextFormat_GetFontWeight(format);
5358 layout->format.style = IDWriteTextFormat_GetFontStyle(format);
5359 layout->format.stretch = IDWriteTextFormat_GetFontStretch(format);
5360 layout->format.fontsize= IDWriteTextFormat_GetFontSize(format);
5361 layout->format.tabstop = IDWriteTextFormat_GetIncrementalTabStop(format);
5362 layout->format.textalignment = IDWriteTextFormat_GetTextAlignment(format);
5363 layout->format.paralign = IDWriteTextFormat_GetParagraphAlignment(format);
5364 layout->format.wrapping = IDWriteTextFormat_GetWordWrapping(format);
5365 layout->format.readingdir = IDWriteTextFormat_GetReadingDirection(format);
5366 layout->format.flow = IDWriteTextFormat_GetFlowDirection(format);
5367 hr = IDWriteTextFormat_GetLineSpacing(format, &layout->format.spacing.method,
5368 &layout->format.spacing.height, &layout->format.spacing.baseline);
5369 if (FAILED(hr))
5370 return hr;
5372 hr = IDWriteTextFormat_GetTrimming(format, &layout->format.trimming, &layout->format.trimmingsign);
5373 if (FAILED(hr))
5374 return hr;
5376 /* locale name and length */
5377 len = IDWriteTextFormat_GetLocaleNameLength(format);
5378 layout->format.locale = heap_alloc((len+1)*sizeof(WCHAR));
5379 if (!layout->format.locale)
5380 return E_OUTOFMEMORY;
5382 hr = IDWriteTextFormat_GetLocaleName(format, layout->format.locale, len+1);
5383 if (FAILED(hr))
5384 return hr;
5385 layout->format.locale_len = len;
5387 /* font family name and length */
5388 len = IDWriteTextFormat_GetFontFamilyNameLength(format);
5389 layout->format.family_name = heap_alloc((len+1)*sizeof(WCHAR));
5390 if (!layout->format.family_name)
5391 return E_OUTOFMEMORY;
5393 hr = IDWriteTextFormat_GetFontFamilyName(format, layout->format.family_name, len+1);
5394 if (FAILED(hr))
5395 return hr;
5396 layout->format.family_len = len;
5398 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
5399 if (hr == S_OK)
5401 IDWriteTextFormat2 *format2;
5403 layout->format.vertical_orientation = IDWriteTextFormat1_GetVerticalGlyphOrientation(format1);
5404 layout->format.optical_alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
5405 IDWriteTextFormat1_GetFontFallback(format1, &layout->format.fallback);
5407 if (IDWriteTextFormat1_QueryInterface(format1, &IID_IDWriteTextFormat2, (void**)&format2) == S_OK) {
5408 IDWriteTextFormat2_GetLineSpacing(format2, &layout->format.spacing);
5409 IDWriteTextFormat2_Release(format2);
5412 IDWriteTextFormat1_Release(format1);
5415 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat3, (void **)&format3);
5416 if (hr == S_OK)
5418 layout->format.automatic_axes = IDWriteTextFormat3_GetAutomaticFontAxes(format3);
5419 IDWriteTextFormat3_Release(format3);
5422 return IDWriteTextFormat_GetFontCollection(format, &layout->format.collection);
5425 static HRESULT init_textlayout(const struct textlayout_desc *desc, struct dwrite_textlayout *layout)
5427 struct layout_range_header *range, *strike, *underline, *effect, *spacing, *typography;
5428 static const DWRITE_TEXT_RANGE r = { 0, ~0u };
5429 HRESULT hr;
5431 layout->IDWriteTextLayout4_iface.lpVtbl = &dwritetextlayoutvtbl;
5432 layout->IDWriteTextFormat3_iface.lpVtbl = &dwritetextformat3_layout_vtbl;
5433 layout->IDWriteTextAnalysisSink1_iface.lpVtbl = &dwritetextlayoutsinkvtbl;
5434 layout->IDWriteTextAnalysisSource1_iface.lpVtbl = &dwritetextlayoutsourcevtbl;
5435 layout->refcount = 1;
5436 layout->len = desc->length;
5437 layout->recompute = RECOMPUTE_EVERYTHING;
5438 list_init(&layout->eruns);
5439 list_init(&layout->inlineobjects);
5440 list_init(&layout->underlines);
5441 list_init(&layout->strikethrough);
5442 list_init(&layout->runs);
5443 list_init(&layout->ranges);
5444 list_init(&layout->strike_ranges);
5445 list_init(&layout->underline_ranges);
5446 list_init(&layout->effects);
5447 list_init(&layout->spacing);
5448 list_init(&layout->typographies);
5449 layout->metrics.layoutWidth = desc->max_width;
5450 layout->metrics.layoutHeight = desc->max_height;
5452 layout->str = heap_strdupnW(desc->string, desc->length);
5453 if (desc->length && !layout->str) {
5454 hr = E_OUTOFMEMORY;
5455 goto fail;
5458 hr = layout_format_from_textformat(layout, desc->format);
5459 if (FAILED(hr))
5460 goto fail;
5462 range = alloc_layout_range(layout, &r, LAYOUT_RANGE_REGULAR);
5463 strike = alloc_layout_range(layout, &r, LAYOUT_RANGE_STRIKETHROUGH);
5464 underline = alloc_layout_range(layout, &r, LAYOUT_RANGE_UNDERLINE);
5465 effect = alloc_layout_range(layout, &r, LAYOUT_RANGE_EFFECT);
5466 spacing = alloc_layout_range(layout, &r, LAYOUT_RANGE_SPACING);
5467 typography = alloc_layout_range(layout, &r, LAYOUT_RANGE_TYPOGRAPHY);
5468 if (!range || !strike || !effect || !spacing || !typography || !underline) {
5469 free_layout_range(range);
5470 free_layout_range(strike);
5471 free_layout_range(underline);
5472 free_layout_range(effect);
5473 free_layout_range(spacing);
5474 free_layout_range(typography);
5475 hr = E_OUTOFMEMORY;
5476 goto fail;
5479 layout->measuringmode = desc->is_gdi_compatible ? (desc->use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL :
5480 DWRITE_MEASURING_MODE_GDI_CLASSIC) : DWRITE_MEASURING_MODE_NATURAL;
5481 layout->ppdip = desc->ppdip;
5482 layout->transform = desc->transform ? *desc->transform : identity;
5484 layout->factory = desc->factory;
5485 IDWriteFactory7_AddRef(layout->factory);
5486 list_add_head(&layout->ranges, &range->entry);
5487 list_add_head(&layout->strike_ranges, &strike->entry);
5488 list_add_head(&layout->underline_ranges, &underline->entry);
5489 list_add_head(&layout->effects, &effect->entry);
5490 list_add_head(&layout->spacing, &spacing->entry);
5491 list_add_head(&layout->typographies, &typography->entry);
5492 return S_OK;
5494 fail:
5495 IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
5496 return hr;
5499 HRESULT create_textlayout(const struct textlayout_desc *desc, IDWriteTextLayout **layout)
5501 struct dwrite_textlayout *object;
5502 HRESULT hr;
5504 *layout = NULL;
5506 if (desc->max_width < 0.0f || desc->max_height < 0.0f)
5507 return E_INVALIDARG;
5509 if (!desc->format || !desc->string)
5510 return E_INVALIDARG;
5512 if (!(object = heap_alloc_zero(sizeof(*object))))
5513 return E_OUTOFMEMORY;
5515 hr = init_textlayout(desc, object);
5516 if (hr == S_OK)
5517 *layout = (IDWriteTextLayout *)&object->IDWriteTextLayout4_iface;
5519 return hr;
5522 static HRESULT WINAPI dwritetrimmingsign_QueryInterface(IDWriteInlineObject *iface, REFIID riid, void **obj)
5524 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5526 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteInlineObject)) {
5527 *obj = iface;
5528 IDWriteInlineObject_AddRef(iface);
5529 return S_OK;
5532 WARN("%s not implemented.\n", debugstr_guid(riid));
5534 *obj = NULL;
5535 return E_NOINTERFACE;
5538 static ULONG WINAPI dwritetrimmingsign_AddRef(IDWriteInlineObject *iface)
5540 struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
5541 ULONG refcount = InterlockedIncrement(&sign->refcount);
5543 TRACE("%p, refcount %d.\n", iface, refcount);
5545 return refcount;
5548 static ULONG WINAPI dwritetrimmingsign_Release(IDWriteInlineObject *iface)
5550 struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
5551 ULONG refcount = InterlockedDecrement(&sign->refcount);
5553 TRACE("%p, refcount %d.\n", iface, refcount);
5555 if (!refcount)
5557 IDWriteTextLayout_Release(sign->layout);
5558 heap_free(sign);
5561 return refcount;
5564 static HRESULT WINAPI dwritetrimmingsign_Draw(IDWriteInlineObject *iface, void *context, IDWriteTextRenderer *renderer,
5565 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *effect)
5567 struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
5568 DWRITE_LINE_METRICS line;
5569 UINT32 line_count;
5571 TRACE("%p, %p, %p, %.2f, %.2f, %d, %d, %p.\n", iface, context, renderer, originX, originY,
5572 is_sideways, is_rtl, effect);
5574 IDWriteTextLayout_GetLineMetrics(sign->layout, &line, 1, &line_count);
5575 return IDWriteTextLayout_Draw(sign->layout, context, renderer, originX, originY - line.baseline);
5578 static HRESULT WINAPI dwritetrimmingsign_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *ret)
5580 struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
5581 DWRITE_TEXT_METRICS metrics;
5582 HRESULT hr;
5584 TRACE("%p, %p.\n", iface, ret);
5586 hr = IDWriteTextLayout_GetMetrics(sign->layout, &metrics);
5587 if (FAILED(hr))
5589 memset(ret, 0, sizeof(*ret));
5590 return hr;
5593 ret->width = metrics.width;
5594 ret->height = 0.0f;
5595 ret->baseline = 0.0f;
5596 ret->supportsSideways = FALSE;
5597 return S_OK;
5600 static HRESULT WINAPI dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
5602 struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
5604 TRACE("%p, %p.\n", iface, overhangs);
5606 return IDWriteTextLayout_GetOverhangMetrics(sign->layout, overhangs);
5609 static HRESULT WINAPI dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
5610 DWRITE_BREAK_CONDITION *after)
5612 TRACE("%p, %p, %p.\n", iface, before, after);
5614 *before = *after = DWRITE_BREAK_CONDITION_NEUTRAL;
5615 return S_OK;
5618 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl =
5620 dwritetrimmingsign_QueryInterface,
5621 dwritetrimmingsign_AddRef,
5622 dwritetrimmingsign_Release,
5623 dwritetrimmingsign_Draw,
5624 dwritetrimmingsign_GetMetrics,
5625 dwritetrimmingsign_GetOverhangMetrics,
5626 dwritetrimmingsign_GetBreakConditions
5629 static inline BOOL is_reading_direction_horz(DWRITE_READING_DIRECTION direction)
5631 return (direction == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT) ||
5632 (direction == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
5635 static inline BOOL is_reading_direction_vert(DWRITE_READING_DIRECTION direction)
5637 return (direction == DWRITE_READING_DIRECTION_TOP_TO_BOTTOM) ||
5638 (direction == DWRITE_READING_DIRECTION_BOTTOM_TO_TOP);
5641 static inline BOOL is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction)
5643 return (direction == DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT) ||
5644 (direction == DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT);
5647 static inline BOOL is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction)
5649 return (direction == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM) ||
5650 (direction == DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP);
5653 HRESULT create_trimmingsign(IDWriteFactory7 *factory, IDWriteTextFormat *format, IDWriteInlineObject **sign)
5655 static const WCHAR ellipsisW = 0x2026;
5656 struct dwrite_trimmingsign *object;
5657 DWRITE_READING_DIRECTION reading;
5658 DWRITE_FLOW_DIRECTION flow;
5659 HRESULT hr;
5661 *sign = NULL;
5663 if (!format)
5664 return E_INVALIDARG;
5666 /* Validate reading/flow direction here, layout creation won't complain about
5667 invalid combinations. */
5668 reading = IDWriteTextFormat_GetReadingDirection(format);
5669 flow = IDWriteTextFormat_GetFlowDirection(format);
5671 if ((is_reading_direction_horz(reading) && is_flow_direction_horz(flow)) ||
5672 (is_reading_direction_vert(reading) && is_flow_direction_vert(flow)))
5673 return DWRITE_E_FLOWDIRECTIONCONFLICTS;
5675 if (!(object = heap_alloc(sizeof(*object))))
5676 return E_OUTOFMEMORY;
5678 object->IDWriteInlineObject_iface.lpVtbl = &dwritetrimmingsignvtbl;
5679 object->refcount = 1;
5681 hr = IDWriteFactory7_CreateTextLayout(factory, &ellipsisW, 1, format, 0.0f, 0.0f, &object->layout);
5682 if (FAILED(hr))
5684 heap_free(object);
5685 return hr;
5688 IDWriteTextLayout_SetWordWrapping(object->layout, DWRITE_WORD_WRAPPING_NO_WRAP);
5689 IDWriteTextLayout_SetParagraphAlignment(object->layout, DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
5690 IDWriteTextLayout_SetTextAlignment(object->layout, DWRITE_TEXT_ALIGNMENT_LEADING);
5692 *sign = &object->IDWriteInlineObject_iface;
5694 return S_OK;
5697 static HRESULT WINAPI dwritetextformat_QueryInterface(IDWriteTextFormat3 *iface, REFIID riid, void **obj)
5699 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5701 if (IsEqualIID(riid, &IID_IDWriteTextFormat3) ||
5702 IsEqualIID(riid, &IID_IDWriteTextFormat2) ||
5703 IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
5704 IsEqualIID(riid, &IID_IDWriteTextFormat) ||
5705 IsEqualIID(riid, &IID_IUnknown))
5707 *obj = iface;
5708 IDWriteTextFormat3_AddRef(iface);
5709 return S_OK;
5712 WARN("%s not implemented.\n", debugstr_guid(riid));
5714 *obj = NULL;
5716 return E_NOINTERFACE;
5719 static ULONG WINAPI dwritetextformat_AddRef(IDWriteTextFormat3 *iface)
5721 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5722 ULONG refcount = InterlockedIncrement(&format->refcount);
5724 TRACE("%p, refcount %d.\n", iface, refcount);
5726 return refcount;
5729 static ULONG WINAPI dwritetextformat_Release(IDWriteTextFormat3 *iface)
5731 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5732 ULONG refcount = InterlockedDecrement(&format->refcount);
5734 TRACE("%p, refcount %d.\n", iface, refcount);
5736 if (!refcount)
5738 release_format_data(&format->format);
5739 heap_free(format);
5742 return refcount;
5745 static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat3 *iface, DWRITE_TEXT_ALIGNMENT alignment)
5747 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5749 TRACE("%p, %d.\n", iface, alignment);
5751 return format_set_textalignment(&format->format, alignment, NULL);
5754 static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat3 *iface,
5755 DWRITE_PARAGRAPH_ALIGNMENT alignment)
5757 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5759 TRACE("%p, %d.\n", iface, alignment);
5761 return format_set_paralignment(&format->format, alignment, NULL);
5764 static HRESULT WINAPI dwritetextformat_SetWordWrapping(IDWriteTextFormat3 *iface, DWRITE_WORD_WRAPPING wrapping)
5766 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5768 TRACE("%p, %d.\n", iface, wrapping);
5770 return format_set_wordwrapping(&format->format, wrapping, NULL);
5773 static HRESULT WINAPI dwritetextformat_SetReadingDirection(IDWriteTextFormat3 *iface, DWRITE_READING_DIRECTION direction)
5775 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5777 TRACE("%p, %d.\n", iface, direction);
5779 return format_set_readingdirection(&format->format, direction, NULL);
5782 static HRESULT WINAPI dwritetextformat_SetFlowDirection(IDWriteTextFormat3 *iface, DWRITE_FLOW_DIRECTION direction)
5784 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5786 TRACE("%p, %d.\n", iface, direction);
5788 return format_set_flowdirection(&format->format, direction, NULL);
5791 static HRESULT WINAPI dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat3 *iface, FLOAT tabstop)
5793 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5795 TRACE("%p, %f.\n", iface, tabstop);
5797 if (tabstop <= 0.0f)
5798 return E_INVALIDARG;
5800 format->format.tabstop = tabstop;
5801 return S_OK;
5804 static HRESULT WINAPI dwritetextformat_SetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING const *trimming,
5805 IDWriteInlineObject *trimming_sign)
5807 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5809 TRACE("%p, %p, %p.\n", iface, trimming, trimming_sign);
5811 return format_set_trimming(&format->format, trimming, trimming_sign, NULL);
5814 static HRESULT WINAPI dwritetextformat_SetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING_METHOD method,
5815 FLOAT height, FLOAT baseline)
5817 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5818 DWRITE_LINE_SPACING spacing;
5820 TRACE("%p, %d, %f, %f.\n", iface, method, height, baseline);
5822 spacing = format->format.spacing;
5823 spacing.method = method;
5824 spacing.height = height;
5825 spacing.baseline = baseline;
5827 return format_set_linespacing(&format->format, &spacing, NULL);
5830 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_GetTextAlignment(IDWriteTextFormat3 *iface)
5832 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5834 TRACE("%p.\n", iface);
5836 return format->format.textalignment;
5839 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_GetParagraphAlignment(IDWriteTextFormat3 *iface)
5841 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5843 TRACE("%p.\n", iface);
5845 return format->format.paralign;
5848 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_GetWordWrapping(IDWriteTextFormat3 *iface)
5850 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5852 TRACE("%p.\n", iface);
5854 return format->format.wrapping;
5857 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_GetReadingDirection(IDWriteTextFormat3 *iface)
5859 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5861 TRACE("%p.\n", iface);
5863 return format->format.readingdir;
5866 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_GetFlowDirection(IDWriteTextFormat3 *iface)
5868 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5870 TRACE("%p.\n", iface);
5872 return format->format.flow;
5875 static FLOAT WINAPI dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat3 *iface)
5877 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5879 TRACE("%p.\n", iface);
5881 return format->format.tabstop;
5884 static HRESULT WINAPI dwritetextformat_GetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING *options,
5885 IDWriteInlineObject **trimming_sign)
5887 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5889 TRACE("%p, %p, %p.\n", iface, options, trimming_sign);
5891 *options = format->format.trimming;
5892 if ((*trimming_sign = format->format.trimmingsign))
5893 IDWriteInlineObject_AddRef(*trimming_sign);
5895 return S_OK;
5898 static HRESULT WINAPI dwritetextformat_GetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING_METHOD *method,
5899 FLOAT *spacing, FLOAT *baseline)
5901 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5903 TRACE("%p, %p, %p, %p.\n", iface, method, spacing, baseline);
5905 *method = format->format.spacing.method;
5906 *spacing = format->format.spacing.height;
5907 *baseline = format->format.spacing.baseline;
5908 return S_OK;
5911 static HRESULT WINAPI dwritetextformat_GetFontCollection(IDWriteTextFormat3 *iface, IDWriteFontCollection **collection)
5913 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5915 TRACE("%p, %p.\n", iface, collection);
5917 *collection = format->format.collection;
5918 IDWriteFontCollection_AddRef(*collection);
5920 return S_OK;
5923 static UINT32 WINAPI dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat3 *iface)
5925 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5927 TRACE("%p.\n", iface);
5929 return format->format.family_len;
5932 static HRESULT WINAPI dwritetextformat_GetFontFamilyName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
5934 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5936 TRACE("%p, %p, %u.\n", iface, name, size);
5938 if (size <= format->format.family_len)
5939 return E_NOT_SUFFICIENT_BUFFER;
5940 wcscpy(name, format->format.family_name);
5941 return S_OK;
5944 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_GetFontWeight(IDWriteTextFormat3 *iface)
5946 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5948 TRACE("%p.\n", iface);
5950 return format->format.weight;
5953 static DWRITE_FONT_STYLE WINAPI dwritetextformat_GetFontStyle(IDWriteTextFormat3 *iface)
5955 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5957 TRACE("%p.\n", iface);
5959 return format->format.style;
5962 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_GetFontStretch(IDWriteTextFormat3 *iface)
5964 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5966 TRACE("%p.\n", iface);
5968 return format->format.stretch;
5971 static FLOAT WINAPI dwritetextformat_GetFontSize(IDWriteTextFormat3 *iface)
5973 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5975 TRACE("%p.\n", iface);
5977 return format->format.fontsize;
5980 static UINT32 WINAPI dwritetextformat_GetLocaleNameLength(IDWriteTextFormat3 *iface)
5982 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5984 TRACE("%p.\n", iface);
5986 return format->format.locale_len;
5989 static HRESULT WINAPI dwritetextformat_GetLocaleName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
5991 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5993 TRACE("%p, %p %u.\n", iface, name, size);
5995 if (size <= format->format.locale_len)
5996 return E_NOT_SUFFICIENT_BUFFER;
5997 wcscpy(name, format->format.locale);
5998 return S_OK;
6001 static HRESULT WINAPI dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat3 *iface,
6002 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
6004 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6006 TRACE("%p, %d.\n", iface, orientation);
6008 return format_set_vertical_orientation(&format->format, orientation, NULL);
6011 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat3 *iface)
6013 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6015 TRACE("%p.\n", iface);
6017 return format->format.vertical_orientation;
6020 static HRESULT WINAPI dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat3 *iface, BOOL lastline_wrapping_enabled)
6022 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6024 TRACE("%p, %d.\n", iface, lastline_wrapping_enabled);
6026 format->format.last_line_wrapping = !!lastline_wrapping_enabled;
6027 return S_OK;
6030 static BOOL WINAPI dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat3 *iface)
6032 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6034 TRACE("%p.\n", iface);
6036 return format->format.last_line_wrapping;
6039 static HRESULT WINAPI dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat3 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
6041 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6043 TRACE("%p, %d.\n", iface, alignment);
6045 return format_set_optical_alignment(&format->format, alignment);
6048 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat3 *iface)
6050 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6052 TRACE("%p.\n", iface);
6054 return format->format.optical_alignment;
6057 static HRESULT WINAPI dwritetextformat1_SetFontFallback(IDWriteTextFormat3 *iface, IDWriteFontFallback *fallback)
6059 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6061 TRACE("%p, %p.\n", iface, fallback);
6063 return set_fontfallback_for_format(&format->format, fallback);
6066 static HRESULT WINAPI dwritetextformat1_GetFontFallback(IDWriteTextFormat3 *iface, IDWriteFontFallback **fallback)
6068 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6070 TRACE("%p, %p.\n", iface, fallback);
6072 return get_fontfallback_from_format(&format->format, fallback);
6075 static HRESULT WINAPI dwritetextformat2_SetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING const *spacing)
6077 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6079 TRACE("%p, %p.\n", iface, spacing);
6081 return format_set_linespacing(&format->format, spacing, NULL);
6084 static HRESULT WINAPI dwritetextformat2_GetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING *spacing)
6086 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6088 TRACE("%p, %p.\n", iface, spacing);
6090 *spacing = format->format.spacing;
6091 return S_OK;
6094 static HRESULT WINAPI dwritetextformat3_SetFontAxisValues(IDWriteTextFormat3 *iface,
6095 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values)
6097 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6099 TRACE("%p, %p, %u.\n", iface, axis_values, num_values);
6101 return format_set_font_axisvalues(&format->format, axis_values, num_values);
6104 static UINT32 WINAPI dwritetextformat3_GetFontAxisValueCount(IDWriteTextFormat3 *iface)
6106 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6108 TRACE("%p.\n", iface);
6110 return format->format.axis_values_count;
6113 static HRESULT WINAPI dwritetextformat3_GetFontAxisValues(IDWriteTextFormat3 *iface,
6114 DWRITE_FONT_AXIS_VALUE *axis_values, UINT32 num_values)
6116 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6118 TRACE("%p, %p, %u.\n", iface, axis_values, num_values);
6120 return format_get_font_axisvalues(&format->format, axis_values, num_values);
6123 static DWRITE_AUTOMATIC_FONT_AXES WINAPI dwritetextformat3_GetAutomaticFontAxes(IDWriteTextFormat3 *iface)
6125 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6127 TRACE("%p.\n", iface);
6129 return format->format.automatic_axes;
6132 static HRESULT WINAPI dwritetextformat3_SetAutomaticFontAxes(IDWriteTextFormat3 *iface, DWRITE_AUTOMATIC_FONT_AXES axes)
6134 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6136 TRACE("%p, %d.\n", iface, axes);
6138 format->format.automatic_axes = axes;
6140 return S_OK;
6143 static const IDWriteTextFormat3Vtbl dwritetextformatvtbl =
6145 dwritetextformat_QueryInterface,
6146 dwritetextformat_AddRef,
6147 dwritetextformat_Release,
6148 dwritetextformat_SetTextAlignment,
6149 dwritetextformat_SetParagraphAlignment,
6150 dwritetextformat_SetWordWrapping,
6151 dwritetextformat_SetReadingDirection,
6152 dwritetextformat_SetFlowDirection,
6153 dwritetextformat_SetIncrementalTabStop,
6154 dwritetextformat_SetTrimming,
6155 dwritetextformat_SetLineSpacing,
6156 dwritetextformat_GetTextAlignment,
6157 dwritetextformat_GetParagraphAlignment,
6158 dwritetextformat_GetWordWrapping,
6159 dwritetextformat_GetReadingDirection,
6160 dwritetextformat_GetFlowDirection,
6161 dwritetextformat_GetIncrementalTabStop,
6162 dwritetextformat_GetTrimming,
6163 dwritetextformat_GetLineSpacing,
6164 dwritetextformat_GetFontCollection,
6165 dwritetextformat_GetFontFamilyNameLength,
6166 dwritetextformat_GetFontFamilyName,
6167 dwritetextformat_GetFontWeight,
6168 dwritetextformat_GetFontStyle,
6169 dwritetextformat_GetFontStretch,
6170 dwritetextformat_GetFontSize,
6171 dwritetextformat_GetLocaleNameLength,
6172 dwritetextformat_GetLocaleName,
6173 dwritetextformat1_SetVerticalGlyphOrientation,
6174 dwritetextformat1_GetVerticalGlyphOrientation,
6175 dwritetextformat1_SetLastLineWrapping,
6176 dwritetextformat1_GetLastLineWrapping,
6177 dwritetextformat1_SetOpticalAlignment,
6178 dwritetextformat1_GetOpticalAlignment,
6179 dwritetextformat1_SetFontFallback,
6180 dwritetextformat1_GetFontFallback,
6181 dwritetextformat2_SetLineSpacing,
6182 dwritetextformat2_GetLineSpacing,
6183 dwritetextformat3_SetFontAxisValues,
6184 dwritetextformat3_GetFontAxisValueCount,
6185 dwritetextformat3_GetFontAxisValues,
6186 dwritetextformat3_GetAutomaticFontAxes,
6187 dwritetextformat3_SetAutomaticFontAxes,
6190 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat *iface)
6192 return (iface->lpVtbl == (IDWriteTextFormatVtbl*)&dwritetextformatvtbl) ?
6193 CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat3_iface) : NULL;
6196 HRESULT create_textformat(const WCHAR *family_name, IDWriteFontCollection *collection, DWRITE_FONT_WEIGHT weight,
6197 DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, FLOAT size, const WCHAR *locale, IDWriteTextFormat **format)
6199 struct dwrite_textformat *object;
6201 *format = NULL;
6203 if (size <= 0.0f)
6204 return E_INVALIDARG;
6206 if (((UINT32)weight > DWRITE_FONT_WEIGHT_ULTRA_BLACK) ||
6207 ((UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED) ||
6208 ((UINT32)style > DWRITE_FONT_STYLE_ITALIC))
6209 return E_INVALIDARG;
6211 if (!(object = heap_alloc_zero(sizeof(*object))))
6212 return E_OUTOFMEMORY;
6214 object->IDWriteTextFormat3_iface.lpVtbl = &dwritetextformatvtbl;
6215 object->refcount = 1;
6216 object->format.family_name = heap_strdupW(family_name);
6217 object->format.family_len = wcslen(family_name);
6218 object->format.locale = heap_strdupW(locale);
6219 object->format.locale_len = wcslen(locale);
6220 /* Force locale name to lower case, layout will inherit this modified value. */
6221 wcslwr(object->format.locale);
6222 object->format.weight = weight;
6223 object->format.style = style;
6224 object->format.fontsize = size;
6225 object->format.tabstop = 4.0f * size;
6226 object->format.stretch = stretch;
6227 object->format.last_line_wrapping = TRUE;
6228 object->format.collection = collection;
6229 IDWriteFontCollection_AddRef(object->format.collection);
6231 *format = (IDWriteTextFormat *)&object->IDWriteTextFormat3_iface;
6233 return S_OK;
6236 static HRESULT WINAPI dwritetypography_QueryInterface(IDWriteTypography *iface, REFIID riid, void **obj)
6238 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6240 if (IsEqualIID(riid, &IID_IDWriteTypography) || IsEqualIID(riid, &IID_IUnknown)) {
6241 *obj = iface;
6242 IDWriteTypography_AddRef(iface);
6243 return S_OK;
6246 WARN("%s not implemented.\n", debugstr_guid(riid));
6248 *obj = NULL;
6250 return E_NOINTERFACE;
6253 static ULONG WINAPI dwritetypography_AddRef(IDWriteTypography *iface)
6255 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
6256 ULONG refcount = InterlockedIncrement(&typography->refcount);
6258 TRACE("%p, refcount %d.\n", iface, refcount);
6260 return refcount;
6263 static ULONG WINAPI dwritetypography_Release(IDWriteTypography *iface)
6265 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
6266 ULONG refcount = InterlockedDecrement(&typography->refcount);
6268 TRACE("%p, refcount %d.\n", iface, refcount);
6270 if (!refcount)
6272 heap_free(typography->features);
6273 heap_free(typography);
6276 return refcount;
6279 static HRESULT WINAPI dwritetypography_AddFontFeature(IDWriteTypography *iface, DWRITE_FONT_FEATURE feature)
6281 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
6283 TRACE("%p, %s, %u.\n", iface, debugstr_tag(feature.nameTag), feature.parameter);
6285 if (!dwrite_array_reserve((void **)&typography->features, &typography->capacity, typography->count + 1,
6286 sizeof(*typography->features)))
6288 return E_OUTOFMEMORY;
6291 typography->features[typography->count++] = feature;
6293 return S_OK;
6296 static UINT32 WINAPI dwritetypography_GetFontFeatureCount(IDWriteTypography *iface)
6298 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
6300 TRACE("%p.\n", iface);
6302 return typography->count;
6305 static HRESULT WINAPI dwritetypography_GetFontFeature(IDWriteTypography *iface, UINT32 index,
6306 DWRITE_FONT_FEATURE *feature)
6308 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
6310 TRACE("%p, %u, %p.\n", iface, index, feature);
6312 if (index >= typography->count)
6313 return E_INVALIDARG;
6315 *feature = typography->features[index];
6316 return S_OK;
6319 static const IDWriteTypographyVtbl dwritetypographyvtbl = {
6320 dwritetypography_QueryInterface,
6321 dwritetypography_AddRef,
6322 dwritetypography_Release,
6323 dwritetypography_AddFontFeature,
6324 dwritetypography_GetFontFeatureCount,
6325 dwritetypography_GetFontFeature
6328 HRESULT create_typography(IDWriteTypography **ret)
6330 struct dwrite_typography *typography;
6332 *ret = NULL;
6334 typography = heap_alloc_zero(sizeof(*typography));
6335 if (!typography)
6336 return E_OUTOFMEMORY;
6338 typography->IDWriteTypography_iface.lpVtbl = &dwritetypographyvtbl;
6339 typography->refcount = 1;
6341 *ret = &typography->IDWriteTypography_iface;
6343 return S_OK;