wined3d: Pass a wined3d_device_context to wined3d_cs_emit_blt_sub_resource().
[wine/zf.git] / dlls / dwrite / layout.c
blob48741bf08473417d0687660b9813126267e372cc
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 static inline BOOL layout_is_erun_rtl(const struct layout_effective_run *erun)
1476 return erun->run->u.regular.run.bidiLevel & 1;
1479 /* A set of parameters that additionally splits resulting runs. It happens after shaping and all text processing,
1480 no glyph changes are possible. It's understandable for drawing effects, because DrawGlyphRun() reports them as
1481 one of the arguments, but it also happens for decorations, so every effective run has uniform
1482 underline/strikethough/effect tuple. */
1483 struct layout_final_splitting_params {
1484 BOOL strikethrough;
1485 BOOL underline;
1486 IUnknown *effect;
1489 static inline BOOL layout_get_strikethrough_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1491 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->strike_ranges, pos);
1492 return ((struct layout_range_bool*)h)->value;
1495 static inline BOOL layout_get_underline_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1497 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->underline_ranges, pos);
1498 return ((struct layout_range_bool*)h)->value;
1501 static void layout_splitting_params_from_pos(struct dwrite_textlayout *layout, UINT32 pos,
1502 struct layout_final_splitting_params *params)
1504 params->strikethrough = layout_get_strikethrough_from_pos(layout, pos);
1505 params->underline = layout_get_underline_from_pos(layout, pos);
1506 params->effect = layout_get_effect_from_pos(layout, pos);
1509 static BOOL is_same_splitting_params(const struct layout_final_splitting_params *left,
1510 const struct layout_final_splitting_params *right)
1512 return left->strikethrough == right->strikethrough &&
1513 left->underline == right->underline &&
1514 left->effect == right->effect;
1517 static void layout_get_erun_font_metrics(struct dwrite_textlayout *layout, struct layout_effective_run *erun,
1518 DWRITE_FONT_METRICS *metrics)
1520 memset(metrics, 0, sizeof(*metrics));
1521 if (is_layout_gdi_compatible(layout)) {
1522 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(
1523 erun->run->u.regular.run.fontFace,
1524 erun->run->u.regular.run.fontEmSize,
1525 layout->ppdip,
1526 &layout->transform,
1527 metrics);
1528 if (FAILED(hr))
1529 WARN("failed to get font metrics, 0x%08x\n", hr);
1531 else
1532 IDWriteFontFace_GetMetrics(erun->run->u.regular.run.fontFace, metrics);
1535 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
1536 'cluster_count' indicates how many clusters to add, including first one. */
1537 static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 first_cluster,
1538 UINT32 cluster_count, UINT32 line, FLOAT origin_x, struct layout_final_splitting_params *params)
1540 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1541 UINT32 i, start, length, last_cluster;
1542 struct layout_effective_run *run;
1544 if (r->kind == LAYOUT_RUN_INLINE) {
1545 struct layout_effective_inline *inlineobject;
1547 inlineobject = heap_alloc(sizeof(*inlineobject));
1548 if (!inlineobject)
1549 return E_OUTOFMEMORY;
1551 inlineobject->object = r->u.object.object;
1552 inlineobject->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1553 inlineobject->origin.x = is_rtl ? origin_x - inlineobject->width : origin_x;
1554 inlineobject->origin.y = 0.0f; /* set after line is built */
1555 inlineobject->align_dx = 0.0f;
1556 inlineobject->baseline = r->baseline;
1558 /* It's not clear how these two are set, possibly directionality
1559 is derived from surrounding text (replaced text could have
1560 different ranges which differ in reading direction). */
1561 inlineobject->is_sideways = FALSE;
1562 inlineobject->is_rtl = FALSE;
1563 inlineobject->line = line;
1565 /* effect assigned from start position and on is used for inline objects */
1566 inlineobject->effect = layout_get_effect_from_pos(layout, layout->clusters[first_cluster].position +
1567 layout->clusters[first_cluster].run->start_position);
1569 list_add_tail(&layout->inlineobjects, &inlineobject->entry);
1570 return S_OK;
1573 run = heap_alloc(sizeof(*run));
1574 if (!run)
1575 return E_OUTOFMEMORY;
1577 /* No need to iterate for that, use simple fact that:
1578 <last cluster position> = <first cluster position> + <sum of cluster lengths not including last one> */
1579 last_cluster = first_cluster + cluster_count - 1;
1580 length = layout->clusters[last_cluster].position - layout->clusters[first_cluster].position +
1581 layout->clustermetrics[last_cluster].length;
1583 run->clustermap = heap_calloc(length, sizeof(*run->clustermap));
1584 if (!run->clustermap) {
1585 heap_free(run);
1586 return E_OUTOFMEMORY;
1589 run->run = r;
1590 run->start = start = layout->clusters[first_cluster].position;
1591 run->length = length;
1592 run->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1593 memset(&run->bbox, 0, sizeof(run->bbox));
1595 /* Check if run direction matches paragraph direction, if it doesn't adjust by
1596 run width */
1597 if (layout_is_erun_rtl(run) ^ is_rtl)
1598 run->origin.x = is_rtl ? origin_x - run->width : origin_x + run->width;
1599 else
1600 run->origin.x = origin_x;
1602 run->origin.y = 0.0f; /* set after line is built */
1603 run->align_dx = 0.0f;
1604 run->line = line;
1606 if (r->u.regular.run.glyphCount) {
1607 /* Trim leading and trailing clusters. */
1608 run->glyphcount = r->u.regular.run.glyphCount - r->u.regular.clustermap[start];
1609 if (start + length < r->u.regular.descr.stringLength)
1610 run->glyphcount -= r->u.regular.run.glyphCount - r->u.regular.clustermap[start + length];
1612 else
1613 run->glyphcount = 0;
1615 /* cluster map needs to be shifted */
1616 for (i = 0; i < length; i++)
1617 run->clustermap[i] = r->u.regular.clustermap[start + i] - r->u.regular.clustermap[start];
1619 run->effect = params->effect;
1620 run->underlined = params->underline;
1621 list_add_tail(&layout->eruns, &run->entry);
1623 /* Strikethrough style is guaranteed to be consistent within effective run,
1624 its width equals to run width, thickness and offset are derived from
1625 font metrics, rest of the values are from layout or run itself */
1626 if (params->strikethrough) {
1627 struct layout_strikethrough *s;
1628 DWRITE_FONT_METRICS metrics;
1630 s = heap_alloc(sizeof(*s));
1631 if (!s)
1632 return E_OUTOFMEMORY;
1634 layout_get_erun_font_metrics(layout, run, &metrics);
1635 s->s.width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1636 s->s.thickness = SCALE_FONT_METRIC(metrics.strikethroughThickness, r->u.regular.run.fontEmSize, &metrics);
1637 /* Negative offset moves it above baseline as Y coordinate grows downward. */
1638 s->s.offset = -SCALE_FONT_METRIC(metrics.strikethroughPosition, r->u.regular.run.fontEmSize, &metrics);
1639 s->s.readingDirection = layout->format.readingdir;
1640 s->s.flowDirection = layout->format.flow;
1641 s->s.localeName = r->u.regular.descr.localeName;
1642 s->s.measuringMode = layout->measuringmode;
1643 s->run = run;
1645 list_add_tail(&layout->strikethrough, &s->entry);
1648 return S_OK;
1651 static void layout_apply_line_spacing(struct dwrite_textlayout *layout, UINT32 line)
1653 switch (layout->format.spacing.method)
1655 case DWRITE_LINE_SPACING_METHOD_DEFAULT:
1656 layout->lines[line].metrics.height = layout->lines[line].height;
1657 layout->lines[line].metrics.baseline = layout->lines[line].baseline;
1658 break;
1659 case DWRITE_LINE_SPACING_METHOD_UNIFORM:
1660 layout->lines[line].metrics.height = layout->format.spacing.height;
1661 layout->lines[line].metrics.baseline = layout->format.spacing.baseline;
1662 break;
1663 case DWRITE_LINE_SPACING_METHOD_PROPORTIONAL:
1664 layout->lines[line].metrics.height = layout->lines[line].height * layout->format.spacing.height;
1665 layout->lines[line].metrics.baseline = layout->lines[line].baseline * layout->format.spacing.baseline;
1666 break;
1667 default:
1668 ERR("Unknown spacing method %u\n", layout->format.spacing.method);
1672 static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_LINE_METRICS1 *metrics)
1674 size_t i = layout->metrics.lineCount;
1676 if (!dwrite_array_reserve((void **)&layout->lines, &layout->lines_size, layout->metrics.lineCount + 1,
1677 sizeof(*layout->lines)))
1679 return E_OUTOFMEMORY;
1682 layout->lines[i].metrics = *metrics;
1683 layout->lines[i].height = metrics->height;
1684 layout->lines[i].baseline = metrics->baseline;
1686 if (layout->format.spacing.method != DWRITE_LINE_SPACING_METHOD_DEFAULT)
1687 layout_apply_line_spacing(layout, i);
1689 layout->metrics.lineCount++;
1690 return S_OK;
1693 static inline struct layout_effective_run *layout_get_next_erun(struct dwrite_textlayout *layout,
1694 const struct layout_effective_run *cur)
1696 struct list *e;
1698 if (!cur)
1699 e = list_head(&layout->eruns);
1700 else
1701 e = list_next(&layout->eruns, &cur->entry);
1702 if (!e)
1703 return NULL;
1704 return LIST_ENTRY(e, struct layout_effective_run, entry);
1707 static inline struct layout_effective_run *layout_get_prev_erun(struct dwrite_textlayout *layout,
1708 const struct layout_effective_run *cur)
1710 struct list *e;
1712 if (!cur)
1713 e = list_tail(&layout->eruns);
1714 else
1715 e = list_prev(&layout->eruns, &cur->entry);
1716 if (!e)
1717 return NULL;
1718 return LIST_ENTRY(e, struct layout_effective_run, entry);
1721 static inline struct layout_effective_inline *layout_get_next_inline_run(struct dwrite_textlayout *layout,
1722 const struct layout_effective_inline *cur)
1724 struct list *e;
1726 if (!cur)
1727 e = list_head(&layout->inlineobjects);
1728 else
1729 e = list_next(&layout->inlineobjects, &cur->entry);
1730 if (!e)
1731 return NULL;
1732 return LIST_ENTRY(e, struct layout_effective_inline, entry);
1735 static FLOAT layout_get_line_width(struct dwrite_textlayout *layout,
1736 struct layout_effective_run *erun, struct layout_effective_inline *inrun, UINT32 line)
1738 FLOAT width = 0.0f;
1740 while (erun && erun->line == line) {
1741 width += erun->width;
1742 erun = layout_get_next_erun(layout, erun);
1743 if (!erun)
1744 break;
1747 while (inrun && inrun->line == line) {
1748 width += inrun->width;
1749 inrun = layout_get_next_inline_run(layout, inrun);
1750 if (!inrun)
1751 break;
1754 return width;
1757 static inline BOOL should_skip_transform(const DWRITE_MATRIX *m, FLOAT *det)
1759 *det = m->m11 * m->m22 - m->m12 * m->m21;
1760 /* on certain conditions we can skip transform */
1761 return (!memcmp(m, &identity, sizeof(*m)) || fabsf(*det) <= 1e-10f);
1764 static inline void layout_apply_snapping(D2D1_POINT_2F *vec, BOOL skiptransform, FLOAT ppdip,
1765 const DWRITE_MATRIX *m, FLOAT det)
1767 if (!skiptransform) {
1768 D2D1_POINT_2F vec2;
1770 /* apply transform */
1771 vec->x *= ppdip;
1772 vec->y *= ppdip;
1774 vec2.x = m->m11 * vec->x + m->m21 * vec->y + m->dx;
1775 vec2.y = m->m12 * vec->x + m->m22 * vec->y + m->dy;
1777 /* snap */
1778 vec2.x = floorf(vec2.x + 0.5f);
1779 vec2.y = floorf(vec2.y + 0.5f);
1781 /* apply inverted transform, we don't care about X component at this point */
1782 vec->x = (m->m22 * vec2.x - m->m21 * vec2.y + m->m21 * m->dy - m->m22 * m->dx) / det;
1783 vec->x /= ppdip;
1785 vec->y = (-m->m12 * vec2.x + m->m11 * vec2.y - (m->m11 * m->dy - m->m12 * m->dx)) / det;
1786 vec->y /= ppdip;
1788 else {
1789 vec->x = floorf(vec->x * ppdip + 0.5f) / ppdip;
1790 vec->y = floorf(vec->y * ppdip + 0.5f) / ppdip;
1794 static void layout_apply_leading_alignment(struct dwrite_textlayout *layout)
1796 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1797 struct layout_effective_inline *inrun;
1798 struct layout_effective_run *erun;
1800 erun = layout_get_next_erun(layout, NULL);
1801 inrun = layout_get_next_inline_run(layout, NULL);
1803 while (erun) {
1804 erun->align_dx = 0.0f;
1805 erun = layout_get_next_erun(layout, erun);
1808 while (inrun) {
1809 inrun->align_dx = 0.0f;
1810 inrun = layout_get_next_inline_run(layout, inrun);
1813 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
1816 static void layout_apply_trailing_alignment(struct dwrite_textlayout *layout)
1818 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1819 struct layout_effective_inline *inrun;
1820 struct layout_effective_run *erun;
1821 UINT32 line;
1823 erun = layout_get_next_erun(layout, NULL);
1824 inrun = layout_get_next_inline_run(layout, NULL);
1826 for (line = 0; line < layout->metrics.lineCount; line++) {
1827 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1828 FLOAT shift = layout->metrics.layoutWidth - width;
1830 if (is_rtl)
1831 shift *= -1.0f;
1833 while (erun && erun->line == line) {
1834 erun->align_dx = shift;
1835 erun = layout_get_next_erun(layout, erun);
1838 while (inrun && inrun->line == line) {
1839 inrun->align_dx = shift;
1840 inrun = layout_get_next_inline_run(layout, inrun);
1844 layout->metrics.left = is_rtl ? 0.0f : layout->metrics.layoutWidth - layout->metrics.width;
1847 static inline FLOAT layout_get_centered_shift(struct dwrite_textlayout *layout, BOOL skiptransform,
1848 FLOAT width, FLOAT det)
1850 if (is_layout_gdi_compatible(layout)) {
1851 D2D1_POINT_2F vec = { layout->metrics.layoutWidth - width, 0.0f};
1852 layout_apply_snapping(&vec, skiptransform, layout->ppdip, &layout->transform, det);
1853 return floorf(vec.x / 2.0f);
1855 else
1856 return (layout->metrics.layoutWidth - width) / 2.0f;
1859 static void layout_apply_centered_alignment(struct dwrite_textlayout *layout)
1861 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1862 struct layout_effective_inline *inrun;
1863 struct layout_effective_run *erun;
1864 BOOL skiptransform;
1865 UINT32 line;
1866 FLOAT det;
1868 erun = layout_get_next_erun(layout, NULL);
1869 inrun = layout_get_next_inline_run(layout, NULL);
1871 skiptransform = should_skip_transform(&layout->transform, &det);
1873 for (line = 0; line < layout->metrics.lineCount; line++) {
1874 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1875 FLOAT shift = layout_get_centered_shift(layout, skiptransform, width, det);
1877 if (is_rtl)
1878 shift *= -1.0f;
1880 while (erun && erun->line == line) {
1881 erun->align_dx = shift;
1882 erun = layout_get_next_erun(layout, erun);
1885 while (inrun && inrun->line == line) {
1886 inrun->align_dx = shift;
1887 inrun = layout_get_next_inline_run(layout, inrun);
1891 layout->metrics.left = (layout->metrics.layoutWidth - layout->metrics.width) / 2.0f;
1894 static void layout_apply_text_alignment(struct dwrite_textlayout *layout)
1896 switch (layout->format.textalignment)
1898 case DWRITE_TEXT_ALIGNMENT_LEADING:
1899 layout_apply_leading_alignment(layout);
1900 break;
1901 case DWRITE_TEXT_ALIGNMENT_TRAILING:
1902 layout_apply_trailing_alignment(layout);
1903 break;
1904 case DWRITE_TEXT_ALIGNMENT_CENTER:
1905 layout_apply_centered_alignment(layout);
1906 break;
1907 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED:
1908 FIXME("alignment %d not implemented\n", layout->format.textalignment);
1909 break;
1910 default:
1915 static void layout_apply_par_alignment(struct dwrite_textlayout *layout)
1917 struct layout_effective_inline *inrun;
1918 struct layout_effective_run *erun;
1919 FLOAT origin_y = 0.0f;
1920 UINT32 line;
1922 /* alignment mode defines origin, after that all run origins are updated
1923 the same way */
1925 switch (layout->format.paralign)
1927 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR:
1928 origin_y = 0.0f;
1929 break;
1930 case DWRITE_PARAGRAPH_ALIGNMENT_FAR:
1931 origin_y = layout->metrics.layoutHeight - layout->metrics.height;
1932 break;
1933 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER:
1934 origin_y = (layout->metrics.layoutHeight - layout->metrics.height) / 2.0f;
1935 break;
1936 default:
1940 layout->metrics.top = origin_y;
1942 erun = layout_get_next_erun(layout, NULL);
1943 inrun = layout_get_next_inline_run(layout, NULL);
1944 for (line = 0; line < layout->metrics.lineCount; line++)
1946 float pos_y = origin_y + layout->lines[line].metrics.baseline;
1948 while (erun && erun->line == line) {
1949 erun->origin.y = pos_y;
1950 erun = layout_get_next_erun(layout, erun);
1953 while (inrun && inrun->line == line) {
1954 inrun->origin.y = pos_y - inrun->baseline;
1955 inrun = layout_get_next_inline_run(layout, inrun);
1958 origin_y += layout->lines[line].metrics.height;
1962 struct layout_underline_splitting_params {
1963 const WCHAR *locale; /* points to range data, no additional allocation */
1964 IUnknown *effect; /* does not hold another reference */
1967 static void init_u_splitting_params_from_erun(struct layout_effective_run *erun,
1968 struct layout_underline_splitting_params *params)
1970 params->locale = erun->run->u.regular.descr.localeName;
1971 params->effect = erun->effect;
1974 static BOOL is_same_u_splitting(struct layout_underline_splitting_params *left,
1975 struct layout_underline_splitting_params *right)
1977 return left->effect == right->effect && !wcsicmp(left->locale, right->locale);
1980 static HRESULT layout_add_underline(struct dwrite_textlayout *layout, struct layout_effective_run *first,
1981 struct layout_effective_run *last)
1983 FLOAT thickness, offset, runheight;
1984 struct layout_effective_run *cur;
1985 DWRITE_FONT_METRICS metrics;
1987 if (first == layout_get_prev_erun(layout, last)) {
1988 layout_get_erun_font_metrics(layout, first, &metrics);
1989 thickness = SCALE_FONT_METRIC(metrics.underlineThickness, first->run->u.regular.run.fontEmSize, &metrics);
1990 offset = SCALE_FONT_METRIC(metrics.underlinePosition, first->run->u.regular.run.fontEmSize, &metrics);
1991 runheight = SCALE_FONT_METRIC(metrics.capHeight, first->run->u.regular.run.fontEmSize, &metrics);
1993 else {
1994 FLOAT width = 0.0f;
1996 /* Single underline is added for consecutive underlined runs. In this case underline parameters are
1997 calculated as weighted average, where run width acts as a weight. */
1998 thickness = offset = runheight = 0.0f;
1999 cur = first;
2000 do {
2001 layout_get_erun_font_metrics(layout, cur, &metrics);
2003 thickness += SCALE_FONT_METRIC(metrics.underlineThickness, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
2004 offset += SCALE_FONT_METRIC(metrics.underlinePosition, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
2005 runheight = max(SCALE_FONT_METRIC(metrics.capHeight, cur->run->u.regular.run.fontEmSize, &metrics), runheight);
2006 width += cur->width;
2008 cur = layout_get_next_erun(layout, cur);
2009 } while (cur != last);
2011 thickness /= width;
2012 offset /= width;
2015 cur = first;
2016 do {
2017 struct layout_underline_splitting_params params, prev_params;
2018 struct layout_effective_run *next, *w;
2019 struct layout_underline *u;
2021 init_u_splitting_params_from_erun(cur, &prev_params);
2022 while ((next = layout_get_next_erun(layout, cur)) != last) {
2023 init_u_splitting_params_from_erun(next, &params);
2024 if (!is_same_u_splitting(&prev_params, &params))
2025 break;
2026 cur = next;
2029 u = heap_alloc(sizeof(*u));
2030 if (!u)
2031 return E_OUTOFMEMORY;
2033 w = cur;
2034 u->u.width = 0.0f;
2035 while (w != next) {
2036 u->u.width += w->width;
2037 w = layout_get_next_erun(layout, w);
2040 u->u.thickness = thickness;
2041 /* Font metrics convention is to have it negative when below baseline, for rendering
2042 however Y grows from baseline down for horizontal baseline. */
2043 u->u.offset = -offset;
2044 u->u.runHeight = runheight;
2045 u->u.readingDirection = is_run_rtl(cur) ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
2046 DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
2047 u->u.flowDirection = layout->format.flow;
2048 u->u.localeName = cur->run->u.regular.descr.localeName;
2049 u->u.measuringMode = layout->measuringmode;
2050 u->run = cur;
2051 list_add_tail(&layout->underlines, &u->entry);
2053 cur = next;
2054 } while (cur != last);
2056 return S_OK;
2059 /* Adds zero width line, metrics are derived from font at specified text position. */
2060 static HRESULT layout_set_dummy_line_metrics(struct dwrite_textlayout *layout, UINT32 pos)
2062 DWRITE_LINE_METRICS1 metrics = { 0 };
2063 DWRITE_FONT_METRICS fontmetrics;
2064 struct layout_range *range;
2065 IDWriteFontFace *fontface;
2066 IDWriteFont *font;
2067 HRESULT hr;
2069 range = get_layout_range_by_pos(layout, pos);
2070 hr = create_matching_font(range->collection,
2071 range->fontfamily,
2072 range->weight,
2073 range->style,
2074 range->stretch,
2075 &font);
2076 if (FAILED(hr))
2077 return hr;
2078 hr = IDWriteFont_CreateFontFace(font, &fontface);
2079 IDWriteFont_Release(font);
2080 if (FAILED(hr))
2081 return hr;
2083 layout_get_font_metrics(layout, fontface, range->fontsize, &fontmetrics);
2084 layout_get_font_height(range->fontsize, &fontmetrics, &metrics.baseline, &metrics.height);
2085 IDWriteFontFace_Release(fontface);
2087 return layout_set_line_metrics(layout, &metrics);
2090 static void layout_add_line(struct dwrite_textlayout *layout, UINT32 first_cluster, UINT32 last_cluster,
2091 UINT32 *textpos)
2093 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
2094 struct layout_final_splitting_params params, prev_params;
2095 DWRITE_INLINE_OBJECT_METRICS sign_metrics = { 0 };
2096 UINT32 line = layout->metrics.lineCount, i;
2097 DWRITE_LINE_METRICS1 metrics = { 0 };
2098 UINT32 index, start, pos = *textpos;
2099 FLOAT descent, trailingspacewidth;
2100 BOOL append_trimming_run = FALSE;
2101 const struct layout_run *run;
2102 float width = 0.0f, origin_x;
2103 HRESULT hr;
2105 /* Take a look at clusters we got for this line in reverse order to set trailing properties for current line */
2106 for (index = last_cluster, trailingspacewidth = 0.0f; index >= first_cluster; index--) {
2107 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
2108 struct layout_cluster *lc = &layout->clusters[index];
2109 WCHAR ch;
2111 /* This also filters out clusters added from inline objects, those are never
2112 treated as a white space. */
2113 if (!cluster->isWhitespace)
2114 break;
2116 /* Every isNewline cluster is also isWhitespace, but not every
2117 newline character cluster has isNewline set, so go back to original string. */
2118 ch = lc->run->u.regular.descr.string[lc->position];
2119 if (cluster->length == 1 && lb_is_newline_char(ch))
2120 metrics.newlineLength += cluster->length;
2122 metrics.trailingWhitespaceLength += cluster->length;
2123 trailingspacewidth += cluster->width;
2125 if (index == 0)
2126 break;
2129 /* Line metrics length includes trailing whitespace length too */
2130 for (i = first_cluster; i <= last_cluster; i++)
2131 metrics.length += layout->clustermetrics[i].length;
2133 /* Ignore trailing whitespaces */
2134 while (last_cluster > first_cluster) {
2135 if (!layout->clustermetrics[last_cluster].isWhitespace)
2136 break;
2138 last_cluster--;
2141 /* Does not include trailing space width */
2142 if (!layout->clustermetrics[last_cluster].isWhitespace)
2143 width = get_cluster_range_width(layout, first_cluster, last_cluster + 1);
2145 /* Append trimming run if necessary */
2146 if (width > layout->metrics.layoutWidth && layout->format.trimmingsign != NULL &&
2147 layout->format.trimming.granularity != DWRITE_TRIMMING_GRANULARITY_NONE) {
2148 FLOAT trimmed_width = width;
2150 hr = IDWriteInlineObject_GetMetrics(layout->format.trimmingsign, &sign_metrics);
2151 if (SUCCEEDED(hr)) {
2152 while (last_cluster > first_cluster) {
2153 if (trimmed_width + sign_metrics.width <= layout->metrics.layoutWidth)
2154 break;
2155 if (layout->format.trimming.granularity == DWRITE_TRIMMING_GRANULARITY_CHARACTER)
2156 trimmed_width -= layout->clustermetrics[last_cluster--].width;
2157 else {
2158 while (last_cluster > first_cluster) {
2159 trimmed_width -= layout->clustermetrics[last_cluster].width;
2160 if (layout->clustermetrics[last_cluster--].canWrapLineAfter)
2161 break;
2165 append_trimming_run = TRUE;
2167 else
2168 WARN("Failed to get trimming sign metrics, lines won't be trimmed, hr %#x.\n", hr);
2170 width = trimmed_width + sign_metrics.width;
2173 layout_splitting_params_from_pos(layout, pos, &params);
2174 prev_params = params;
2175 run = layout->clusters[first_cluster].run;
2177 /* Form runs from a range of clusters; this is what will be reported with DrawGlyphRun() */
2178 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0f;
2179 for (start = first_cluster, i = first_cluster; i <= last_cluster; i++) {
2180 layout_splitting_params_from_pos(layout, pos, &params);
2182 if (run != layout->clusters[i].run || !is_same_splitting_params(&prev_params, &params)) {
2183 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, &prev_params);
2184 if (FAILED(hr))
2185 return;
2187 origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) :
2188 get_cluster_range_width(layout, start, i);
2189 run = layout->clusters[i].run;
2190 start = i;
2193 prev_params = params;
2194 pos += layout->clustermetrics[i].length;
2197 /* Final run from what's left from cluster range */
2198 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, &prev_params);
2199 if (FAILED(hr))
2200 return;
2202 if (get_cluster_range_width(layout, start, i) + sign_metrics.width > layout->metrics.layoutWidth)
2203 append_trimming_run = FALSE;
2205 if (append_trimming_run) {
2206 struct layout_effective_inline *trimming_sign;
2208 trimming_sign = heap_alloc(sizeof(*trimming_sign));
2209 if (!trimming_sign)
2210 return;
2212 trimming_sign->object = layout->format.trimmingsign;
2213 trimming_sign->width = sign_metrics.width;
2214 origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) : get_cluster_range_width(layout, start, i);
2215 trimming_sign->origin.x = is_rtl ? origin_x - trimming_sign->width : origin_x;
2216 trimming_sign->origin.y = 0.0f; /* set after line is built */
2217 trimming_sign->align_dx = 0.0f;
2218 trimming_sign->baseline = sign_metrics.baseline;
2220 trimming_sign->is_sideways = FALSE;
2221 trimming_sign->is_rtl = FALSE;
2222 trimming_sign->line = line;
2224 trimming_sign->effect = layout_get_effect_from_pos(layout, layout->clusters[i].position +
2225 layout->clusters[i].run->start_position);
2227 list_add_tail(&layout->inlineobjects, &trimming_sign->entry);
2230 /* Look for max baseline and descent for this line */
2231 for (index = first_cluster, metrics.baseline = 0.0f, descent = 0.0f; index <= last_cluster; index++) {
2232 const struct layout_run *cur = layout->clusters[index].run;
2233 FLOAT cur_descent = cur->height - cur->baseline;
2235 if (cur->baseline > metrics.baseline)
2236 metrics.baseline = cur->baseline;
2237 if (cur_descent > descent)
2238 descent = cur_descent;
2241 layout->metrics.width = max(width, layout->metrics.width);
2242 layout->metrics.widthIncludingTrailingWhitespace = max(width + trailingspacewidth,
2243 layout->metrics.widthIncludingTrailingWhitespace);
2245 metrics.height = descent + metrics.baseline;
2246 metrics.isTrimmed = append_trimming_run || width > layout->metrics.layoutWidth;
2247 layout_set_line_metrics(layout, &metrics);
2249 *textpos += metrics.length;
2252 static void layout_set_line_positions(struct dwrite_textlayout *layout)
2254 struct layout_effective_inline *inrun;
2255 struct layout_effective_run *erun;
2256 FLOAT origin_y;
2257 UINT32 line;
2259 /* Now all line info is here, update effective runs positions in flow direction */
2260 erun = layout_get_next_erun(layout, NULL);
2261 inrun = layout_get_next_inline_run(layout, NULL);
2263 for (line = 0, origin_y = 0.0f; line < layout->metrics.lineCount; line++)
2265 float pos_y = origin_y + layout->lines[line].metrics.baseline;
2267 /* For all runs on this line */
2268 while (erun && erun->line == line) {
2269 erun->origin.y = pos_y;
2270 erun = layout_get_next_erun(layout, erun);
2273 /* Same for inline runs */
2274 while (inrun && inrun->line == line) {
2275 inrun->origin.y = pos_y - inrun->baseline;
2276 inrun = layout_get_next_inline_run(layout, inrun);
2279 origin_y += layout->lines[line].metrics.height;
2282 layout->metrics.height = origin_y;
2284 /* Initial paragraph alignment is always near */
2285 if (layout->format.paralign != DWRITE_PARAGRAPH_ALIGNMENT_NEAR)
2286 layout_apply_par_alignment(layout);
2289 static BOOL layout_can_wrap_after(const struct dwrite_textlayout *layout, UINT32 cluster)
2291 if (layout->format.wrapping == DWRITE_WORD_WRAPPING_CHARACTER)
2292 return TRUE;
2294 return layout->clustermetrics[cluster].canWrapLineAfter;
2297 static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
2299 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
2300 struct layout_effective_run *erun, *first_underlined;
2301 UINT32 i, start, textpos, last_breaking_point;
2302 DWRITE_LINE_METRICS1 metrics;
2303 FLOAT width;
2304 UINT32 line;
2305 HRESULT hr;
2307 if (!(layout->recompute & RECOMPUTE_LINES))
2308 return S_OK;
2310 free_layout_eruns(layout);
2312 hr = layout_compute(layout);
2313 if (FAILED(hr))
2314 return hr;
2316 layout->metrics.lineCount = 0;
2317 memset(&metrics, 0, sizeof(metrics));
2319 layout->metrics.height = 0.0f;
2320 layout->metrics.width = 0.0f;
2321 layout->metrics.widthIncludingTrailingWhitespace = 0.0f;
2323 last_breaking_point = ~0u;
2325 for (i = 0, start = 0, width = 0.0f, textpos = 0; i < layout->cluster_count; i++) {
2326 BOOL overflow = FALSE;
2328 while (i < layout->cluster_count && !layout->clustermetrics[i].isNewline) {
2329 /* Check for overflow */
2330 overflow = ((width + layout->clustermetrics[i].width > layout->metrics.layoutWidth) &&
2331 (layout->format.wrapping != DWRITE_WORD_WRAPPING_NO_WRAP));
2332 if (overflow)
2333 break;
2335 if (layout_can_wrap_after(layout, i))
2336 last_breaking_point = i;
2337 width += layout->clustermetrics[i].width;
2338 i++;
2340 i = min(i, layout->cluster_count - 1);
2342 /* Ignore if overflown on whitespace */
2343 if (overflow && !(layout->clustermetrics[i].isWhitespace && layout_can_wrap_after(layout, i))) {
2344 /* Use most recently found breaking point */
2345 if (last_breaking_point != ~0u) {
2346 i = last_breaking_point;
2347 last_breaking_point = ~0u;
2349 else {
2350 /* Otherwise proceed forward to next newline or breaking point */
2351 for (; i < layout->cluster_count; i++)
2352 if (layout_can_wrap_after(layout, i) || layout->clustermetrics[i].isNewline)
2353 break;
2356 i = min(i, layout->cluster_count - 1);
2358 layout_add_line(layout, start, i, &textpos);
2359 start = i + 1;
2360 width = 0.0f;
2363 /* Add dummy line if:
2364 - there's no text, metrics come from first range in this case;
2365 - last ended with a mandatory break, metrics come from last text position.
2367 if (layout->len == 0)
2368 hr = layout_set_dummy_line_metrics(layout, 0);
2369 else if (layout->cluster_count && layout->clustermetrics[layout->cluster_count - 1].isNewline)
2370 hr = layout_set_dummy_line_metrics(layout, layout->len - 1);
2371 if (FAILED(hr))
2372 return hr;
2374 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
2375 layout->metrics.top = 0.0f;
2376 layout->metrics.maxBidiReorderingDepth = 1; /* FIXME */
2378 /* Add explicit underlined runs */
2379 erun = layout_get_next_erun(layout, NULL);
2380 first_underlined = erun && erun->underlined ? erun : NULL;
2381 for (line = 0; line < layout->metrics.lineCount; line++) {
2382 while (erun && erun->line == line) {
2383 erun = layout_get_next_erun(layout, erun);
2385 if (first_underlined && (!erun || !erun->underlined)) {
2386 layout_add_underline(layout, first_underlined, erun);
2387 first_underlined = NULL;
2389 else if (!first_underlined && erun && erun->underlined)
2390 first_underlined = erun;
2394 /* Position runs in flow direction */
2395 layout_set_line_positions(layout);
2397 /* Initial alignment is always leading */
2398 if (layout->format.textalignment != DWRITE_TEXT_ALIGNMENT_LEADING)
2399 layout_apply_text_alignment(layout);
2401 layout->recompute &= ~RECOMPUTE_LINES;
2402 return hr;
2405 static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum layout_range_attr_kind attr,
2406 struct layout_range_attr_value *value)
2408 struct layout_range_spacing const *range_spacing = (struct layout_range_spacing*)h;
2409 struct layout_range_iface const *range_iface = (struct layout_range_iface*)h;
2410 struct layout_range_bool const *range_bool = (struct layout_range_bool*)h;
2411 struct layout_range const *range = (struct layout_range*)h;
2413 switch (attr) {
2414 case LAYOUT_RANGE_ATTR_WEIGHT:
2415 return range->weight == value->u.weight;
2416 case LAYOUT_RANGE_ATTR_STYLE:
2417 return range->style == value->u.style;
2418 case LAYOUT_RANGE_ATTR_STRETCH:
2419 return range->stretch == value->u.stretch;
2420 case LAYOUT_RANGE_ATTR_FONTSIZE:
2421 return range->fontsize == value->u.fontsize;
2422 case LAYOUT_RANGE_ATTR_INLINE:
2423 return range->object == value->u.object;
2424 case LAYOUT_RANGE_ATTR_EFFECT:
2425 return range_iface->iface == value->u.effect;
2426 case LAYOUT_RANGE_ATTR_UNDERLINE:
2427 return range_bool->value == value->u.underline;
2428 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2429 return range_bool->value == value->u.strikethrough;
2430 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2431 return range->pair_kerning == value->u.pair_kerning;
2432 case LAYOUT_RANGE_ATTR_FONTCOLL:
2433 return range->collection == value->u.collection;
2434 case LAYOUT_RANGE_ATTR_LOCALE:
2435 return !wcsicmp(range->locale, value->u.locale);
2436 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2437 return !wcscmp(range->fontfamily, value->u.fontfamily);
2438 case LAYOUT_RANGE_ATTR_SPACING:
2439 return range_spacing->leading == value->u.spacing.leading &&
2440 range_spacing->trailing == value->u.spacing.trailing &&
2441 range_spacing->min_advance == value->u.spacing.min_advance;
2442 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2443 return range_iface->iface == (IUnknown*)value->u.typography;
2444 default:
2448 return FALSE;
2451 static inline BOOL is_same_layout_attributes(struct layout_range_header const *hleft, struct layout_range_header const *hright)
2453 switch (hleft->kind)
2455 case LAYOUT_RANGE_REGULAR:
2457 struct layout_range const *left = (struct layout_range const*)hleft;
2458 struct layout_range const *right = (struct layout_range const*)hright;
2459 return left->weight == right->weight &&
2460 left->style == right->style &&
2461 left->stretch == right->stretch &&
2462 left->fontsize == right->fontsize &&
2463 left->object == right->object &&
2464 left->pair_kerning == right->pair_kerning &&
2465 left->collection == right->collection &&
2466 !wcsicmp(left->locale, right->locale) &&
2467 !wcscmp(left->fontfamily, right->fontfamily);
2469 case LAYOUT_RANGE_UNDERLINE:
2470 case LAYOUT_RANGE_STRIKETHROUGH:
2472 struct layout_range_bool const *left = (struct layout_range_bool const*)hleft;
2473 struct layout_range_bool const *right = (struct layout_range_bool const*)hright;
2474 return left->value == right->value;
2476 case LAYOUT_RANGE_EFFECT:
2477 case LAYOUT_RANGE_TYPOGRAPHY:
2479 struct layout_range_iface const *left = (struct layout_range_iface const*)hleft;
2480 struct layout_range_iface const *right = (struct layout_range_iface const*)hright;
2481 return left->iface == right->iface;
2483 case LAYOUT_RANGE_SPACING:
2485 struct layout_range_spacing const *left = (struct layout_range_spacing const*)hleft;
2486 struct layout_range_spacing const *right = (struct layout_range_spacing const*)hright;
2487 return left->leading == right->leading &&
2488 left->trailing == right->trailing &&
2489 left->min_advance == right->min_advance;
2491 default:
2492 FIXME("unknown range kind %d\n", hleft->kind);
2493 return FALSE;
2497 static inline BOOL is_same_text_range(const DWRITE_TEXT_RANGE *left, const DWRITE_TEXT_RANGE *right)
2499 return left->startPosition == right->startPosition && left->length == right->length;
2502 /* Allocates range and inits it with default values from text format. */
2503 static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout *layout, const DWRITE_TEXT_RANGE *r,
2504 enum layout_range_kind kind)
2506 struct layout_range_header *h;
2508 switch (kind)
2510 case LAYOUT_RANGE_REGULAR:
2512 struct layout_range *range;
2514 range = heap_alloc_zero(sizeof(*range));
2515 if (!range) return NULL;
2517 range->weight = layout->format.weight;
2518 range->style = layout->format.style;
2519 range->stretch = layout->format.stretch;
2520 range->fontsize = layout->format.fontsize;
2522 range->fontfamily = heap_strdupW(layout->format.family_name);
2523 if (!range->fontfamily)
2525 heap_free(range);
2526 return NULL;
2529 range->collection = layout->format.collection;
2530 if (range->collection)
2531 IDWriteFontCollection_AddRef(range->collection);
2532 wcscpy(range->locale, layout->format.locale);
2534 h = &range->h;
2535 break;
2537 case LAYOUT_RANGE_UNDERLINE:
2538 case LAYOUT_RANGE_STRIKETHROUGH:
2540 struct layout_range_bool *range;
2542 range = heap_alloc_zero(sizeof(*range));
2543 if (!range) return NULL;
2545 h = &range->h;
2546 break;
2548 case LAYOUT_RANGE_EFFECT:
2549 case LAYOUT_RANGE_TYPOGRAPHY:
2551 struct layout_range_iface *range;
2553 range = heap_alloc_zero(sizeof(*range));
2554 if (!range) return NULL;
2556 h = &range->h;
2557 break;
2559 case LAYOUT_RANGE_SPACING:
2561 struct layout_range_spacing *range;
2563 range = heap_alloc_zero(sizeof(*range));
2564 if (!range) return NULL;
2566 h = &range->h;
2567 break;
2569 default:
2570 FIXME("unknown range kind %d\n", kind);
2571 return NULL;
2574 h->kind = kind;
2575 h->range = *r;
2576 return h;
2579 static struct layout_range_header *alloc_layout_range_from(struct layout_range_header *h, const DWRITE_TEXT_RANGE *r)
2581 struct layout_range_header *ret;
2583 switch (h->kind)
2585 case LAYOUT_RANGE_REGULAR:
2587 struct layout_range *from = (struct layout_range*)h;
2589 struct layout_range *range = heap_alloc(sizeof(*range));
2590 if (!range) return NULL;
2592 *range = *from;
2593 range->fontfamily = heap_strdupW(from->fontfamily);
2594 if (!range->fontfamily) {
2595 heap_free(range);
2596 return NULL;
2599 /* update refcounts */
2600 if (range->object)
2601 IDWriteInlineObject_AddRef(range->object);
2602 if (range->collection)
2603 IDWriteFontCollection_AddRef(range->collection);
2604 ret = &range->h;
2605 break;
2607 case LAYOUT_RANGE_UNDERLINE:
2608 case LAYOUT_RANGE_STRIKETHROUGH:
2610 struct layout_range_bool *strike = heap_alloc(sizeof(*strike));
2611 if (!strike) return NULL;
2613 *strike = *(struct layout_range_bool*)h;
2614 ret = &strike->h;
2615 break;
2617 case LAYOUT_RANGE_EFFECT:
2618 case LAYOUT_RANGE_TYPOGRAPHY:
2620 struct layout_range_iface *effect = heap_alloc(sizeof(*effect));
2621 if (!effect) return NULL;
2623 *effect = *(struct layout_range_iface*)h;
2624 if (effect->iface)
2625 IUnknown_AddRef(effect->iface);
2626 ret = &effect->h;
2627 break;
2629 case LAYOUT_RANGE_SPACING:
2631 struct layout_range_spacing *spacing = heap_alloc(sizeof(*spacing));
2632 if (!spacing) return NULL;
2634 *spacing = *(struct layout_range_spacing*)h;
2635 ret = &spacing->h;
2636 break;
2638 default:
2639 FIXME("unknown range kind %d\n", h->kind);
2640 return NULL;
2643 ret->range = *r;
2644 return ret;
2647 static void free_layout_range(struct layout_range_header *h)
2649 if (!h)
2650 return;
2652 switch (h->kind)
2654 case LAYOUT_RANGE_REGULAR:
2656 struct layout_range *range = (struct layout_range*)h;
2658 if (range->object)
2659 IDWriteInlineObject_Release(range->object);
2660 if (range->collection)
2661 IDWriteFontCollection_Release(range->collection);
2662 heap_free(range->fontfamily);
2663 break;
2665 case LAYOUT_RANGE_EFFECT:
2666 case LAYOUT_RANGE_TYPOGRAPHY:
2668 struct layout_range_iface *range = (struct layout_range_iface*)h;
2669 if (range->iface)
2670 IUnknown_Release(range->iface);
2671 break;
2673 default:
2677 heap_free(h);
2680 static void free_layout_ranges_list(struct dwrite_textlayout *layout)
2682 struct layout_range_header *cur, *cur2;
2684 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->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->underline_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->strike_ranges, struct layout_range_header, entry) {
2695 list_remove(&cur->entry);
2696 free_layout_range(cur);
2699 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->effects, struct layout_range_header, entry) {
2700 list_remove(&cur->entry);
2701 free_layout_range(cur);
2704 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->spacing, struct layout_range_header, entry) {
2705 list_remove(&cur->entry);
2706 free_layout_range(cur);
2709 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->typographies, struct layout_range_header, entry) {
2710 list_remove(&cur->entry);
2711 free_layout_range(cur);
2715 static struct layout_range_header *find_outer_range(struct list *ranges, const DWRITE_TEXT_RANGE *range)
2717 struct layout_range_header *cur;
2719 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
2721 if (cur->range.startPosition > range->startPosition)
2722 return NULL;
2724 if ((cur->range.startPosition + cur->range.length < range->startPosition + range->length) &&
2725 (range->startPosition < cur->range.startPosition + cur->range.length))
2726 return NULL;
2727 if (cur->range.startPosition + cur->range.length >= range->startPosition + range->length)
2728 return cur;
2731 return NULL;
2734 static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
2736 if (*dest == value) return FALSE;
2738 if (*dest)
2739 IUnknown_Release(*dest);
2740 *dest = value;
2741 if (*dest)
2742 IUnknown_AddRef(*dest);
2744 return TRUE;
2747 static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2749 struct layout_range_spacing *dest_spacing = (struct layout_range_spacing*)h;
2750 struct layout_range_iface *dest_iface = (struct layout_range_iface*)h;
2751 struct layout_range_bool *dest_bool = (struct layout_range_bool*)h;
2752 struct layout_range *dest = (struct layout_range*)h;
2754 BOOL changed = FALSE;
2756 switch (attr) {
2757 case LAYOUT_RANGE_ATTR_WEIGHT:
2758 changed = dest->weight != value->u.weight;
2759 dest->weight = value->u.weight;
2760 break;
2761 case LAYOUT_RANGE_ATTR_STYLE:
2762 changed = dest->style != value->u.style;
2763 dest->style = value->u.style;
2764 break;
2765 case LAYOUT_RANGE_ATTR_STRETCH:
2766 changed = dest->stretch != value->u.stretch;
2767 dest->stretch = value->u.stretch;
2768 break;
2769 case LAYOUT_RANGE_ATTR_FONTSIZE:
2770 changed = dest->fontsize != value->u.fontsize;
2771 dest->fontsize = value->u.fontsize;
2772 break;
2773 case LAYOUT_RANGE_ATTR_INLINE:
2774 changed = set_layout_range_iface_attr((IUnknown**)&dest->object, (IUnknown*)value->u.object);
2775 break;
2776 case LAYOUT_RANGE_ATTR_EFFECT:
2777 changed = set_layout_range_iface_attr(&dest_iface->iface, value->u.effect);
2778 break;
2779 case LAYOUT_RANGE_ATTR_UNDERLINE:
2780 changed = dest_bool->value != value->u.underline;
2781 dest_bool->value = value->u.underline;
2782 break;
2783 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2784 changed = dest_bool->value != value->u.strikethrough;
2785 dest_bool->value = value->u.strikethrough;
2786 break;
2787 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2788 changed = dest->pair_kerning != value->u.pair_kerning;
2789 dest->pair_kerning = value->u.pair_kerning;
2790 break;
2791 case LAYOUT_RANGE_ATTR_FONTCOLL:
2792 changed = set_layout_range_iface_attr((IUnknown**)&dest->collection, (IUnknown*)value->u.collection);
2793 break;
2794 case LAYOUT_RANGE_ATTR_LOCALE:
2795 changed = !!wcsicmp(dest->locale, value->u.locale);
2796 if (changed)
2798 wcscpy(dest->locale, value->u.locale);
2799 wcslwr(dest->locale);
2801 break;
2802 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2803 changed = !!wcscmp(dest->fontfamily, value->u.fontfamily);
2804 if (changed)
2806 heap_free(dest->fontfamily);
2807 dest->fontfamily = heap_strdupW(value->u.fontfamily);
2809 break;
2810 case LAYOUT_RANGE_ATTR_SPACING:
2811 changed = dest_spacing->leading != value->u.spacing.leading ||
2812 dest_spacing->trailing != value->u.spacing.trailing ||
2813 dest_spacing->min_advance != value->u.spacing.min_advance;
2814 dest_spacing->leading = value->u.spacing.leading;
2815 dest_spacing->trailing = value->u.spacing.trailing;
2816 dest_spacing->min_advance = value->u.spacing.min_advance;
2817 break;
2818 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2819 changed = set_layout_range_iface_attr(&dest_iface->iface, (IUnknown*)value->u.typography);
2820 break;
2821 default:
2825 return changed;
2828 static inline BOOL is_in_layout_range(const DWRITE_TEXT_RANGE *outer, const DWRITE_TEXT_RANGE *inner)
2830 return (inner->startPosition >= outer->startPosition) &&
2831 (inner->startPosition + inner->length <= outer->startPosition + outer->length);
2834 static inline HRESULT return_range(const struct layout_range_header *h, DWRITE_TEXT_RANGE *r)
2836 if (r) *r = h->range;
2837 return S_OK;
2840 /* Sets attribute value for given range, does all needed splitting/merging of existing ranges. */
2841 static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2843 struct layout_range_header *cur, *right, *left, *outer;
2844 BOOL changed = FALSE;
2845 struct list *ranges;
2846 DWRITE_TEXT_RANGE r;
2848 /* ignore zero length ranges */
2849 if (value->range.length == 0)
2850 return S_OK;
2852 if (~0u - value->range.startPosition < value->range.length)
2853 return E_INVALIDARG;
2855 /* select from ranges lists */
2856 switch (attr)
2858 case LAYOUT_RANGE_ATTR_WEIGHT:
2859 case LAYOUT_RANGE_ATTR_STYLE:
2860 case LAYOUT_RANGE_ATTR_STRETCH:
2861 case LAYOUT_RANGE_ATTR_FONTSIZE:
2862 case LAYOUT_RANGE_ATTR_INLINE:
2863 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2864 case LAYOUT_RANGE_ATTR_FONTCOLL:
2865 case LAYOUT_RANGE_ATTR_LOCALE:
2866 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2867 ranges = &layout->ranges;
2868 break;
2869 case LAYOUT_RANGE_ATTR_UNDERLINE:
2870 ranges = &layout->underline_ranges;
2871 break;
2872 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2873 ranges = &layout->strike_ranges;
2874 break;
2875 case LAYOUT_RANGE_ATTR_EFFECT:
2876 ranges = &layout->effects;
2877 break;
2878 case LAYOUT_RANGE_ATTR_SPACING:
2879 ranges = &layout->spacing;
2880 break;
2881 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2882 ranges = &layout->typographies;
2883 break;
2884 default:
2885 FIXME("unknown attr kind %d\n", attr);
2886 return E_FAIL;
2889 /* If new range is completely within existing range, split existing range in two */
2890 if ((outer = find_outer_range(ranges, &value->range))) {
2892 /* no need to add same range */
2893 if (is_same_layout_attrvalue(outer, attr, value))
2894 return S_OK;
2896 /* for matching range bounds just replace data */
2897 if (is_same_text_range(&outer->range, &value->range)) {
2898 changed = set_layout_range_attrval(outer, attr, value);
2899 goto done;
2902 /* add new range to the left */
2903 if (value->range.startPosition == outer->range.startPosition) {
2904 left = alloc_layout_range_from(outer, &value->range);
2905 if (!left) return E_OUTOFMEMORY;
2907 changed = set_layout_range_attrval(left, attr, value);
2908 list_add_before(&outer->entry, &left->entry);
2909 outer->range.startPosition += value->range.length;
2910 outer->range.length -= value->range.length;
2911 goto done;
2914 /* add new range to the right */
2915 if (value->range.startPosition + value->range.length == outer->range.startPosition + outer->range.length) {
2916 right = alloc_layout_range_from(outer, &value->range);
2917 if (!right) return E_OUTOFMEMORY;
2919 changed = set_layout_range_attrval(right, attr, value);
2920 list_add_after(&outer->entry, &right->entry);
2921 outer->range.length -= value->range.length;
2922 goto done;
2925 r.startPosition = value->range.startPosition + value->range.length;
2926 r.length = outer->range.length + outer->range.startPosition - r.startPosition;
2928 /* right part */
2929 right = alloc_layout_range_from(outer, &r);
2930 /* new range in the middle */
2931 cur = alloc_layout_range_from(outer, &value->range);
2932 if (!right || !cur) {
2933 free_layout_range(right);
2934 free_layout_range(cur);
2935 return E_OUTOFMEMORY;
2938 /* reuse container range as a left part */
2939 outer->range.length = value->range.startPosition - outer->range.startPosition;
2941 /* new part */
2942 set_layout_range_attrval(cur, attr, value);
2944 list_add_after(&outer->entry, &cur->entry);
2945 list_add_after(&cur->entry, &right->entry);
2947 layout->recompute = RECOMPUTE_EVERYTHING;
2948 return S_OK;
2951 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2952 Update all of them. */
2953 left = get_layout_range_header_by_pos(ranges, value->range.startPosition);
2954 if (left->range.startPosition == value->range.startPosition)
2955 changed = set_layout_range_attrval(left, attr, value);
2956 else /* need to split */ {
2957 r.startPosition = value->range.startPosition;
2958 r.length = left->range.length - value->range.startPosition + left->range.startPosition;
2959 left->range.length -= r.length;
2960 cur = alloc_layout_range_from(left, &r);
2961 changed = set_layout_range_attrval(cur, attr, value);
2962 list_add_after(&left->entry, &cur->entry);
2964 cur = LIST_ENTRY(list_next(ranges, &left->entry), struct layout_range_header, entry);
2966 /* for all existing ranges covered by new one update value */
2967 while (cur && is_in_layout_range(&value->range, &cur->range)) {
2968 changed |= set_layout_range_attrval(cur, attr, value);
2969 cur = LIST_ENTRY(list_next(ranges, &cur->entry), struct layout_range_header, entry);
2972 /* it's possible rightmost range intersects */
2973 if (cur && (cur->range.startPosition < value->range.startPosition + value->range.length)) {
2974 r.startPosition = cur->range.startPosition;
2975 r.length = value->range.startPosition + value->range.length - cur->range.startPosition;
2976 left = alloc_layout_range_from(cur, &r);
2977 changed |= set_layout_range_attrval(left, attr, value);
2978 cur->range.startPosition += left->range.length;
2979 cur->range.length -= left->range.length;
2980 list_add_before(&cur->entry, &left->entry);
2983 done:
2984 if (changed) {
2985 struct list *next, *i;
2987 layout->recompute = RECOMPUTE_EVERYTHING;
2988 i = list_head(ranges);
2989 while ((next = list_next(ranges, i))) {
2990 struct layout_range_header *next_range = LIST_ENTRY(next, struct layout_range_header, entry);
2992 cur = LIST_ENTRY(i, struct layout_range_header, entry);
2993 if (is_same_layout_attributes(cur, next_range)) {
2994 /* remove similar range */
2995 cur->range.length += next_range->range.length;
2996 list_remove(next);
2997 free_layout_range(next_range);
2999 else
3000 i = list_next(ranges, i);
3004 return S_OK;
3007 static inline const WCHAR *get_string_attribute_ptr(struct layout_range *range, enum layout_range_attr_kind kind)
3009 const WCHAR *str;
3011 switch (kind) {
3012 case LAYOUT_RANGE_ATTR_LOCALE:
3013 str = range->locale;
3014 break;
3015 case LAYOUT_RANGE_ATTR_FONTFAMILY:
3016 str = range->fontfamily;
3017 break;
3018 default:
3019 str = NULL;
3022 return str;
3025 static HRESULT get_string_attribute_length(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
3026 UINT32 *length, DWRITE_TEXT_RANGE *r)
3028 struct layout_range *range;
3029 const WCHAR *str;
3031 range = get_layout_range_by_pos(layout, position);
3032 if (!range) {
3033 *length = 0;
3034 return S_OK;
3037 str = get_string_attribute_ptr(range, kind);
3038 *length = wcslen(str);
3039 return return_range(&range->h, r);
3042 static HRESULT get_string_attribute_value(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
3043 WCHAR *ret, UINT32 length, DWRITE_TEXT_RANGE *r)
3045 struct layout_range *range;
3046 const WCHAR *str;
3048 if (length == 0)
3049 return E_INVALIDARG;
3051 ret[0] = 0;
3052 range = get_layout_range_by_pos(layout, position);
3053 if (!range)
3054 return E_INVALIDARG;
3056 str = get_string_attribute_ptr(range, kind);
3057 if (length < wcslen(str) + 1)
3058 return E_NOT_SUFFICIENT_BUFFER;
3060 wcscpy(ret, str);
3061 return return_range(&range->h, r);
3064 static HRESULT WINAPI dwritetextlayout_QueryInterface(IDWriteTextLayout4 *iface, REFIID riid, void **obj)
3066 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3068 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
3070 *obj = NULL;
3072 if (IsEqualIID(riid, &IID_IDWriteTextLayout4) ||
3073 IsEqualIID(riid, &IID_IDWriteTextLayout3) ||
3074 IsEqualIID(riid, &IID_IDWriteTextLayout2) ||
3075 IsEqualIID(riid, &IID_IDWriteTextLayout1) ||
3076 IsEqualIID(riid, &IID_IDWriteTextLayout) ||
3077 IsEqualIID(riid, &IID_IUnknown))
3079 *obj = iface;
3081 else if (IsEqualIID(riid, &IID_IDWriteTextFormat3) ||
3082 IsEqualIID(riid, &IID_IDWriteTextFormat2) ||
3083 IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
3084 IsEqualIID(riid, &IID_IDWriteTextFormat))
3086 *obj = &layout->IDWriteTextFormat3_iface;
3089 if (*obj) {
3090 IDWriteTextLayout4_AddRef(iface);
3091 return S_OK;
3094 WARN("%s not implemented.\n", debugstr_guid(riid));
3096 return E_NOINTERFACE;
3099 static ULONG WINAPI dwritetextlayout_AddRef(IDWriteTextLayout4 *iface)
3101 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3102 ULONG refcount = InterlockedIncrement(&layout->refcount);
3104 TRACE("%p, refcount %u.\n", iface, refcount);
3106 return refcount;
3109 static ULONG WINAPI dwritetextlayout_Release(IDWriteTextLayout4 *iface)
3111 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3112 ULONG refcount = InterlockedDecrement(&layout->refcount);
3114 TRACE("%p, refcount %u.\n", iface, refcount);
3116 if (!refcount)
3118 IDWriteFactory7_Release(layout->factory);
3119 free_layout_ranges_list(layout);
3120 free_layout_eruns(layout);
3121 free_layout_runs(layout);
3122 release_format_data(&layout->format);
3123 heap_free(layout->nominal_breakpoints);
3124 heap_free(layout->actual_breakpoints);
3125 heap_free(layout->clustermetrics);
3126 heap_free(layout->clusters);
3127 heap_free(layout->lines);
3128 heap_free(layout->str);
3129 heap_free(layout);
3132 return refcount;
3135 static HRESULT WINAPI dwritetextlayout_SetTextAlignment(IDWriteTextLayout4 *iface, DWRITE_TEXT_ALIGNMENT alignment)
3137 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3138 return IDWriteTextFormat3_SetTextAlignment(&layout->IDWriteTextFormat3_iface, alignment);
3141 static HRESULT WINAPI dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout4 *iface,
3142 DWRITE_PARAGRAPH_ALIGNMENT alignment)
3144 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3145 return IDWriteTextFormat3_SetParagraphAlignment(&layout->IDWriteTextFormat3_iface, alignment);
3148 static HRESULT WINAPI dwritetextlayout_SetWordWrapping(IDWriteTextLayout4 *iface, DWRITE_WORD_WRAPPING wrapping)
3150 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3151 return IDWriteTextFormat3_SetWordWrapping(&layout->IDWriteTextFormat3_iface, wrapping);
3154 static HRESULT WINAPI dwritetextlayout_SetReadingDirection(IDWriteTextLayout4 *iface,
3155 DWRITE_READING_DIRECTION direction)
3157 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3158 return IDWriteTextFormat3_SetReadingDirection(&layout->IDWriteTextFormat3_iface, direction);
3161 static HRESULT WINAPI dwritetextlayout_SetFlowDirection(IDWriteTextLayout4 *iface, DWRITE_FLOW_DIRECTION direction)
3163 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3164 return IDWriteTextFormat3_SetFlowDirection(&layout->IDWriteTextFormat3_iface, direction);
3167 static HRESULT WINAPI dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout4 *iface, FLOAT tabstop)
3169 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3170 return IDWriteTextFormat3_SetIncrementalTabStop(&layout->IDWriteTextFormat3_iface, tabstop);
3173 static HRESULT WINAPI dwritetextlayout_SetTrimming(IDWriteTextLayout4 *iface, DWRITE_TRIMMING const *trimming,
3174 IDWriteInlineObject *trimming_sign)
3176 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3177 return IDWriteTextFormat3_SetTrimming(&layout->IDWriteTextFormat3_iface, trimming, trimming_sign);
3180 static HRESULT WINAPI dwritetextlayout_SetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING_METHOD spacing,
3181 FLOAT line_spacing, FLOAT baseline)
3183 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3184 return IDWriteTextFormat1_SetLineSpacing((IDWriteTextFormat1 *)&layout->IDWriteTextFormat3_iface, spacing,
3185 line_spacing, baseline);
3188 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextlayout_GetTextAlignment(IDWriteTextLayout4 *iface)
3190 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3191 return IDWriteTextFormat3_GetTextAlignment(&layout->IDWriteTextFormat3_iface);
3194 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout4 *iface)
3196 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3197 return IDWriteTextFormat3_GetParagraphAlignment(&layout->IDWriteTextFormat3_iface);
3200 static DWRITE_WORD_WRAPPING WINAPI dwritetextlayout_GetWordWrapping(IDWriteTextLayout4 *iface)
3202 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3203 return IDWriteTextFormat3_GetWordWrapping(&layout->IDWriteTextFormat3_iface);
3206 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_GetReadingDirection(IDWriteTextLayout4 *iface)
3208 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3209 return IDWriteTextFormat3_GetReadingDirection(&layout->IDWriteTextFormat3_iface);
3212 static DWRITE_FLOW_DIRECTION WINAPI dwritetextlayout_GetFlowDirection(IDWriteTextLayout4 *iface)
3214 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3215 return IDWriteTextFormat3_GetFlowDirection(&layout->IDWriteTextFormat3_iface);
3218 static FLOAT WINAPI dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout4 *iface)
3220 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3221 return IDWriteTextFormat3_GetIncrementalTabStop(&layout->IDWriteTextFormat3_iface);
3224 static HRESULT WINAPI dwritetextlayout_GetTrimming(IDWriteTextLayout4 *iface, DWRITE_TRIMMING *options,
3225 IDWriteInlineObject **trimming_sign)
3227 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3228 return IDWriteTextFormat3_GetTrimming(&layout->IDWriteTextFormat3_iface, options, trimming_sign);
3231 static HRESULT WINAPI dwritetextlayout_GetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING_METHOD *method,
3232 FLOAT *spacing, FLOAT *baseline)
3234 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3235 return IDWriteTextFormat_GetLineSpacing((IDWriteTextFormat *)&layout->IDWriteTextFormat3_iface, method,
3236 spacing, baseline);
3239 static HRESULT WINAPI dwritetextlayout_GetFontCollection(IDWriteTextLayout4 *iface, IDWriteFontCollection **collection)
3241 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3242 return IDWriteTextFormat3_GetFontCollection(&layout->IDWriteTextFormat3_iface, collection);
3245 static UINT32 WINAPI dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout4 *iface)
3247 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3248 return IDWriteTextFormat3_GetFontFamilyNameLength(&layout->IDWriteTextFormat3_iface);
3251 static HRESULT WINAPI dwritetextlayout_GetFontFamilyName(IDWriteTextLayout4 *iface, WCHAR *name, UINT32 size)
3253 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3254 return IDWriteTextFormat3_GetFontFamilyName(&layout->IDWriteTextFormat3_iface, name, size);
3257 static DWRITE_FONT_WEIGHT WINAPI dwritetextlayout_GetFontWeight(IDWriteTextLayout4 *iface)
3259 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3260 return IDWriteTextFormat3_GetFontWeight(&layout->IDWriteTextFormat3_iface);
3263 static DWRITE_FONT_STYLE WINAPI dwritetextlayout_GetFontStyle(IDWriteTextLayout4 *iface)
3265 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3266 return IDWriteTextFormat3_GetFontStyle(&layout->IDWriteTextFormat3_iface);
3269 static DWRITE_FONT_STRETCH WINAPI dwritetextlayout_GetFontStretch(IDWriteTextLayout4 *iface)
3271 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3272 return IDWriteTextFormat3_GetFontStretch(&layout->IDWriteTextFormat3_iface);
3275 static FLOAT WINAPI dwritetextlayout_GetFontSize(IDWriteTextLayout4 *iface)
3277 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3278 return IDWriteTextFormat3_GetFontSize(&layout->IDWriteTextFormat3_iface);
3281 static UINT32 WINAPI dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout4 *iface)
3283 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3284 return IDWriteTextFormat3_GetLocaleNameLength(&layout->IDWriteTextFormat3_iface);
3287 static HRESULT WINAPI dwritetextlayout_GetLocaleName(IDWriteTextLayout4 *iface, WCHAR *name, UINT32 size)
3289 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3290 return IDWriteTextFormat3_GetLocaleName(&layout->IDWriteTextFormat3_iface, name, size);
3293 static HRESULT WINAPI dwritetextlayout_SetMaxWidth(IDWriteTextLayout4 *iface, FLOAT maxWidth)
3295 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3296 BOOL changed;
3298 TRACE("%p, %.8e.\n", iface, maxWidth);
3300 if (maxWidth < 0.0f)
3301 return E_INVALIDARG;
3303 changed = layout->metrics.layoutWidth != maxWidth;
3304 layout->metrics.layoutWidth = maxWidth;
3306 if (changed)
3307 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
3308 return S_OK;
3311 static HRESULT WINAPI dwritetextlayout_SetMaxHeight(IDWriteTextLayout4 *iface, FLOAT maxHeight)
3313 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3314 BOOL changed;
3316 TRACE("%p, %.8e.\n", iface, maxHeight);
3318 if (maxHeight < 0.0f)
3319 return E_INVALIDARG;
3321 changed = layout->metrics.layoutHeight != maxHeight;
3322 layout->metrics.layoutHeight = maxHeight;
3324 if (changed)
3325 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
3326 return S_OK;
3329 static HRESULT WINAPI dwritetextlayout_SetFontCollection(IDWriteTextLayout4 *iface, IDWriteFontCollection *collection,
3330 DWRITE_TEXT_RANGE range)
3332 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3333 struct layout_range_attr_value value;
3335 TRACE("%p, %p, %s.\n", iface, collection, debugstr_range(&range));
3337 value.range = range;
3338 value.u.collection = collection;
3339 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_FONTCOLL, &value);
3342 static HRESULT WINAPI dwritetextlayout_SetFontFamilyName(IDWriteTextLayout4 *iface, WCHAR const *name,
3343 DWRITE_TEXT_RANGE range)
3345 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3346 struct layout_range_attr_value value;
3348 TRACE("%p, %s, %s.\n", iface, debugstr_w(name), debugstr_range(&range));
3350 if (!name)
3351 return E_INVALIDARG;
3353 value.range = range;
3354 value.u.fontfamily = name;
3355 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_FONTFAMILY, &value);
3358 static HRESULT WINAPI dwritetextlayout_SetFontWeight(IDWriteTextLayout4 *iface, DWRITE_FONT_WEIGHT weight,
3359 DWRITE_TEXT_RANGE range)
3361 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3362 struct layout_range_attr_value value;
3364 TRACE("%p, %d, %s.\n", iface, weight, debugstr_range(&range));
3366 if ((UINT32)weight > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
3367 return E_INVALIDARG;
3369 value.range = range;
3370 value.u.weight = weight;
3371 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_WEIGHT, &value);
3374 static HRESULT WINAPI dwritetextlayout_SetFontStyle(IDWriteTextLayout4 *iface, DWRITE_FONT_STYLE style,
3375 DWRITE_TEXT_RANGE range)
3377 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3378 struct layout_range_attr_value value;
3380 TRACE("%p, %d, %s.\n", iface, style, debugstr_range(&range));
3382 if ((UINT32)style > DWRITE_FONT_STYLE_ITALIC)
3383 return E_INVALIDARG;
3385 value.range = range;
3386 value.u.style = style;
3387 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_STYLE, &value);
3390 static HRESULT WINAPI dwritetextlayout_SetFontStretch(IDWriteTextLayout4 *iface, DWRITE_FONT_STRETCH stretch,
3391 DWRITE_TEXT_RANGE range)
3393 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3394 struct layout_range_attr_value value;
3396 TRACE("%p, %d, %s.\n", iface, stretch, debugstr_range(&range));
3398 if (stretch == DWRITE_FONT_STRETCH_UNDEFINED || (UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
3399 return E_INVALIDARG;
3401 value.range = range;
3402 value.u.stretch = stretch;
3403 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_STRETCH, &value);
3406 static HRESULT WINAPI dwritetextlayout_SetFontSize(IDWriteTextLayout4 *iface, FLOAT size, DWRITE_TEXT_RANGE range)
3408 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3409 struct layout_range_attr_value value;
3411 TRACE("%p, %.8e, %s.\n", iface, size, debugstr_range(&range));
3413 if (size <= 0.0f)
3414 return E_INVALIDARG;
3416 value.range = range;
3417 value.u.fontsize = size;
3418 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_FONTSIZE, &value);
3421 static HRESULT WINAPI dwritetextlayout_SetUnderline(IDWriteTextLayout4 *iface, BOOL underline, DWRITE_TEXT_RANGE range)
3423 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3424 struct layout_range_attr_value value;
3426 TRACE("%p, %d, %s.\n", iface, underline, debugstr_range(&range));
3428 value.range = range;
3429 value.u.underline = underline;
3430 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_UNDERLINE, &value);
3433 static HRESULT WINAPI dwritetextlayout_SetStrikethrough(IDWriteTextLayout4 *iface, BOOL strikethrough,
3434 DWRITE_TEXT_RANGE range)
3436 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3437 struct layout_range_attr_value value;
3439 TRACE("%p, %d, %s.\n", iface, strikethrough, debugstr_range(&range));
3441 value.range = range;
3442 value.u.strikethrough = strikethrough;
3443 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_STRIKETHROUGH, &value);
3446 static HRESULT WINAPI dwritetextlayout_SetDrawingEffect(IDWriteTextLayout4 *iface, IUnknown* effect,
3447 DWRITE_TEXT_RANGE range)
3449 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3450 struct layout_range_attr_value value;
3452 TRACE("%p, %p, %s.\n", iface, effect, debugstr_range(&range));
3454 value.range = range;
3455 value.u.effect = effect;
3456 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_EFFECT, &value);
3459 static HRESULT WINAPI dwritetextlayout_SetInlineObject(IDWriteTextLayout4 *iface, IDWriteInlineObject *object,
3460 DWRITE_TEXT_RANGE range)
3462 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3463 struct layout_range_attr_value value;
3465 TRACE("%p, %p, %s.\n", iface, object, debugstr_range(&range));
3467 value.range = range;
3468 value.u.object = object;
3469 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_INLINE, &value);
3472 static HRESULT WINAPI dwritetextlayout_SetTypography(IDWriteTextLayout4 *iface, IDWriteTypography *typography,
3473 DWRITE_TEXT_RANGE range)
3475 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3476 struct layout_range_attr_value value;
3478 TRACE("%p, %p, %s.\n", iface, typography, debugstr_range(&range));
3480 value.range = range;
3481 value.u.typography = typography;
3482 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_TYPOGRAPHY, &value);
3485 static HRESULT WINAPI dwritetextlayout_SetLocaleName(IDWriteTextLayout4 *iface, WCHAR const* locale,
3486 DWRITE_TEXT_RANGE range)
3488 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3489 struct layout_range_attr_value value;
3491 TRACE("%p, %s, %s.\n", iface, debugstr_w(locale), debugstr_range(&range));
3493 if (!locale || wcslen(locale) > LOCALE_NAME_MAX_LENGTH-1)
3494 return E_INVALIDARG;
3496 value.range = range;
3497 value.u.locale = locale;
3498 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_LOCALE, &value);
3501 static FLOAT WINAPI dwritetextlayout_GetMaxWidth(IDWriteTextLayout4 *iface)
3503 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3505 TRACE("%p.\n", iface);
3507 return layout->metrics.layoutWidth;
3510 static FLOAT WINAPI dwritetextlayout_GetMaxHeight(IDWriteTextLayout4 *iface)
3512 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3514 TRACE("%p.\n", iface);
3516 return layout->metrics.layoutHeight;
3519 static HRESULT WINAPI dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout4 *iface, UINT32 position,
3520 IDWriteFontCollection **collection, DWRITE_TEXT_RANGE *r)
3522 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3523 struct layout_range *range;
3525 TRACE("%p, %u, %p, %p.\n", iface, position, collection, r);
3527 range = get_layout_range_by_pos(layout, position);
3528 *collection = range->collection;
3529 if (*collection)
3530 IDWriteFontCollection_AddRef(*collection);
3532 return return_range(&range->h, r);
3535 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout4 *iface,
3536 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
3538 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3540 TRACE("%p, %d, %p, %p.\n", iface, position, length, r);
3542 return get_string_attribute_length(layout, LAYOUT_RANGE_ATTR_FONTFAMILY, position, length, r);
3545 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout4 *iface,
3546 UINT32 position, WCHAR *name, UINT32 length, DWRITE_TEXT_RANGE *r)
3548 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3550 TRACE("%p, %u, %p, %u, %p.\n", iface, position, name, length, r);
3552 return get_string_attribute_value(layout, LAYOUT_RANGE_ATTR_FONTFAMILY, position, name, length, r);
3555 static HRESULT WINAPI dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout4 *iface,
3556 UINT32 position, DWRITE_FONT_WEIGHT *weight, DWRITE_TEXT_RANGE *r)
3558 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3559 struct layout_range *range;
3561 TRACE("%p, %u, %p, %p.\n", iface, position, weight, r);
3563 range = get_layout_range_by_pos(layout, position);
3564 *weight = range->weight;
3566 return return_range(&range->h, r);
3569 static HRESULT WINAPI dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout4 *iface,
3570 UINT32 position, DWRITE_FONT_STYLE *style, DWRITE_TEXT_RANGE *r)
3572 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3573 struct layout_range *range;
3575 TRACE("%p, %u, %p, %p.\n", iface, position, style, r);
3577 range = get_layout_range_by_pos(layout, position);
3578 *style = range->style;
3579 return return_range(&range->h, r);
3582 static HRESULT WINAPI dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout4 *iface,
3583 UINT32 position, DWRITE_FONT_STRETCH *stretch, DWRITE_TEXT_RANGE *r)
3585 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3586 struct layout_range *range;
3588 TRACE("%p, %u, %p, %p.\n", iface, position, stretch, r);
3590 range = get_layout_range_by_pos(layout, position);
3591 *stretch = range->stretch;
3592 return return_range(&range->h, r);
3595 static HRESULT WINAPI dwritetextlayout_layout_GetFontSize(IDWriteTextLayout4 *iface,
3596 UINT32 position, FLOAT *size, DWRITE_TEXT_RANGE *r)
3598 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3599 struct layout_range *range;
3601 TRACE("%p, %u, %p, %p.\n", iface, position, size, r);
3603 range = get_layout_range_by_pos(layout, position);
3604 *size = range->fontsize;
3605 return return_range(&range->h, r);
3608 static HRESULT WINAPI dwritetextlayout_GetUnderline(IDWriteTextLayout4 *iface,
3609 UINT32 position, BOOL *underline, DWRITE_TEXT_RANGE *r)
3611 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3612 struct layout_range_bool *range;
3614 TRACE("%p, %u, %p, %p.\n", iface, position, underline, r);
3616 range = (struct layout_range_bool *)get_layout_range_header_by_pos(&layout->underline_ranges, position);
3617 *underline = range->value;
3619 return return_range(&range->h, r);
3622 static HRESULT WINAPI dwritetextlayout_GetStrikethrough(IDWriteTextLayout4 *iface,
3623 UINT32 position, BOOL *strikethrough, DWRITE_TEXT_RANGE *r)
3625 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3626 struct layout_range_bool *range;
3628 TRACE("%p, %u, %p, %p.\n", iface, position, strikethrough, r);
3630 range = (struct layout_range_bool *)get_layout_range_header_by_pos(&layout->strike_ranges, position);
3631 *strikethrough = range->value;
3633 return return_range(&range->h, r);
3636 static HRESULT WINAPI dwritetextlayout_GetDrawingEffect(IDWriteTextLayout4 *iface,
3637 UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r)
3639 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3640 struct layout_range_iface *range;
3642 TRACE("%p, %u, %p, %p.\n", iface, position, effect, r);
3644 range = (struct layout_range_iface *)get_layout_range_header_by_pos(&layout->effects, position);
3645 *effect = range->iface;
3646 if (*effect)
3647 IUnknown_AddRef(*effect);
3649 return return_range(&range->h, r);
3652 static HRESULT WINAPI dwritetextlayout_GetInlineObject(IDWriteTextLayout4 *iface,
3653 UINT32 position, IDWriteInlineObject **object, DWRITE_TEXT_RANGE *r)
3655 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3656 struct layout_range *range;
3658 TRACE("%p, %u, %p, %p.\n", iface, position, object, r);
3660 range = get_layout_range_by_pos(layout, position);
3661 *object = range->object;
3662 if (*object)
3663 IDWriteInlineObject_AddRef(*object);
3665 return return_range(&range->h, r);
3668 static HRESULT WINAPI dwritetextlayout_GetTypography(IDWriteTextLayout4 *iface,
3669 UINT32 position, IDWriteTypography** typography, DWRITE_TEXT_RANGE *r)
3671 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3672 struct layout_range_iface *range;
3674 TRACE("%p, %u, %p, %p.\n", iface, position, typography, r);
3676 range = (struct layout_range_iface *)get_layout_range_header_by_pos(&layout->typographies, position);
3677 *typography = (IDWriteTypography *)range->iface;
3678 if (*typography)
3679 IDWriteTypography_AddRef(*typography);
3681 return return_range(&range->h, r);
3684 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout4 *iface,
3685 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
3687 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3689 TRACE("%p, %u, %p, %p.\n", iface, position, length, r);
3691 return get_string_attribute_length(layout, LAYOUT_RANGE_ATTR_LOCALE, position, length, r);
3694 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout4 *iface,
3695 UINT32 position, WCHAR *locale, UINT32 length, DWRITE_TEXT_RANGE *r)
3697 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3699 TRACE("%p, %u, %p, %u, %p.\n", iface, position, locale, length, r);
3701 return get_string_attribute_value(layout, LAYOUT_RANGE_ATTR_LOCALE, position, locale, length, r);
3704 static inline FLOAT renderer_apply_snapping(FLOAT coord, BOOL skiptransform, FLOAT ppdip, FLOAT det,
3705 const DWRITE_MATRIX *m)
3707 D2D1_POINT_2F vec, vec2;
3709 if (!skiptransform) {
3710 /* apply transform */
3711 vec.x = 0.0f;
3712 vec.y = coord * ppdip;
3714 vec2.x = m->m11 * vec.x + m->m21 * vec.y + m->dx;
3715 vec2.y = m->m12 * vec.x + m->m22 * vec.y + m->dy;
3717 /* snap */
3718 vec2.x = floorf(vec2.x + 0.5f);
3719 vec2.y = floorf(vec2.y + 0.5f);
3721 /* apply inverted transform, we don't care about X component at this point */
3722 vec.y = (-m->m12 * vec2.x + m->m11 * vec2.y - (m->m11 * m->dy - m->m12 * m->dx)) / det;
3723 vec.y /= ppdip;
3725 else
3726 vec.y = floorf(coord * ppdip + 0.5f) / ppdip;
3728 return vec.y;
3731 static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout4 *iface,
3732 void *context, IDWriteTextRenderer* renderer, FLOAT origin_x, FLOAT origin_y)
3734 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3735 BOOL disabled = FALSE, skiptransform = FALSE;
3736 struct layout_effective_inline *inlineobject;
3737 struct layout_effective_run *run;
3738 struct layout_strikethrough *s;
3739 struct layout_underline *u;
3740 FLOAT det = 0.0f, ppdip = 0.0f;
3741 DWRITE_MATRIX m = { 0 };
3742 HRESULT hr;
3744 TRACE("%p, %p, %p, %.8e, %.8e.\n", iface, context, renderer, origin_x, origin_y);
3746 hr = layout_compute_effective_runs(layout);
3747 if (FAILED(hr))
3748 return hr;
3750 hr = IDWriteTextRenderer_IsPixelSnappingDisabled(renderer, context, &disabled);
3751 if (FAILED(hr))
3752 return hr;
3754 if (!disabled) {
3755 hr = IDWriteTextRenderer_GetPixelsPerDip(renderer, context, &ppdip);
3756 if (FAILED(hr))
3757 return hr;
3759 hr = IDWriteTextRenderer_GetCurrentTransform(renderer, context, &m);
3760 if (FAILED(hr))
3761 return hr;
3763 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
3764 if (ppdip <= 0.0f ||
3765 (m.m11 * m.m22 != 0.0f && (m.m12 != 0.0f || m.m21 != 0.0f)) ||
3766 (m.m12 * m.m21 != 0.0f && (m.m11 != 0.0f || m.m22 != 0.0f)))
3767 disabled = TRUE;
3768 else
3769 skiptransform = should_skip_transform(&m, &det);
3772 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
3773 /* 1. Regular runs */
3774 LIST_FOR_EACH_ENTRY(run, &layout->eruns, struct layout_effective_run, entry)
3776 const struct regular_layout_run *regular = &run->run->u.regular;
3777 UINT32 start_glyph = regular->clustermap[run->start];
3778 DWRITE_GLYPH_RUN_DESCRIPTION descr;
3779 DWRITE_GLYPH_RUN glyph_run;
3781 /* Everything but cluster map will be reused from nominal run, as we only need
3782 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
3783 it can't be reused because it has to start with 0 index for each reported run. */
3784 glyph_run = regular->run;
3785 glyph_run.glyphCount = run->glyphcount;
3787 /* fixup glyph data arrays */
3788 glyph_run.glyphIndices += start_glyph;
3789 glyph_run.glyphAdvances += start_glyph;
3790 glyph_run.glyphOffsets += start_glyph;
3792 /* description */
3793 descr = regular->descr;
3794 descr.stringLength = run->length;
3795 descr.string += run->start;
3796 descr.clusterMap = run->clustermap;
3797 descr.textPosition += run->start;
3799 /* return value is ignored */
3800 IDWriteTextRenderer_DrawGlyphRun(renderer,
3801 context,
3802 run->origin.x + run->align_dx + origin_x,
3803 SNAP_COORD(run->origin.y + origin_y),
3804 layout->measuringmode,
3805 &glyph_run,
3806 &descr,
3807 run->effect);
3810 /* 2. Inline objects */
3811 LIST_FOR_EACH_ENTRY(inlineobject, &layout->inlineobjects, struct layout_effective_inline, entry)
3813 IDWriteTextRenderer_DrawInlineObject(renderer,
3814 context,
3815 inlineobject->origin.x + inlineobject->align_dx + origin_x,
3816 SNAP_COORD(inlineobject->origin.y + origin_y),
3817 inlineobject->object,
3818 inlineobject->is_sideways,
3819 inlineobject->is_rtl,
3820 inlineobject->effect);
3823 /* 3. Underlines */
3824 LIST_FOR_EACH_ENTRY(u, &layout->underlines, struct layout_underline, entry)
3826 IDWriteTextRenderer_DrawUnderline(renderer,
3827 context,
3828 /* horizontal underline always grows from left to right, width is always added to origin regardless of run direction */
3829 (is_run_rtl(u->run) ? u->run->origin.x - u->run->width : u->run->origin.x) + u->run->align_dx + origin_x,
3830 SNAP_COORD(u->run->origin.y + origin_y),
3831 &u->u,
3832 u->run->effect);
3835 /* 4. Strikethrough */
3836 LIST_FOR_EACH_ENTRY(s, &layout->strikethrough, struct layout_strikethrough, entry)
3838 IDWriteTextRenderer_DrawStrikethrough(renderer,
3839 context,
3840 s->run->origin.x + s->run->align_dx + origin_x,
3841 SNAP_COORD(s->run->origin.y + origin_y),
3842 &s->s,
3843 s->run->effect);
3845 #undef SNAP_COORD
3847 return S_OK;
3850 static HRESULT WINAPI dwritetextlayout_GetLineMetrics(IDWriteTextLayout4 *iface,
3851 DWRITE_LINE_METRICS *metrics, UINT32 max_count, UINT32 *count)
3853 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3854 unsigned int line_count;
3855 HRESULT hr;
3856 size_t i;
3858 TRACE("%p, %p, %u, %p.\n", iface, metrics, max_count, count);
3860 if (FAILED(hr = layout_compute_effective_runs(layout)))
3861 return hr;
3863 if (metrics)
3865 line_count = min(max_count, layout->metrics.lineCount);
3866 for (i = 0; i < line_count; ++i)
3867 memcpy(&metrics[i], &layout->lines[i].metrics, sizeof(*metrics));
3870 *count = layout->metrics.lineCount;
3871 return max_count >= layout->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3874 static HRESULT layout_update_metrics(struct dwrite_textlayout *layout)
3876 return layout_compute_effective_runs(layout);
3879 static HRESULT WINAPI dwritetextlayout_GetMetrics(IDWriteTextLayout4 *iface, DWRITE_TEXT_METRICS *metrics)
3881 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3882 HRESULT hr;
3884 TRACE("%p, %p.\n", iface, metrics);
3886 hr = layout_update_metrics(layout);
3887 if (hr == S_OK)
3888 memcpy(metrics, &layout->metrics, sizeof(*metrics));
3890 return hr;
3893 static void d2d_rect_offset(D2D1_RECT_F *rect, FLOAT x, FLOAT y)
3895 rect->left += x;
3896 rect->right += x;
3897 rect->top += y;
3898 rect->bottom += y;
3901 static BOOL d2d_rect_is_empty(const D2D1_RECT_F *rect)
3903 return ((rect->left >= rect->right) || (rect->top >= rect->bottom));
3906 static void d2d_rect_union(D2D1_RECT_F *dst, const D2D1_RECT_F *src)
3908 if (d2d_rect_is_empty(dst)) {
3909 if (d2d_rect_is_empty(src)) {
3910 dst->left = dst->right = dst->top = dst->bottom = 0.0f;
3911 return;
3913 else
3914 *dst = *src;
3916 else {
3917 if (!d2d_rect_is_empty(src)) {
3918 dst->left = min(dst->left, src->left);
3919 dst->right = max(dst->right, src->right);
3920 dst->top = min(dst->top, src->top);
3921 dst->bottom = max(dst->bottom, src->bottom);
3926 static void layout_get_erun_bbox(struct dwrite_textlayout *layout, struct layout_effective_run *run, D2D1_RECT_F *bbox)
3928 const struct regular_layout_run *regular = &run->run->u.regular;
3929 UINT32 start_glyph = regular->clustermap[run->start];
3930 D2D1_POINT_2F baseline_origin = { 0 }, *origins;
3931 DWRITE_GLYPH_RUN glyph_run;
3932 unsigned int i;
3933 HRESULT hr;
3935 if (run->bbox.top == run->bbox.bottom)
3937 struct dwrite_glyphbitmap glyph_bitmap;
3938 RECT *bbox;
3940 glyph_run = regular->run;
3941 glyph_run.glyphCount = run->glyphcount;
3942 glyph_run.glyphIndices = &regular->run.glyphIndices[start_glyph];
3943 glyph_run.glyphAdvances = &regular->run.glyphAdvances[start_glyph];
3944 glyph_run.glyphOffsets = &regular->run.glyphOffsets[start_glyph];
3946 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
3947 glyph_bitmap.key = glyph_run.fontFace;
3948 glyph_bitmap.simulations = IDWriteFontFace_GetSimulations(glyph_run.fontFace);
3949 glyph_bitmap.emsize = glyph_run.fontEmSize;
3950 glyph_bitmap.nohint = layout->measuringmode == DWRITE_MEASURING_MODE_NATURAL;
3952 bbox = &glyph_bitmap.bbox;
3954 if (!(origins = heap_calloc(glyph_run.glyphCount, sizeof(*origins))))
3955 return;
3957 if (FAILED(hr = compute_glyph_origins(&glyph_run, layout->measuringmode, baseline_origin, &layout->transform, origins)))
3959 WARN("Failed to compute glyph origins, hr %#x.\n", hr);
3960 heap_free(origins);
3961 return;
3964 for (i = 0; i < glyph_run.glyphCount; ++i)
3966 D2D1_RECT_F glyph_bbox;
3968 glyph_bitmap.glyph = glyph_run.glyphIndices[i];
3969 dwrite_fontface_get_glyph_bbox(&glyph_bitmap);
3971 glyph_bbox.left = bbox->left;
3972 glyph_bbox.top = bbox->top;
3973 glyph_bbox.right = bbox->right;
3974 glyph_bbox.bottom = bbox->bottom;
3976 d2d_rect_offset(&glyph_bbox, origins[i].x, origins[i].y);
3977 d2d_rect_union(&run->bbox, &glyph_bbox);
3980 heap_free(origins);
3983 *bbox = run->bbox;
3984 d2d_rect_offset(bbox, run->origin.x + run->align_dx, run->origin.y);
3987 static void layout_get_inlineobj_bbox(struct dwrite_textlayout *layout, struct layout_effective_inline *run,
3988 D2D1_RECT_F *bbox)
3990 DWRITE_OVERHANG_METRICS overhang_metrics = { 0 };
3991 DWRITE_INLINE_OBJECT_METRICS metrics = { 0 };
3992 HRESULT hr;
3994 if (FAILED(hr = IDWriteInlineObject_GetMetrics(run->object, &metrics))) {
3995 WARN("Failed to get inline object metrics, hr %#x.\n", hr);
3996 memset(bbox, 0, sizeof(*bbox));
3997 return;
4000 bbox->left = run->origin.x + run->align_dx;
4001 bbox->right = bbox->left + metrics.width;
4002 bbox->top = run->origin.y;
4003 bbox->bottom = bbox->top + metrics.height;
4005 IDWriteInlineObject_GetOverhangMetrics(run->object, &overhang_metrics);
4007 bbox->left -= overhang_metrics.left;
4008 bbox->right += overhang_metrics.right;
4009 bbox->top -= overhang_metrics.top;
4010 bbox->bottom += overhang_metrics.bottom;
4013 static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout4 *iface,
4014 DWRITE_OVERHANG_METRICS *overhangs)
4016 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4017 struct layout_effective_inline *inline_run;
4018 struct layout_effective_run *run;
4019 D2D1_RECT_F bbox = { 0 };
4020 HRESULT hr;
4022 TRACE("%p, %p.\n", iface, overhangs);
4024 memset(overhangs, 0, sizeof(*overhangs));
4026 if (!(layout->recompute & RECOMPUTE_OVERHANGS))
4028 *overhangs = layout->overhangs;
4029 return S_OK;
4032 hr = layout_compute_effective_runs(layout);
4033 if (FAILED(hr))
4034 return hr;
4036 LIST_FOR_EACH_ENTRY(run, &layout->eruns, struct layout_effective_run, entry)
4038 D2D1_RECT_F run_bbox;
4040 layout_get_erun_bbox(layout, run, &run_bbox);
4041 d2d_rect_union(&bbox, &run_bbox);
4044 LIST_FOR_EACH_ENTRY(inline_run, &layout->inlineobjects, struct layout_effective_inline, entry)
4046 D2D1_RECT_F object_bbox;
4048 layout_get_inlineobj_bbox(layout, inline_run, &object_bbox);
4049 d2d_rect_union(&bbox, &object_bbox);
4052 /* Deltas from layout box. */
4053 layout->overhangs.left = -bbox.left;
4054 layout->overhangs.top = -bbox.top;
4055 layout->overhangs.right = bbox.right - layout->metrics.layoutWidth;
4056 layout->overhangs.bottom = bbox.bottom - layout->metrics.layoutHeight;
4057 layout->recompute &= ~RECOMPUTE_OVERHANGS;
4059 *overhangs = layout->overhangs;
4061 return S_OK;
4064 static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout4 *iface,
4065 DWRITE_CLUSTER_METRICS *metrics, UINT32 max_count, UINT32 *count)
4067 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4068 HRESULT hr;
4070 TRACE("%p, %p, %u, %p.\n", iface, metrics, max_count, count);
4072 hr = layout_compute(layout);
4073 if (FAILED(hr))
4074 return hr;
4076 if (metrics)
4077 memcpy(metrics, layout->clustermetrics, sizeof(DWRITE_CLUSTER_METRICS) * min(max_count, layout->cluster_count));
4079 *count = layout->cluster_count;
4080 return max_count >= layout->cluster_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
4083 static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout4 *iface, FLOAT* min_width)
4085 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4086 UINT32 start;
4087 FLOAT width;
4088 HRESULT hr;
4090 TRACE("%p, %p.\n", iface, min_width);
4092 if (!min_width)
4093 return E_INVALIDARG;
4095 if (!(layout->recompute & RECOMPUTE_MINIMAL_WIDTH))
4096 goto width_done;
4098 *min_width = 0.0f;
4099 hr = layout_compute(layout);
4100 if (FAILED(hr))
4101 return hr;
4103 /* Find widest word without emergency breaking between clusters, trailing whitespaces
4104 preceding breaking point do not contribute to word width. */
4105 for (start = 0; start < layout->cluster_count;)
4107 UINT32 end = start, j, next;
4109 /* Last cluster always could be wrapped after. */
4110 while (!layout->clustermetrics[end].canWrapLineAfter)
4111 end++;
4112 /* make is so current cluster range that we can wrap after is [start,end) */
4113 end++;
4115 next = end;
4117 /* Ignore trailing whitespace clusters, in case of single space range will
4118 be reduced to empty range, or [start,start+1). */
4119 while (end > start && layout->clustermetrics[end-1].isWhitespace)
4120 end--;
4122 /* check if cluster range exceeds last minimal width */
4123 width = 0.0f;
4124 for (j = start; j < end; j++)
4125 width += layout->clustermetrics[j].width;
4127 start = next;
4129 if (width > layout->minwidth)
4130 layout->minwidth = width;
4132 layout->recompute &= ~RECOMPUTE_MINIMAL_WIDTH;
4134 width_done:
4135 *min_width = layout->minwidth;
4136 return S_OK;
4139 static HRESULT WINAPI dwritetextlayout_HitTestPoint(IDWriteTextLayout4 *iface,
4140 FLOAT pointX, FLOAT pointY, BOOL* is_trailinghit, BOOL* is_inside, DWRITE_HIT_TEST_METRICS *metrics)
4142 FIXME("%p, %.8e, %.8e, %p, %p, %p): stub\n", iface, pointX, pointY, is_trailinghit, is_inside, metrics);
4144 return E_NOTIMPL;
4147 static HRESULT WINAPI dwritetextlayout_HitTestTextPosition(IDWriteTextLayout4 *iface,
4148 UINT32 textPosition, BOOL is_trailinghit, FLOAT *pointX, FLOAT *pointY, DWRITE_HIT_TEST_METRICS *metrics)
4150 FIXME("%p, %u, %d, %p, %p, %p): stub\n", iface, textPosition, is_trailinghit, pointX, pointY, metrics);
4152 return E_NOTIMPL;
4155 static HRESULT WINAPI dwritetextlayout_HitTestTextRange(IDWriteTextLayout4 *iface,
4156 UINT32 textPosition, UINT32 textLength, FLOAT originX, FLOAT originY,
4157 DWRITE_HIT_TEST_METRICS *metrics, UINT32 max_metricscount, UINT32* actual_metricscount)
4159 FIXME("%p, %u, %u, %f, %f, %p, %u, %p): stub\n", iface, textPosition, textLength, originX, originY, metrics,
4160 max_metricscount, actual_metricscount);
4162 return E_NOTIMPL;
4165 static HRESULT WINAPI dwritetextlayout1_SetPairKerning(IDWriteTextLayout4 *iface, BOOL is_pairkerning_enabled,
4166 DWRITE_TEXT_RANGE range)
4168 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4169 struct layout_range_attr_value value;
4171 TRACE("%p, %d, %s.\n", iface, is_pairkerning_enabled, debugstr_range(&range));
4173 value.range = range;
4174 value.u.pair_kerning = !!is_pairkerning_enabled;
4175 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_PAIR_KERNING, &value);
4178 static HRESULT WINAPI dwritetextlayout1_GetPairKerning(IDWriteTextLayout4 *iface, UINT32 position,
4179 BOOL *is_pairkerning_enabled, DWRITE_TEXT_RANGE *r)
4181 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4182 struct layout_range *range;
4184 TRACE("%p, %u, %p, %p.\n", iface, position, is_pairkerning_enabled, r);
4186 range = get_layout_range_by_pos(layout, position);
4187 *is_pairkerning_enabled = range->pair_kerning;
4189 return return_range(&range->h, r);
4192 static HRESULT WINAPI dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout4 *iface, FLOAT leading, FLOAT trailing,
4193 FLOAT min_advance, DWRITE_TEXT_RANGE range)
4195 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4196 struct layout_range_attr_value value;
4198 TRACE("%p, %.8e, %.8e, %.8e, %s.\n", iface, leading, trailing, min_advance, debugstr_range(&range));
4200 if (min_advance < 0.0f)
4201 return E_INVALIDARG;
4203 value.range = range;
4204 value.u.spacing.leading = leading;
4205 value.u.spacing.trailing = trailing;
4206 value.u.spacing.min_advance = min_advance;
4207 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_SPACING, &value);
4210 static HRESULT WINAPI dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout4 *iface, UINT32 position, FLOAT *leading,
4211 FLOAT *trailing, FLOAT *min_advance, DWRITE_TEXT_RANGE *r)
4213 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4214 struct layout_range_spacing *range;
4216 TRACE("%p, %u, %p, %p, %p, %p.\n", iface, position, leading, trailing, min_advance, r);
4218 range = (struct layout_range_spacing *)get_layout_range_header_by_pos(&layout->spacing, position);
4219 *leading = range->leading;
4220 *trailing = range->trailing;
4221 *min_advance = range->min_advance;
4223 return return_range(&range->h, r);
4226 static HRESULT WINAPI dwritetextlayout2_GetMetrics(IDWriteTextLayout4 *iface, DWRITE_TEXT_METRICS1 *metrics)
4228 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4229 HRESULT hr;
4231 TRACE("%p, %p.\n", iface, metrics);
4233 if (SUCCEEDED(hr = layout_update_metrics(layout)))
4234 *metrics = layout->metrics;
4236 return hr;
4239 static HRESULT layout_set_vertical_orientation(struct dwrite_textlayout *layout,
4240 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4242 BOOL changed;
4243 HRESULT hr;
4245 if (FAILED(hr = format_set_vertical_orientation(&layout->format, orientation, &changed)))
4246 return hr;
4248 if (changed)
4249 layout->recompute = RECOMPUTE_EVERYTHING;
4251 return S_OK;
4254 static HRESULT WINAPI dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout4 *iface,
4255 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4257 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4259 TRACE("%p, %d.\n", iface, orientation);
4261 return layout_set_vertical_orientation(layout, orientation);
4264 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout4 *iface)
4266 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4268 TRACE("%p.\n", iface);
4270 return layout->format.vertical_orientation;
4273 static HRESULT WINAPI dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout4 *iface, BOOL lastline_wrapping_enabled)
4275 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4277 TRACE("%p, %d.\n", iface, lastline_wrapping_enabled);
4279 return IDWriteTextFormat3_SetLastLineWrapping(&layout->IDWriteTextFormat3_iface, lastline_wrapping_enabled);
4282 static BOOL WINAPI dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout4 *iface)
4284 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4286 TRACE("%p.\n", iface);
4288 return IDWriteTextFormat3_GetLastLineWrapping(&layout->IDWriteTextFormat3_iface);
4291 static HRESULT WINAPI dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout4 *iface,
4292 DWRITE_OPTICAL_ALIGNMENT alignment)
4294 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4296 TRACE("%p, %d.\n", iface, alignment);
4298 return IDWriteTextFormat3_SetOpticalAlignment(&layout->IDWriteTextFormat3_iface, alignment);
4301 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout4 *iface)
4303 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4305 TRACE("%p.\n", iface);
4307 return IDWriteTextFormat3_GetOpticalAlignment(&layout->IDWriteTextFormat3_iface);
4310 static HRESULT WINAPI dwritetextlayout2_SetFontFallback(IDWriteTextLayout4 *iface, IDWriteFontFallback *fallback)
4312 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4314 TRACE("%p, %p.\n", iface, fallback);
4316 return set_fontfallback_for_format(&layout->format, fallback);
4319 static HRESULT WINAPI dwritetextlayout2_GetFontFallback(IDWriteTextLayout4 *iface, IDWriteFontFallback **fallback)
4321 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4323 TRACE("%p, %p.\n", iface, fallback);
4325 return get_fontfallback_from_format(&layout->format, fallback);
4328 static HRESULT WINAPI dwritetextlayout3_InvalidateLayout(IDWriteTextLayout4 *iface)
4330 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4332 TRACE("%p.\n", iface);
4334 layout->recompute = RECOMPUTE_EVERYTHING;
4335 return S_OK;
4338 static HRESULT WINAPI dwritetextlayout3_SetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING const *spacing)
4340 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4341 BOOL changed;
4342 HRESULT hr;
4344 TRACE("%p, %p.\n", iface, spacing);
4346 hr = format_set_linespacing(&layout->format, spacing, &changed);
4347 if (FAILED(hr))
4348 return hr;
4350 if (changed)
4352 if (!(layout->recompute & RECOMPUTE_LINES))
4354 UINT32 line;
4356 for (line = 0; line < layout->metrics.lineCount; line++)
4357 layout_apply_line_spacing(layout, line);
4359 layout_set_line_positions(layout);
4362 layout->recompute |= RECOMPUTE_OVERHANGS;
4365 return S_OK;
4368 static HRESULT WINAPI dwritetextlayout3_GetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING *spacing)
4370 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4372 TRACE("%p, %p.\n", iface, spacing);
4374 *spacing = layout->format.spacing;
4375 return S_OK;
4378 static HRESULT WINAPI dwritetextlayout3_GetLineMetrics(IDWriteTextLayout4 *iface, DWRITE_LINE_METRICS1 *metrics,
4379 UINT32 max_count, UINT32 *count)
4381 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4382 unsigned int line_count;
4383 HRESULT hr;
4384 size_t i;
4386 TRACE("%p, %p, %u, %p.\n", iface, metrics, max_count, count);
4388 if (FAILED(hr = layout_compute_effective_runs(layout)))
4389 return hr;
4391 if (metrics)
4393 line_count = min(max_count, layout->metrics.lineCount);
4394 for (i = 0; i < line_count; ++i)
4395 metrics[i] = layout->lines[i].metrics;
4398 *count = layout->metrics.lineCount;
4399 return max_count >= layout->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
4402 static HRESULT WINAPI dwritetextlayout4_SetFontAxisValues(IDWriteTextLayout4 *iface,
4403 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, DWRITE_TEXT_RANGE range)
4405 FIXME("%p, %p, %u, %s.\n", iface, axis_values, num_values, debugstr_range(&range));
4407 return E_NOTIMPL;
4410 static UINT32 WINAPI dwritetextlayout4_GetFontAxisValueCount(IDWriteTextLayout4 *iface, UINT32 pos)
4412 FIXME("%p, %u.\n", iface, pos);
4414 return 0;
4417 static HRESULT WINAPI dwritetextlayout4_GetFontAxisValues(IDWriteTextLayout4 *iface, UINT32 pos,
4418 DWRITE_FONT_AXIS_VALUE *values, UINT32 num_values, DWRITE_TEXT_RANGE *range)
4420 FIXME("%p, %u, %p, %u, %p.\n", iface, pos, values, num_values, range);
4422 return E_NOTIMPL;
4425 static DWRITE_AUTOMATIC_FONT_AXES WINAPI dwritetextlayout4_GetAutomaticFontAxes(IDWriteTextLayout4 *iface)
4427 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4429 TRACE("%p.\n", iface);
4431 return layout->format.automatic_axes;
4434 static HRESULT WINAPI dwritetextlayout4_SetAutomaticFontAxes(IDWriteTextLayout4 *iface,
4435 DWRITE_AUTOMATIC_FONT_AXES axes)
4437 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4439 TRACE("%p, %d.\n", iface, axes);
4441 if ((unsigned int)axes > DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE)
4442 return E_INVALIDARG;
4444 layout->format.automatic_axes = axes;
4445 return S_OK;
4448 static const IDWriteTextLayout4Vtbl dwritetextlayoutvtbl =
4450 dwritetextlayout_QueryInterface,
4451 dwritetextlayout_AddRef,
4452 dwritetextlayout_Release,
4453 dwritetextlayout_SetTextAlignment,
4454 dwritetextlayout_SetParagraphAlignment,
4455 dwritetextlayout_SetWordWrapping,
4456 dwritetextlayout_SetReadingDirection,
4457 dwritetextlayout_SetFlowDirection,
4458 dwritetextlayout_SetIncrementalTabStop,
4459 dwritetextlayout_SetTrimming,
4460 dwritetextlayout_SetLineSpacing,
4461 dwritetextlayout_GetTextAlignment,
4462 dwritetextlayout_GetParagraphAlignment,
4463 dwritetextlayout_GetWordWrapping,
4464 dwritetextlayout_GetReadingDirection,
4465 dwritetextlayout_GetFlowDirection,
4466 dwritetextlayout_GetIncrementalTabStop,
4467 dwritetextlayout_GetTrimming,
4468 dwritetextlayout_GetLineSpacing,
4469 dwritetextlayout_GetFontCollection,
4470 dwritetextlayout_GetFontFamilyNameLength,
4471 dwritetextlayout_GetFontFamilyName,
4472 dwritetextlayout_GetFontWeight,
4473 dwritetextlayout_GetFontStyle,
4474 dwritetextlayout_GetFontStretch,
4475 dwritetextlayout_GetFontSize,
4476 dwritetextlayout_GetLocaleNameLength,
4477 dwritetextlayout_GetLocaleName,
4478 dwritetextlayout_SetMaxWidth,
4479 dwritetextlayout_SetMaxHeight,
4480 dwritetextlayout_SetFontCollection,
4481 dwritetextlayout_SetFontFamilyName,
4482 dwritetextlayout_SetFontWeight,
4483 dwritetextlayout_SetFontStyle,
4484 dwritetextlayout_SetFontStretch,
4485 dwritetextlayout_SetFontSize,
4486 dwritetextlayout_SetUnderline,
4487 dwritetextlayout_SetStrikethrough,
4488 dwritetextlayout_SetDrawingEffect,
4489 dwritetextlayout_SetInlineObject,
4490 dwritetextlayout_SetTypography,
4491 dwritetextlayout_SetLocaleName,
4492 dwritetextlayout_GetMaxWidth,
4493 dwritetextlayout_GetMaxHeight,
4494 dwritetextlayout_layout_GetFontCollection,
4495 dwritetextlayout_layout_GetFontFamilyNameLength,
4496 dwritetextlayout_layout_GetFontFamilyName,
4497 dwritetextlayout_layout_GetFontWeight,
4498 dwritetextlayout_layout_GetFontStyle,
4499 dwritetextlayout_layout_GetFontStretch,
4500 dwritetextlayout_layout_GetFontSize,
4501 dwritetextlayout_GetUnderline,
4502 dwritetextlayout_GetStrikethrough,
4503 dwritetextlayout_GetDrawingEffect,
4504 dwritetextlayout_GetInlineObject,
4505 dwritetextlayout_GetTypography,
4506 dwritetextlayout_layout_GetLocaleNameLength,
4507 dwritetextlayout_layout_GetLocaleName,
4508 dwritetextlayout_Draw,
4509 dwritetextlayout_GetLineMetrics,
4510 dwritetextlayout_GetMetrics,
4511 dwritetextlayout_GetOverhangMetrics,
4512 dwritetextlayout_GetClusterMetrics,
4513 dwritetextlayout_DetermineMinWidth,
4514 dwritetextlayout_HitTestPoint,
4515 dwritetextlayout_HitTestTextPosition,
4516 dwritetextlayout_HitTestTextRange,
4517 dwritetextlayout1_SetPairKerning,
4518 dwritetextlayout1_GetPairKerning,
4519 dwritetextlayout1_SetCharacterSpacing,
4520 dwritetextlayout1_GetCharacterSpacing,
4521 dwritetextlayout2_GetMetrics,
4522 dwritetextlayout2_SetVerticalGlyphOrientation,
4523 dwritetextlayout2_GetVerticalGlyphOrientation,
4524 dwritetextlayout2_SetLastLineWrapping,
4525 dwritetextlayout2_GetLastLineWrapping,
4526 dwritetextlayout2_SetOpticalAlignment,
4527 dwritetextlayout2_GetOpticalAlignment,
4528 dwritetextlayout2_SetFontFallback,
4529 dwritetextlayout2_GetFontFallback,
4530 dwritetextlayout3_InvalidateLayout,
4531 dwritetextlayout3_SetLineSpacing,
4532 dwritetextlayout3_GetLineSpacing,
4533 dwritetextlayout3_GetLineMetrics,
4534 dwritetextlayout4_SetFontAxisValues,
4535 dwritetextlayout4_GetFontAxisValueCount,
4536 dwritetextlayout4_GetFontAxisValues,
4537 dwritetextlayout4_GetAutomaticFontAxes,
4538 dwritetextlayout4_SetAutomaticFontAxes,
4541 static HRESULT WINAPI dwritetextformat_layout_QueryInterface(IDWriteTextFormat3 *iface, REFIID riid, void **obj)
4543 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4545 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
4547 return IDWriteTextLayout4_QueryInterface(&layout->IDWriteTextLayout4_iface, riid, obj);
4550 static ULONG WINAPI dwritetextformat_layout_AddRef(IDWriteTextFormat3 *iface)
4552 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4553 return IDWriteTextLayout4_AddRef(&layout->IDWriteTextLayout4_iface);
4556 static ULONG WINAPI dwritetextformat_layout_Release(IDWriteTextFormat3 *iface)
4558 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4559 return IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
4562 static HRESULT WINAPI dwritetextformat_layout_SetTextAlignment(IDWriteTextFormat3 *iface,
4563 DWRITE_TEXT_ALIGNMENT alignment)
4565 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4566 BOOL changed;
4567 HRESULT hr;
4569 TRACE("%p, %d.\n", iface, alignment);
4571 hr = format_set_textalignment(&layout->format, alignment, &changed);
4572 if (FAILED(hr))
4573 return hr;
4575 if (changed)
4577 /* if layout is not ready there's nothing to align */
4578 if (!(layout->recompute & RECOMPUTE_LINES))
4579 layout_apply_text_alignment(layout);
4580 layout->recompute |= RECOMPUTE_OVERHANGS;
4583 return S_OK;
4586 static HRESULT WINAPI dwritetextformat_layout_SetParagraphAlignment(IDWriteTextFormat3 *iface,
4587 DWRITE_PARAGRAPH_ALIGNMENT alignment)
4589 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4590 BOOL changed;
4591 HRESULT hr;
4593 TRACE("%p, %d.\n", iface, alignment);
4595 hr = format_set_paralignment(&layout->format, alignment, &changed);
4596 if (FAILED(hr))
4597 return hr;
4599 if (changed)
4601 /* if layout is not ready there's nothing to align */
4602 if (!(layout->recompute & RECOMPUTE_LINES))
4603 layout_apply_par_alignment(layout);
4604 layout->recompute |= RECOMPUTE_OVERHANGS;
4607 return S_OK;
4610 static HRESULT WINAPI dwritetextformat_layout_SetWordWrapping(IDWriteTextFormat3 *iface, DWRITE_WORD_WRAPPING wrapping)
4612 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4613 BOOL changed;
4614 HRESULT hr;
4616 TRACE("%p, %d.\n", iface, wrapping);
4618 hr = format_set_wordwrapping(&layout->format, wrapping, &changed);
4619 if (FAILED(hr))
4620 return hr;
4622 if (changed)
4623 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
4625 return S_OK;
4628 static HRESULT WINAPI dwritetextformat_layout_SetReadingDirection(IDWriteTextFormat3 *iface,
4629 DWRITE_READING_DIRECTION direction)
4631 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4632 BOOL changed;
4633 HRESULT hr;
4635 TRACE("%p, %d.\n", iface, direction);
4637 hr = format_set_readingdirection(&layout->format, direction, &changed);
4638 if (FAILED(hr))
4639 return hr;
4641 if (changed)
4642 layout->recompute = RECOMPUTE_EVERYTHING;
4644 return S_OK;
4647 static HRESULT WINAPI dwritetextformat_layout_SetFlowDirection(IDWriteTextFormat3 *iface,
4648 DWRITE_FLOW_DIRECTION direction)
4650 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4651 BOOL changed;
4652 HRESULT hr;
4654 TRACE("%p, %d.\n", iface, direction);
4656 hr = format_set_flowdirection(&layout->format, direction, &changed);
4657 if (FAILED(hr))
4658 return hr;
4660 if (changed)
4661 layout->recompute = RECOMPUTE_EVERYTHING;
4663 return S_OK;
4666 static HRESULT WINAPI dwritetextformat_layout_SetIncrementalTabStop(IDWriteTextFormat3 *iface, FLOAT tabstop)
4668 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4670 TRACE("%p, %.8e.\n", iface, tabstop);
4672 if (tabstop <= 0.0f)
4673 return E_INVALIDARG;
4675 layout->format.tabstop = tabstop;
4676 return S_OK;
4679 static HRESULT WINAPI dwritetextformat_layout_SetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING const *trimming,
4680 IDWriteInlineObject *trimming_sign)
4682 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4683 BOOL changed;
4684 HRESULT hr;
4686 TRACE("%p, %p, %p.\n", iface, trimming, trimming_sign);
4688 hr = format_set_trimming(&layout->format, trimming, trimming_sign, &changed);
4690 if (changed)
4691 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
4693 return hr;
4696 static HRESULT WINAPI dwritetextformat_layout_SetLineSpacing(IDWriteTextFormat3 *iface,
4697 DWRITE_LINE_SPACING_METHOD method, FLOAT height, FLOAT baseline)
4699 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4700 DWRITE_LINE_SPACING spacing;
4702 TRACE("%p, %d, %.8e, %.8e.\n", iface, method, height, baseline);
4704 spacing = layout->format.spacing;
4705 spacing.method = method;
4706 spacing.height = height;
4707 spacing.baseline = baseline;
4708 return IDWriteTextLayout4_SetLineSpacing(&layout->IDWriteTextLayout4_iface, &spacing);
4711 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_layout_GetTextAlignment(IDWriteTextFormat3 *iface)
4713 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4715 TRACE("%p.\n", iface);
4717 return layout->format.textalignment;
4720 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_layout_GetParagraphAlignment(IDWriteTextFormat3 *iface)
4722 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4724 TRACE("%p.\n", iface);
4726 return layout->format.paralign;
4729 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_layout_GetWordWrapping(IDWriteTextFormat3 *iface)
4731 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4733 TRACE("%p.\n", iface);
4735 return layout->format.wrapping;
4738 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_layout_GetReadingDirection(IDWriteTextFormat3 *iface)
4740 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4742 TRACE("%p.\n", iface);
4744 return layout->format.readingdir;
4747 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_layout_GetFlowDirection(IDWriteTextFormat3 *iface)
4749 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4751 TRACE("%p.\n", iface);
4753 return layout->format.flow;
4756 static FLOAT WINAPI dwritetextformat_layout_GetIncrementalTabStop(IDWriteTextFormat3 *iface)
4758 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4760 TRACE("%p.\n", iface);
4762 return layout->format.tabstop;
4765 static HRESULT WINAPI dwritetextformat_layout_GetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING *options,
4766 IDWriteInlineObject **trimming_sign)
4768 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4770 TRACE("%p, %p, %p.\n", iface, options, trimming_sign);
4772 *options = layout->format.trimming;
4773 *trimming_sign = layout->format.trimmingsign;
4774 if (*trimming_sign)
4775 IDWriteInlineObject_AddRef(*trimming_sign);
4776 return S_OK;
4779 static HRESULT WINAPI dwritetextformat_layout_GetLineSpacing(IDWriteTextFormat3 *iface,
4780 DWRITE_LINE_SPACING_METHOD *method, FLOAT *spacing, FLOAT *baseline)
4782 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4784 TRACE("%p, %p, %p, %p.\n", iface, method, spacing, baseline);
4786 *method = layout->format.spacing.method;
4787 *spacing = layout->format.spacing.height;
4788 *baseline = layout->format.spacing.baseline;
4789 return S_OK;
4792 static HRESULT WINAPI dwritetextformat_layout_GetFontCollection(IDWriteTextFormat3 *iface,
4793 IDWriteFontCollection **collection)
4795 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4797 TRACE("%p, %p.\n", iface, collection);
4799 *collection = layout->format.collection;
4800 if (*collection)
4801 IDWriteFontCollection_AddRef(*collection);
4802 return S_OK;
4805 static UINT32 WINAPI dwritetextformat_layout_GetFontFamilyNameLength(IDWriteTextFormat3 *iface)
4807 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4809 TRACE("%p.\n", iface);
4811 return layout->format.family_len;
4814 static HRESULT WINAPI dwritetextformat_layout_GetFontFamilyName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
4816 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4818 TRACE("%p, %p, %u.\n", iface, name, size);
4820 if (size <= layout->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
4821 wcscpy(name, layout->format.family_name);
4822 return S_OK;
4825 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_layout_GetFontWeight(IDWriteTextFormat3 *iface)
4827 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4829 TRACE("%p.\n", iface);
4831 return layout->format.weight;
4834 static DWRITE_FONT_STYLE WINAPI dwritetextformat_layout_GetFontStyle(IDWriteTextFormat3 *iface)
4836 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4838 TRACE("%p.\n", iface);
4840 return layout->format.style;
4843 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_layout_GetFontStretch(IDWriteTextFormat3 *iface)
4845 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4847 TRACE("%p.\n", iface);
4849 return layout->format.stretch;
4852 static FLOAT WINAPI dwritetextformat_layout_GetFontSize(IDWriteTextFormat3 *iface)
4854 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4856 TRACE("%p.\n", iface);
4858 return layout->format.fontsize;
4861 static UINT32 WINAPI dwritetextformat_layout_GetLocaleNameLength(IDWriteTextFormat3 *iface)
4863 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4865 TRACE("%p.\n", iface);
4867 return layout->format.locale_len;
4870 static HRESULT WINAPI dwritetextformat_layout_GetLocaleName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
4872 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4874 TRACE("%p, %p, %u.\n", iface, name, size);
4876 if (size <= layout->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
4877 wcscpy(name, layout->format.locale);
4878 return S_OK;
4881 static HRESULT WINAPI dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat3 *iface,
4882 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4884 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4886 TRACE("%p, %d.\n", iface, orientation);
4888 return layout_set_vertical_orientation(layout, orientation);
4891 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat3 *iface)
4893 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4895 TRACE("%p.\n", iface);
4897 return layout->format.vertical_orientation;
4900 static HRESULT WINAPI dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat3 *iface,
4901 BOOL lastline_wrapping_enabled)
4903 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4905 TRACE("%p, %d.\n", iface, lastline_wrapping_enabled);
4907 layout->format.last_line_wrapping = !!lastline_wrapping_enabled;
4908 return S_OK;
4911 static BOOL WINAPI dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat3 *iface)
4913 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4915 TRACE("%p.\n", iface);
4917 return layout->format.last_line_wrapping;
4920 static HRESULT WINAPI dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat3 *iface,
4921 DWRITE_OPTICAL_ALIGNMENT alignment)
4923 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4925 TRACE("%p, %d.\n", iface, alignment);
4927 return format_set_optical_alignment(&layout->format, alignment);
4930 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat3 *iface)
4932 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4934 TRACE("%p.\n", iface);
4936 return layout->format.optical_alignment;
4939 static HRESULT WINAPI dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat3 *iface,
4940 IDWriteFontFallback *fallback)
4942 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4944 TRACE("%p, %p.\n", iface, fallback);
4946 return IDWriteTextLayout4_SetFontFallback(&layout->IDWriteTextLayout4_iface, fallback);
4949 static HRESULT WINAPI dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat3 *iface,
4950 IDWriteFontFallback **fallback)
4952 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4954 TRACE("%p, %p.\n", iface, fallback);
4956 return IDWriteTextLayout4_GetFontFallback(&layout->IDWriteTextLayout4_iface, fallback);
4959 static HRESULT WINAPI dwritetextformat2_layout_SetLineSpacing(IDWriteTextFormat3 *iface,
4960 DWRITE_LINE_SPACING const *spacing)
4962 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4963 return IDWriteTextLayout4_SetLineSpacing(&layout->IDWriteTextLayout4_iface, spacing);
4966 static HRESULT WINAPI dwritetextformat2_layout_GetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING *spacing)
4968 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4969 return IDWriteTextLayout4_GetLineSpacing(&layout->IDWriteTextLayout4_iface, spacing);
4972 static HRESULT WINAPI dwritetextformat3_layout_SetFontAxisValues(IDWriteTextFormat3 *iface,
4973 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values)
4975 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4977 TRACE("%p, %p, %u.\n", iface, axis_values, num_values);
4979 return format_set_font_axisvalues(&layout->format, axis_values, num_values);
4982 static UINT32 WINAPI dwritetextformat3_layout_GetFontAxisValueCount(IDWriteTextFormat3 *iface)
4984 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4986 TRACE("%p.\n", iface);
4988 return layout->format.axis_values_count;
4991 static HRESULT WINAPI dwritetextformat3_layout_GetFontAxisValues(IDWriteTextFormat3 *iface,
4992 DWRITE_FONT_AXIS_VALUE *axis_values, UINT32 num_values)
4994 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4996 TRACE("%p, %p, %u.\n", iface, axis_values, num_values);
4998 return format_get_font_axisvalues(&layout->format, axis_values, num_values);
5001 static DWRITE_AUTOMATIC_FONT_AXES WINAPI dwritetextformat3_layout_GetAutomaticFontAxes(IDWriteTextFormat3 *iface)
5003 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
5004 return IDWriteTextLayout4_GetAutomaticFontAxes(&layout->IDWriteTextLayout4_iface);
5007 static HRESULT WINAPI dwritetextformat3_layout_SetAutomaticFontAxes(IDWriteTextFormat3 *iface,
5008 DWRITE_AUTOMATIC_FONT_AXES axes)
5010 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
5011 return IDWriteTextLayout4_SetAutomaticFontAxes(&layout->IDWriteTextLayout4_iface, axes);
5014 static const IDWriteTextFormat3Vtbl dwritetextformat3_layout_vtbl =
5016 dwritetextformat_layout_QueryInterface,
5017 dwritetextformat_layout_AddRef,
5018 dwritetextformat_layout_Release,
5019 dwritetextformat_layout_SetTextAlignment,
5020 dwritetextformat_layout_SetParagraphAlignment,
5021 dwritetextformat_layout_SetWordWrapping,
5022 dwritetextformat_layout_SetReadingDirection,
5023 dwritetextformat_layout_SetFlowDirection,
5024 dwritetextformat_layout_SetIncrementalTabStop,
5025 dwritetextformat_layout_SetTrimming,
5026 dwritetextformat_layout_SetLineSpacing,
5027 dwritetextformat_layout_GetTextAlignment,
5028 dwritetextformat_layout_GetParagraphAlignment,
5029 dwritetextformat_layout_GetWordWrapping,
5030 dwritetextformat_layout_GetReadingDirection,
5031 dwritetextformat_layout_GetFlowDirection,
5032 dwritetextformat_layout_GetIncrementalTabStop,
5033 dwritetextformat_layout_GetTrimming,
5034 dwritetextformat_layout_GetLineSpacing,
5035 dwritetextformat_layout_GetFontCollection,
5036 dwritetextformat_layout_GetFontFamilyNameLength,
5037 dwritetextformat_layout_GetFontFamilyName,
5038 dwritetextformat_layout_GetFontWeight,
5039 dwritetextformat_layout_GetFontStyle,
5040 dwritetextformat_layout_GetFontStretch,
5041 dwritetextformat_layout_GetFontSize,
5042 dwritetextformat_layout_GetLocaleNameLength,
5043 dwritetextformat_layout_GetLocaleName,
5044 dwritetextformat1_layout_SetVerticalGlyphOrientation,
5045 dwritetextformat1_layout_GetVerticalGlyphOrientation,
5046 dwritetextformat1_layout_SetLastLineWrapping,
5047 dwritetextformat1_layout_GetLastLineWrapping,
5048 dwritetextformat1_layout_SetOpticalAlignment,
5049 dwritetextformat1_layout_GetOpticalAlignment,
5050 dwritetextformat1_layout_SetFontFallback,
5051 dwritetextformat1_layout_GetFontFallback,
5052 dwritetextformat2_layout_SetLineSpacing,
5053 dwritetextformat2_layout_GetLineSpacing,
5054 dwritetextformat3_layout_SetFontAxisValues,
5055 dwritetextformat3_layout_GetFontAxisValueCount,
5056 dwritetextformat3_layout_GetFontAxisValues,
5057 dwritetextformat3_layout_GetAutomaticFontAxes,
5058 dwritetextformat3_layout_SetAutomaticFontAxes,
5061 static HRESULT WINAPI dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink1 *iface,
5062 REFIID riid, void **obj)
5064 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink1) ||
5065 IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) ||
5066 IsEqualIID(riid, &IID_IUnknown))
5068 *obj = iface;
5069 IDWriteTextAnalysisSink1_AddRef(iface);
5070 return S_OK;
5073 WARN("%s not implemented.\n", debugstr_guid(riid));
5075 *obj = NULL;
5076 return E_NOINTERFACE;
5079 static ULONG WINAPI dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink1 *iface)
5081 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
5082 return IDWriteTextLayout4_AddRef(&layout->IDWriteTextLayout4_iface);
5085 static ULONG WINAPI dwritetextlayout_sink_Release(IDWriteTextAnalysisSink1 *iface)
5087 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
5088 return IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
5091 static HRESULT WINAPI dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink1 *iface,
5092 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
5094 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
5095 struct layout_run *run;
5096 HRESULT hr;
5098 TRACE("[%u,%u) script=%u:%s\n", position, position + length, sa->script, debugstr_sa_script(sa->script));
5100 if (FAILED(hr = alloc_layout_run(LAYOUT_RUN_REGULAR, position, &run)))
5101 return hr;
5103 run->u.regular.descr.string = &layout->str[position];
5104 run->u.regular.descr.stringLength = length;
5105 run->u.regular.descr.textPosition = position;
5106 run->u.regular.sa = *sa;
5107 list_add_tail(&layout->runs, &run->entry);
5108 return S_OK;
5111 static HRESULT WINAPI dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink1 *iface,
5112 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
5114 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
5116 if (position + length > layout->len)
5117 return E_FAIL;
5119 memcpy(&layout->nominal_breakpoints[position], breakpoints, length*sizeof(DWRITE_LINE_BREAKPOINT));
5120 return S_OK;
5123 static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink1 *iface, UINT32 position,
5124 UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
5126 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
5127 struct layout_run *cur_run;
5128 HRESULT hr;
5130 TRACE("[%u,%u) %u %u\n", position, position + length, explicitLevel, resolvedLevel);
5132 LIST_FOR_EACH_ENTRY(cur_run, &layout->runs, struct layout_run, entry) {
5133 struct regular_layout_run *cur = &cur_run->u.regular;
5134 struct layout_run *run;
5136 if (cur_run->kind == LAYOUT_RUN_INLINE)
5137 continue;
5139 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
5140 if (position < cur->descr.textPosition || position >= cur->descr.textPosition + cur->descr.stringLength)
5141 continue;
5143 /* full hit - just set run level */
5144 if (cur->descr.textPosition == position && cur->descr.stringLength == length) {
5145 cur->run.bidiLevel = resolvedLevel;
5146 break;
5149 /* current run is fully covered, move to next one */
5150 if (cur->descr.textPosition == position && cur->descr.stringLength < length) {
5151 cur->run.bidiLevel = resolvedLevel;
5152 position += cur->descr.stringLength;
5153 length -= cur->descr.stringLength;
5154 continue;
5157 /* all fully covered runs are processed at this point, reuse existing run for remaining
5158 reported bidi range and add another run for the rest of original one */
5160 if (FAILED(hr = alloc_layout_run(LAYOUT_RUN_REGULAR, position + length, &run)))
5161 return hr;
5163 *run = *cur_run;
5164 run->u.regular.descr.textPosition = position + length;
5165 run->u.regular.descr.stringLength = cur->descr.stringLength - length;
5166 run->u.regular.descr.string = &layout->str[position + length];
5168 /* reduce existing run */
5169 cur->run.bidiLevel = resolvedLevel;
5170 cur->descr.stringLength = length;
5172 list_add_after(&cur_run->entry, &run->entry);
5173 break;
5176 return S_OK;
5179 static HRESULT WINAPI dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink1 *iface,
5180 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
5182 return E_NOTIMPL;
5185 static HRESULT WINAPI dwritetextlayout_sink_SetGlyphOrientation(IDWriteTextAnalysisSink1 *iface,
5186 UINT32 position, UINT32 length, DWRITE_GLYPH_ORIENTATION_ANGLE angle, UINT8 adjusted_bidi_level,
5187 BOOL is_sideways, BOOL is_rtl)
5189 return E_NOTIMPL;
5192 static const IDWriteTextAnalysisSink1Vtbl dwritetextlayoutsinkvtbl = {
5193 dwritetextlayout_sink_QueryInterface,
5194 dwritetextlayout_sink_AddRef,
5195 dwritetextlayout_sink_Release,
5196 dwritetextlayout_sink_SetScriptAnalysis,
5197 dwritetextlayout_sink_SetLineBreakpoints,
5198 dwritetextlayout_sink_SetBidiLevel,
5199 dwritetextlayout_sink_SetNumberSubstitution,
5200 dwritetextlayout_sink_SetGlyphOrientation
5203 static HRESULT WINAPI dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource1 *iface,
5204 REFIID riid, void **obj)
5206 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource1) ||
5207 IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) ||
5208 IsEqualIID(riid, &IID_IUnknown))
5210 *obj = iface;
5211 IDWriteTextAnalysisSource1_AddRef(iface);
5212 return S_OK;
5215 WARN("%s not implemented.\n", debugstr_guid(riid));
5217 *obj = NULL;
5218 return E_NOINTERFACE;
5221 static ULONG WINAPI dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource1 *iface)
5223 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5224 return IDWriteTextLayout4_AddRef(&layout->IDWriteTextLayout4_iface);
5227 static ULONG WINAPI dwritetextlayout_source_Release(IDWriteTextAnalysisSource1 *iface)
5229 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5230 return IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
5233 static HRESULT WINAPI dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource1 *iface,
5234 UINT32 position, WCHAR const** text, UINT32* text_len)
5236 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5238 TRACE("%p, %u, %p, %p.\n", iface, position, text, text_len);
5240 if (position < layout->len) {
5241 *text = &layout->str[position];
5242 *text_len = layout->len - position;
5244 else {
5245 *text = NULL;
5246 *text_len = 0;
5249 return S_OK;
5252 static HRESULT WINAPI dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource1 *iface,
5253 UINT32 position, WCHAR const** text, UINT32* text_len)
5255 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5257 TRACE("%p, %u, %p, %p.\n", iface, position, text, text_len);
5259 if (position > 0 && position < layout->len) {
5260 *text = layout->str;
5261 *text_len = position;
5263 else {
5264 *text = NULL;
5265 *text_len = 0;
5268 return S_OK;
5271 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource1 *iface)
5273 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5274 return IDWriteTextLayout4_GetReadingDirection(&layout->IDWriteTextLayout4_iface);
5277 static HRESULT WINAPI dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource1 *iface,
5278 UINT32 position, UINT32* text_len, WCHAR const** locale)
5280 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5281 struct layout_range *range = get_layout_range_by_pos(layout, position);
5283 if (position < layout->len) {
5284 struct layout_range *next;
5286 *locale = range->locale;
5287 *text_len = range->h.range.length - position;
5289 next = LIST_ENTRY(list_next(&layout->ranges, &range->h.entry), struct layout_range, h.entry);
5290 while (next && next->h.range.startPosition < layout->len && !wcscmp(range->locale, next->locale))
5292 *text_len += next->h.range.length;
5293 next = LIST_ENTRY(list_next(&layout->ranges, &next->h.entry), struct layout_range, h.entry);
5296 *text_len = min(*text_len, layout->len - position);
5298 else {
5299 *locale = NULL;
5300 *text_len = 0;
5303 return S_OK;
5306 static HRESULT WINAPI dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource1 *iface,
5307 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
5309 FIXME("%u %p %p: stub\n", position, text_len, substitution);
5310 return E_NOTIMPL;
5313 static HRESULT WINAPI dwritetextlayout_source_GetVerticalGlyphOrientation(IDWriteTextAnalysisSource1 *iface,
5314 UINT32 position, UINT32 *length, DWRITE_VERTICAL_GLYPH_ORIENTATION *orientation, UINT8 *bidi_level)
5316 FIXME("%u %p %p %p: stub\n", position, length, orientation, bidi_level);
5317 return E_NOTIMPL;
5320 static const IDWriteTextAnalysisSource1Vtbl dwritetextlayoutsourcevtbl = {
5321 dwritetextlayout_source_QueryInterface,
5322 dwritetextlayout_source_AddRef,
5323 dwritetextlayout_source_Release,
5324 dwritetextlayout_source_GetTextAtPosition,
5325 dwritetextlayout_source_GetTextBeforePosition,
5326 dwritetextlayout_source_GetParagraphReadingDirection,
5327 dwritetextlayout_source_GetLocaleName,
5328 dwritetextlayout_source_GetNumberSubstitution,
5329 dwritetextlayout_source_GetVerticalGlyphOrientation
5332 static HRESULT layout_format_from_textformat(struct dwrite_textlayout *layout, IDWriteTextFormat *format)
5334 struct dwrite_textformat *textformat;
5335 IDWriteTextFormat1 *format1;
5336 IDWriteTextFormat3 *format3;
5337 UINT32 len;
5338 HRESULT hr;
5340 if ((textformat = unsafe_impl_from_IDWriteTextFormat(format))) {
5341 layout->format = textformat->format;
5343 layout->format.locale = heap_strdupW(textformat->format.locale);
5344 layout->format.family_name = heap_strdupW(textformat->format.family_name);
5345 if (!layout->format.locale || !layout->format.family_name)
5347 heap_free(layout->format.locale);
5348 heap_free(layout->format.family_name);
5349 return E_OUTOFMEMORY;
5352 if (layout->format.trimmingsign)
5353 IDWriteInlineObject_AddRef(layout->format.trimmingsign);
5354 if (layout->format.collection)
5355 IDWriteFontCollection_AddRef(layout->format.collection);
5356 if (layout->format.fallback)
5357 IDWriteFontFallback_AddRef(layout->format.fallback);
5359 return S_OK;
5362 layout->format.weight = IDWriteTextFormat_GetFontWeight(format);
5363 layout->format.style = IDWriteTextFormat_GetFontStyle(format);
5364 layout->format.stretch = IDWriteTextFormat_GetFontStretch(format);
5365 layout->format.fontsize= IDWriteTextFormat_GetFontSize(format);
5366 layout->format.tabstop = IDWriteTextFormat_GetIncrementalTabStop(format);
5367 layout->format.textalignment = IDWriteTextFormat_GetTextAlignment(format);
5368 layout->format.paralign = IDWriteTextFormat_GetParagraphAlignment(format);
5369 layout->format.wrapping = IDWriteTextFormat_GetWordWrapping(format);
5370 layout->format.readingdir = IDWriteTextFormat_GetReadingDirection(format);
5371 layout->format.flow = IDWriteTextFormat_GetFlowDirection(format);
5372 hr = IDWriteTextFormat_GetLineSpacing(format, &layout->format.spacing.method,
5373 &layout->format.spacing.height, &layout->format.spacing.baseline);
5374 if (FAILED(hr))
5375 return hr;
5377 hr = IDWriteTextFormat_GetTrimming(format, &layout->format.trimming, &layout->format.trimmingsign);
5378 if (FAILED(hr))
5379 return hr;
5381 /* locale name and length */
5382 len = IDWriteTextFormat_GetLocaleNameLength(format);
5383 layout->format.locale = heap_alloc((len+1)*sizeof(WCHAR));
5384 if (!layout->format.locale)
5385 return E_OUTOFMEMORY;
5387 hr = IDWriteTextFormat_GetLocaleName(format, layout->format.locale, len+1);
5388 if (FAILED(hr))
5389 return hr;
5390 layout->format.locale_len = len;
5392 /* font family name and length */
5393 len = IDWriteTextFormat_GetFontFamilyNameLength(format);
5394 layout->format.family_name = heap_alloc((len+1)*sizeof(WCHAR));
5395 if (!layout->format.family_name)
5396 return E_OUTOFMEMORY;
5398 hr = IDWriteTextFormat_GetFontFamilyName(format, layout->format.family_name, len+1);
5399 if (FAILED(hr))
5400 return hr;
5401 layout->format.family_len = len;
5403 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
5404 if (hr == S_OK)
5406 IDWriteTextFormat2 *format2;
5408 layout->format.vertical_orientation = IDWriteTextFormat1_GetVerticalGlyphOrientation(format1);
5409 layout->format.optical_alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
5410 IDWriteTextFormat1_GetFontFallback(format1, &layout->format.fallback);
5412 if (IDWriteTextFormat1_QueryInterface(format1, &IID_IDWriteTextFormat2, (void**)&format2) == S_OK) {
5413 IDWriteTextFormat2_GetLineSpacing(format2, &layout->format.spacing);
5414 IDWriteTextFormat2_Release(format2);
5417 IDWriteTextFormat1_Release(format1);
5420 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat3, (void **)&format3);
5421 if (hr == S_OK)
5423 layout->format.automatic_axes = IDWriteTextFormat3_GetAutomaticFontAxes(format3);
5424 IDWriteTextFormat3_Release(format3);
5427 return IDWriteTextFormat_GetFontCollection(format, &layout->format.collection);
5430 static HRESULT init_textlayout(const struct textlayout_desc *desc, struct dwrite_textlayout *layout)
5432 struct layout_range_header *range, *strike, *underline, *effect, *spacing, *typography;
5433 static const DWRITE_TEXT_RANGE r = { 0, ~0u };
5434 HRESULT hr;
5436 layout->IDWriteTextLayout4_iface.lpVtbl = &dwritetextlayoutvtbl;
5437 layout->IDWriteTextFormat3_iface.lpVtbl = &dwritetextformat3_layout_vtbl;
5438 layout->IDWriteTextAnalysisSink1_iface.lpVtbl = &dwritetextlayoutsinkvtbl;
5439 layout->IDWriteTextAnalysisSource1_iface.lpVtbl = &dwritetextlayoutsourcevtbl;
5440 layout->refcount = 1;
5441 layout->len = desc->length;
5442 layout->recompute = RECOMPUTE_EVERYTHING;
5443 list_init(&layout->eruns);
5444 list_init(&layout->inlineobjects);
5445 list_init(&layout->underlines);
5446 list_init(&layout->strikethrough);
5447 list_init(&layout->runs);
5448 list_init(&layout->ranges);
5449 list_init(&layout->strike_ranges);
5450 list_init(&layout->underline_ranges);
5451 list_init(&layout->effects);
5452 list_init(&layout->spacing);
5453 list_init(&layout->typographies);
5454 layout->metrics.layoutWidth = desc->max_width;
5455 layout->metrics.layoutHeight = desc->max_height;
5457 layout->str = heap_strdupnW(desc->string, desc->length);
5458 if (desc->length && !layout->str) {
5459 hr = E_OUTOFMEMORY;
5460 goto fail;
5463 hr = layout_format_from_textformat(layout, desc->format);
5464 if (FAILED(hr))
5465 goto fail;
5467 range = alloc_layout_range(layout, &r, LAYOUT_RANGE_REGULAR);
5468 strike = alloc_layout_range(layout, &r, LAYOUT_RANGE_STRIKETHROUGH);
5469 underline = alloc_layout_range(layout, &r, LAYOUT_RANGE_UNDERLINE);
5470 effect = alloc_layout_range(layout, &r, LAYOUT_RANGE_EFFECT);
5471 spacing = alloc_layout_range(layout, &r, LAYOUT_RANGE_SPACING);
5472 typography = alloc_layout_range(layout, &r, LAYOUT_RANGE_TYPOGRAPHY);
5473 if (!range || !strike || !effect || !spacing || !typography || !underline) {
5474 free_layout_range(range);
5475 free_layout_range(strike);
5476 free_layout_range(underline);
5477 free_layout_range(effect);
5478 free_layout_range(spacing);
5479 free_layout_range(typography);
5480 hr = E_OUTOFMEMORY;
5481 goto fail;
5484 layout->measuringmode = desc->is_gdi_compatible ? (desc->use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL :
5485 DWRITE_MEASURING_MODE_GDI_CLASSIC) : DWRITE_MEASURING_MODE_NATURAL;
5486 layout->ppdip = desc->ppdip;
5487 layout->transform = desc->transform ? *desc->transform : identity;
5489 layout->factory = desc->factory;
5490 IDWriteFactory7_AddRef(layout->factory);
5491 list_add_head(&layout->ranges, &range->entry);
5492 list_add_head(&layout->strike_ranges, &strike->entry);
5493 list_add_head(&layout->underline_ranges, &underline->entry);
5494 list_add_head(&layout->effects, &effect->entry);
5495 list_add_head(&layout->spacing, &spacing->entry);
5496 list_add_head(&layout->typographies, &typography->entry);
5497 return S_OK;
5499 fail:
5500 IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
5501 return hr;
5504 HRESULT create_textlayout(const struct textlayout_desc *desc, IDWriteTextLayout **layout)
5506 struct dwrite_textlayout *object;
5507 HRESULT hr;
5509 *layout = NULL;
5511 if (desc->max_width < 0.0f || desc->max_height < 0.0f)
5512 return E_INVALIDARG;
5514 if (!desc->format || !desc->string)
5515 return E_INVALIDARG;
5517 if (!(object = heap_alloc_zero(sizeof(*object))))
5518 return E_OUTOFMEMORY;
5520 hr = init_textlayout(desc, object);
5521 if (hr == S_OK)
5522 *layout = (IDWriteTextLayout *)&object->IDWriteTextLayout4_iface;
5524 return hr;
5527 static HRESULT WINAPI dwritetrimmingsign_QueryInterface(IDWriteInlineObject *iface, REFIID riid, void **obj)
5529 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5531 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteInlineObject)) {
5532 *obj = iface;
5533 IDWriteInlineObject_AddRef(iface);
5534 return S_OK;
5537 WARN("%s not implemented.\n", debugstr_guid(riid));
5539 *obj = NULL;
5540 return E_NOINTERFACE;
5543 static ULONG WINAPI dwritetrimmingsign_AddRef(IDWriteInlineObject *iface)
5545 struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
5546 ULONG refcount = InterlockedIncrement(&sign->refcount);
5548 TRACE("%p, refcount %d.\n", iface, refcount);
5550 return refcount;
5553 static ULONG WINAPI dwritetrimmingsign_Release(IDWriteInlineObject *iface)
5555 struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
5556 ULONG refcount = InterlockedDecrement(&sign->refcount);
5558 TRACE("%p, refcount %d.\n", iface, refcount);
5560 if (!refcount)
5562 IDWriteTextLayout_Release(sign->layout);
5563 heap_free(sign);
5566 return refcount;
5569 static HRESULT WINAPI dwritetrimmingsign_Draw(IDWriteInlineObject *iface, void *context, IDWriteTextRenderer *renderer,
5570 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *effect)
5572 struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
5573 DWRITE_LINE_METRICS line;
5574 UINT32 line_count;
5576 TRACE("%p, %p, %p, %.2f, %.2f, %d, %d, %p.\n", iface, context, renderer, originX, originY,
5577 is_sideways, is_rtl, effect);
5579 IDWriteTextLayout_GetLineMetrics(sign->layout, &line, 1, &line_count);
5580 return IDWriteTextLayout_Draw(sign->layout, context, renderer, originX, originY - line.baseline);
5583 static HRESULT WINAPI dwritetrimmingsign_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *ret)
5585 struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
5586 DWRITE_TEXT_METRICS metrics;
5587 HRESULT hr;
5589 TRACE("%p, %p.\n", iface, ret);
5591 hr = IDWriteTextLayout_GetMetrics(sign->layout, &metrics);
5592 if (FAILED(hr))
5594 memset(ret, 0, sizeof(*ret));
5595 return hr;
5598 ret->width = metrics.width;
5599 ret->height = 0.0f;
5600 ret->baseline = 0.0f;
5601 ret->supportsSideways = FALSE;
5602 return S_OK;
5605 static HRESULT WINAPI dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
5607 struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
5609 TRACE("%p, %p.\n", iface, overhangs);
5611 return IDWriteTextLayout_GetOverhangMetrics(sign->layout, overhangs);
5614 static HRESULT WINAPI dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
5615 DWRITE_BREAK_CONDITION *after)
5617 TRACE("%p, %p, %p.\n", iface, before, after);
5619 *before = *after = DWRITE_BREAK_CONDITION_NEUTRAL;
5620 return S_OK;
5623 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl =
5625 dwritetrimmingsign_QueryInterface,
5626 dwritetrimmingsign_AddRef,
5627 dwritetrimmingsign_Release,
5628 dwritetrimmingsign_Draw,
5629 dwritetrimmingsign_GetMetrics,
5630 dwritetrimmingsign_GetOverhangMetrics,
5631 dwritetrimmingsign_GetBreakConditions
5634 static inline BOOL is_reading_direction_horz(DWRITE_READING_DIRECTION direction)
5636 return (direction == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT) ||
5637 (direction == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
5640 static inline BOOL is_reading_direction_vert(DWRITE_READING_DIRECTION direction)
5642 return (direction == DWRITE_READING_DIRECTION_TOP_TO_BOTTOM) ||
5643 (direction == DWRITE_READING_DIRECTION_BOTTOM_TO_TOP);
5646 static inline BOOL is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction)
5648 return (direction == DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT) ||
5649 (direction == DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT);
5652 static inline BOOL is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction)
5654 return (direction == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM) ||
5655 (direction == DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP);
5658 HRESULT create_trimmingsign(IDWriteFactory7 *factory, IDWriteTextFormat *format, IDWriteInlineObject **sign)
5660 static const WCHAR ellipsisW = 0x2026;
5661 struct dwrite_trimmingsign *object;
5662 DWRITE_READING_DIRECTION reading;
5663 DWRITE_FLOW_DIRECTION flow;
5664 HRESULT hr;
5666 *sign = NULL;
5668 if (!format)
5669 return E_INVALIDARG;
5671 /* Validate reading/flow direction here, layout creation won't complain about
5672 invalid combinations. */
5673 reading = IDWriteTextFormat_GetReadingDirection(format);
5674 flow = IDWriteTextFormat_GetFlowDirection(format);
5676 if ((is_reading_direction_horz(reading) && is_flow_direction_horz(flow)) ||
5677 (is_reading_direction_vert(reading) && is_flow_direction_vert(flow)))
5678 return DWRITE_E_FLOWDIRECTIONCONFLICTS;
5680 if (!(object = heap_alloc(sizeof(*object))))
5681 return E_OUTOFMEMORY;
5683 object->IDWriteInlineObject_iface.lpVtbl = &dwritetrimmingsignvtbl;
5684 object->refcount = 1;
5686 hr = IDWriteFactory7_CreateTextLayout(factory, &ellipsisW, 1, format, 0.0f, 0.0f, &object->layout);
5687 if (FAILED(hr))
5689 heap_free(object);
5690 return hr;
5693 IDWriteTextLayout_SetWordWrapping(object->layout, DWRITE_WORD_WRAPPING_NO_WRAP);
5694 IDWriteTextLayout_SetParagraphAlignment(object->layout, DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
5695 IDWriteTextLayout_SetTextAlignment(object->layout, DWRITE_TEXT_ALIGNMENT_LEADING);
5697 *sign = &object->IDWriteInlineObject_iface;
5699 return S_OK;
5702 static HRESULT WINAPI dwritetextformat_QueryInterface(IDWriteTextFormat3 *iface, REFIID riid, void **obj)
5704 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5706 if (IsEqualIID(riid, &IID_IDWriteTextFormat3) ||
5707 IsEqualIID(riid, &IID_IDWriteTextFormat2) ||
5708 IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
5709 IsEqualIID(riid, &IID_IDWriteTextFormat) ||
5710 IsEqualIID(riid, &IID_IUnknown))
5712 *obj = iface;
5713 IDWriteTextFormat3_AddRef(iface);
5714 return S_OK;
5717 WARN("%s not implemented.\n", debugstr_guid(riid));
5719 *obj = NULL;
5721 return E_NOINTERFACE;
5724 static ULONG WINAPI dwritetextformat_AddRef(IDWriteTextFormat3 *iface)
5726 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5727 ULONG refcount = InterlockedIncrement(&format->refcount);
5729 TRACE("%p, refcount %d.\n", iface, refcount);
5731 return refcount;
5734 static ULONG WINAPI dwritetextformat_Release(IDWriteTextFormat3 *iface)
5736 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5737 ULONG refcount = InterlockedDecrement(&format->refcount);
5739 TRACE("%p, refcount %d.\n", iface, refcount);
5741 if (!refcount)
5743 release_format_data(&format->format);
5744 heap_free(format);
5747 return refcount;
5750 static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat3 *iface, DWRITE_TEXT_ALIGNMENT alignment)
5752 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5754 TRACE("%p, %d.\n", iface, alignment);
5756 return format_set_textalignment(&format->format, alignment, NULL);
5759 static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat3 *iface,
5760 DWRITE_PARAGRAPH_ALIGNMENT alignment)
5762 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5764 TRACE("%p, %d.\n", iface, alignment);
5766 return format_set_paralignment(&format->format, alignment, NULL);
5769 static HRESULT WINAPI dwritetextformat_SetWordWrapping(IDWriteTextFormat3 *iface, DWRITE_WORD_WRAPPING wrapping)
5771 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5773 TRACE("%p, %d.\n", iface, wrapping);
5775 return format_set_wordwrapping(&format->format, wrapping, NULL);
5778 static HRESULT WINAPI dwritetextformat_SetReadingDirection(IDWriteTextFormat3 *iface, DWRITE_READING_DIRECTION direction)
5780 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5782 TRACE("%p, %d.\n", iface, direction);
5784 return format_set_readingdirection(&format->format, direction, NULL);
5787 static HRESULT WINAPI dwritetextformat_SetFlowDirection(IDWriteTextFormat3 *iface, DWRITE_FLOW_DIRECTION direction)
5789 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5791 TRACE("%p, %d.\n", iface, direction);
5793 return format_set_flowdirection(&format->format, direction, NULL);
5796 static HRESULT WINAPI dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat3 *iface, FLOAT tabstop)
5798 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5800 TRACE("%p, %f.\n", iface, tabstop);
5802 if (tabstop <= 0.0f)
5803 return E_INVALIDARG;
5805 format->format.tabstop = tabstop;
5806 return S_OK;
5809 static HRESULT WINAPI dwritetextformat_SetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING const *trimming,
5810 IDWriteInlineObject *trimming_sign)
5812 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5814 TRACE("%p, %p, %p.\n", iface, trimming, trimming_sign);
5816 return format_set_trimming(&format->format, trimming, trimming_sign, NULL);
5819 static HRESULT WINAPI dwritetextformat_SetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING_METHOD method,
5820 FLOAT height, FLOAT baseline)
5822 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5823 DWRITE_LINE_SPACING spacing;
5825 TRACE("%p, %d, %f, %f.\n", iface, method, height, baseline);
5827 spacing = format->format.spacing;
5828 spacing.method = method;
5829 spacing.height = height;
5830 spacing.baseline = baseline;
5832 return format_set_linespacing(&format->format, &spacing, NULL);
5835 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_GetTextAlignment(IDWriteTextFormat3 *iface)
5837 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5839 TRACE("%p.\n", iface);
5841 return format->format.textalignment;
5844 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_GetParagraphAlignment(IDWriteTextFormat3 *iface)
5846 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5848 TRACE("%p.\n", iface);
5850 return format->format.paralign;
5853 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_GetWordWrapping(IDWriteTextFormat3 *iface)
5855 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5857 TRACE("%p.\n", iface);
5859 return format->format.wrapping;
5862 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_GetReadingDirection(IDWriteTextFormat3 *iface)
5864 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5866 TRACE("%p.\n", iface);
5868 return format->format.readingdir;
5871 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_GetFlowDirection(IDWriteTextFormat3 *iface)
5873 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5875 TRACE("%p.\n", iface);
5877 return format->format.flow;
5880 static FLOAT WINAPI dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat3 *iface)
5882 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5884 TRACE("%p.\n", iface);
5886 return format->format.tabstop;
5889 static HRESULT WINAPI dwritetextformat_GetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING *options,
5890 IDWriteInlineObject **trimming_sign)
5892 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5894 TRACE("%p, %p, %p.\n", iface, options, trimming_sign);
5896 *options = format->format.trimming;
5897 if ((*trimming_sign = format->format.trimmingsign))
5898 IDWriteInlineObject_AddRef(*trimming_sign);
5900 return S_OK;
5903 static HRESULT WINAPI dwritetextformat_GetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING_METHOD *method,
5904 FLOAT *spacing, FLOAT *baseline)
5906 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5908 TRACE("%p, %p, %p, %p.\n", iface, method, spacing, baseline);
5910 *method = format->format.spacing.method;
5911 *spacing = format->format.spacing.height;
5912 *baseline = format->format.spacing.baseline;
5913 return S_OK;
5916 static HRESULT WINAPI dwritetextformat_GetFontCollection(IDWriteTextFormat3 *iface, IDWriteFontCollection **collection)
5918 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5920 TRACE("%p, %p.\n", iface, collection);
5922 *collection = format->format.collection;
5923 IDWriteFontCollection_AddRef(*collection);
5925 return S_OK;
5928 static UINT32 WINAPI dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat3 *iface)
5930 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5932 TRACE("%p.\n", iface);
5934 return format->format.family_len;
5937 static HRESULT WINAPI dwritetextformat_GetFontFamilyName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
5939 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5941 TRACE("%p, %p, %u.\n", iface, name, size);
5943 if (size <= format->format.family_len)
5944 return E_NOT_SUFFICIENT_BUFFER;
5945 wcscpy(name, format->format.family_name);
5946 return S_OK;
5949 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_GetFontWeight(IDWriteTextFormat3 *iface)
5951 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5953 TRACE("%p.\n", iface);
5955 return format->format.weight;
5958 static DWRITE_FONT_STYLE WINAPI dwritetextformat_GetFontStyle(IDWriteTextFormat3 *iface)
5960 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5962 TRACE("%p.\n", iface);
5964 return format->format.style;
5967 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_GetFontStretch(IDWriteTextFormat3 *iface)
5969 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5971 TRACE("%p.\n", iface);
5973 return format->format.stretch;
5976 static FLOAT WINAPI dwritetextformat_GetFontSize(IDWriteTextFormat3 *iface)
5978 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5980 TRACE("%p.\n", iface);
5982 return format->format.fontsize;
5985 static UINT32 WINAPI dwritetextformat_GetLocaleNameLength(IDWriteTextFormat3 *iface)
5987 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5989 TRACE("%p.\n", iface);
5991 return format->format.locale_len;
5994 static HRESULT WINAPI dwritetextformat_GetLocaleName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
5996 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5998 TRACE("%p, %p %u.\n", iface, name, size);
6000 if (size <= format->format.locale_len)
6001 return E_NOT_SUFFICIENT_BUFFER;
6002 wcscpy(name, format->format.locale);
6003 return S_OK;
6006 static HRESULT WINAPI dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat3 *iface,
6007 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
6009 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6011 TRACE("%p, %d.\n", iface, orientation);
6013 return format_set_vertical_orientation(&format->format, orientation, NULL);
6016 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat3 *iface)
6018 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6020 TRACE("%p.\n", iface);
6022 return format->format.vertical_orientation;
6025 static HRESULT WINAPI dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat3 *iface, BOOL lastline_wrapping_enabled)
6027 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6029 TRACE("%p, %d.\n", iface, lastline_wrapping_enabled);
6031 format->format.last_line_wrapping = !!lastline_wrapping_enabled;
6032 return S_OK;
6035 static BOOL WINAPI dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat3 *iface)
6037 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6039 TRACE("%p.\n", iface);
6041 return format->format.last_line_wrapping;
6044 static HRESULT WINAPI dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat3 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
6046 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6048 TRACE("%p, %d.\n", iface, alignment);
6050 return format_set_optical_alignment(&format->format, alignment);
6053 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat3 *iface)
6055 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6057 TRACE("%p.\n", iface);
6059 return format->format.optical_alignment;
6062 static HRESULT WINAPI dwritetextformat1_SetFontFallback(IDWriteTextFormat3 *iface, IDWriteFontFallback *fallback)
6064 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6066 TRACE("%p, %p.\n", iface, fallback);
6068 return set_fontfallback_for_format(&format->format, fallback);
6071 static HRESULT WINAPI dwritetextformat1_GetFontFallback(IDWriteTextFormat3 *iface, IDWriteFontFallback **fallback)
6073 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6075 TRACE("%p, %p.\n", iface, fallback);
6077 return get_fontfallback_from_format(&format->format, fallback);
6080 static HRESULT WINAPI dwritetextformat2_SetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING const *spacing)
6082 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6084 TRACE("%p, %p.\n", iface, spacing);
6086 return format_set_linespacing(&format->format, spacing, NULL);
6089 static HRESULT WINAPI dwritetextformat2_GetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING *spacing)
6091 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6093 TRACE("%p, %p.\n", iface, spacing);
6095 *spacing = format->format.spacing;
6096 return S_OK;
6099 static HRESULT WINAPI dwritetextformat3_SetFontAxisValues(IDWriteTextFormat3 *iface,
6100 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values)
6102 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6104 TRACE("%p, %p, %u.\n", iface, axis_values, num_values);
6106 return format_set_font_axisvalues(&format->format, axis_values, num_values);
6109 static UINT32 WINAPI dwritetextformat3_GetFontAxisValueCount(IDWriteTextFormat3 *iface)
6111 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6113 TRACE("%p.\n", iface);
6115 return format->format.axis_values_count;
6118 static HRESULT WINAPI dwritetextformat3_GetFontAxisValues(IDWriteTextFormat3 *iface,
6119 DWRITE_FONT_AXIS_VALUE *axis_values, UINT32 num_values)
6121 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6123 TRACE("%p, %p, %u.\n", iface, axis_values, num_values);
6125 return format_get_font_axisvalues(&format->format, axis_values, num_values);
6128 static DWRITE_AUTOMATIC_FONT_AXES WINAPI dwritetextformat3_GetAutomaticFontAxes(IDWriteTextFormat3 *iface)
6130 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6132 TRACE("%p.\n", iface);
6134 return format->format.automatic_axes;
6137 static HRESULT WINAPI dwritetextformat3_SetAutomaticFontAxes(IDWriteTextFormat3 *iface, DWRITE_AUTOMATIC_FONT_AXES axes)
6139 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
6141 TRACE("%p, %d.\n", iface, axes);
6143 format->format.automatic_axes = axes;
6145 return S_OK;
6148 static const IDWriteTextFormat3Vtbl dwritetextformatvtbl =
6150 dwritetextformat_QueryInterface,
6151 dwritetextformat_AddRef,
6152 dwritetextformat_Release,
6153 dwritetextformat_SetTextAlignment,
6154 dwritetextformat_SetParagraphAlignment,
6155 dwritetextformat_SetWordWrapping,
6156 dwritetextformat_SetReadingDirection,
6157 dwritetextformat_SetFlowDirection,
6158 dwritetextformat_SetIncrementalTabStop,
6159 dwritetextformat_SetTrimming,
6160 dwritetextformat_SetLineSpacing,
6161 dwritetextformat_GetTextAlignment,
6162 dwritetextformat_GetParagraphAlignment,
6163 dwritetextformat_GetWordWrapping,
6164 dwritetextformat_GetReadingDirection,
6165 dwritetextformat_GetFlowDirection,
6166 dwritetextformat_GetIncrementalTabStop,
6167 dwritetextformat_GetTrimming,
6168 dwritetextformat_GetLineSpacing,
6169 dwritetextformat_GetFontCollection,
6170 dwritetextformat_GetFontFamilyNameLength,
6171 dwritetextformat_GetFontFamilyName,
6172 dwritetextformat_GetFontWeight,
6173 dwritetextformat_GetFontStyle,
6174 dwritetextformat_GetFontStretch,
6175 dwritetextformat_GetFontSize,
6176 dwritetextformat_GetLocaleNameLength,
6177 dwritetextformat_GetLocaleName,
6178 dwritetextformat1_SetVerticalGlyphOrientation,
6179 dwritetextformat1_GetVerticalGlyphOrientation,
6180 dwritetextformat1_SetLastLineWrapping,
6181 dwritetextformat1_GetLastLineWrapping,
6182 dwritetextformat1_SetOpticalAlignment,
6183 dwritetextformat1_GetOpticalAlignment,
6184 dwritetextformat1_SetFontFallback,
6185 dwritetextformat1_GetFontFallback,
6186 dwritetextformat2_SetLineSpacing,
6187 dwritetextformat2_GetLineSpacing,
6188 dwritetextformat3_SetFontAxisValues,
6189 dwritetextformat3_GetFontAxisValueCount,
6190 dwritetextformat3_GetFontAxisValues,
6191 dwritetextformat3_GetAutomaticFontAxes,
6192 dwritetextformat3_SetAutomaticFontAxes,
6195 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat *iface)
6197 return (iface->lpVtbl == (IDWriteTextFormatVtbl*)&dwritetextformatvtbl) ?
6198 CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat3_iface) : NULL;
6201 HRESULT create_textformat(const WCHAR *family_name, IDWriteFontCollection *collection, DWRITE_FONT_WEIGHT weight,
6202 DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, FLOAT size, const WCHAR *locale, IDWriteTextFormat **format)
6204 struct dwrite_textformat *object;
6206 *format = NULL;
6208 if (size <= 0.0f)
6209 return E_INVALIDARG;
6211 if (((UINT32)weight > DWRITE_FONT_WEIGHT_ULTRA_BLACK) ||
6212 ((UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED) ||
6213 ((UINT32)style > DWRITE_FONT_STYLE_ITALIC))
6214 return E_INVALIDARG;
6216 if (!(object = heap_alloc_zero(sizeof(*object))))
6217 return E_OUTOFMEMORY;
6219 object->IDWriteTextFormat3_iface.lpVtbl = &dwritetextformatvtbl;
6220 object->refcount = 1;
6221 object->format.family_name = heap_strdupW(family_name);
6222 object->format.family_len = wcslen(family_name);
6223 object->format.locale = heap_strdupW(locale);
6224 object->format.locale_len = wcslen(locale);
6225 /* Force locale name to lower case, layout will inherit this modified value. */
6226 wcslwr(object->format.locale);
6227 object->format.weight = weight;
6228 object->format.style = style;
6229 object->format.fontsize = size;
6230 object->format.tabstop = 4.0f * size;
6231 object->format.stretch = stretch;
6232 object->format.last_line_wrapping = TRUE;
6233 object->format.collection = collection;
6234 IDWriteFontCollection_AddRef(object->format.collection);
6236 *format = (IDWriteTextFormat *)&object->IDWriteTextFormat3_iface;
6238 return S_OK;
6241 static HRESULT WINAPI dwritetypography_QueryInterface(IDWriteTypography *iface, REFIID riid, void **obj)
6243 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6245 if (IsEqualIID(riid, &IID_IDWriteTypography) || IsEqualIID(riid, &IID_IUnknown)) {
6246 *obj = iface;
6247 IDWriteTypography_AddRef(iface);
6248 return S_OK;
6251 WARN("%s not implemented.\n", debugstr_guid(riid));
6253 *obj = NULL;
6255 return E_NOINTERFACE;
6258 static ULONG WINAPI dwritetypography_AddRef(IDWriteTypography *iface)
6260 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
6261 ULONG refcount = InterlockedIncrement(&typography->refcount);
6263 TRACE("%p, refcount %d.\n", iface, refcount);
6265 return refcount;
6268 static ULONG WINAPI dwritetypography_Release(IDWriteTypography *iface)
6270 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
6271 ULONG refcount = InterlockedDecrement(&typography->refcount);
6273 TRACE("%p, refcount %d.\n", iface, refcount);
6275 if (!refcount)
6277 heap_free(typography->features);
6278 heap_free(typography);
6281 return refcount;
6284 static HRESULT WINAPI dwritetypography_AddFontFeature(IDWriteTypography *iface, DWRITE_FONT_FEATURE feature)
6286 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
6288 TRACE("%p, %s, %u.\n", iface, debugstr_tag(feature.nameTag), feature.parameter);
6290 if (!dwrite_array_reserve((void **)&typography->features, &typography->capacity, typography->count + 1,
6291 sizeof(*typography->features)))
6293 return E_OUTOFMEMORY;
6296 typography->features[typography->count++] = feature;
6298 return S_OK;
6301 static UINT32 WINAPI dwritetypography_GetFontFeatureCount(IDWriteTypography *iface)
6303 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
6305 TRACE("%p.\n", iface);
6307 return typography->count;
6310 static HRESULT WINAPI dwritetypography_GetFontFeature(IDWriteTypography *iface, UINT32 index,
6311 DWRITE_FONT_FEATURE *feature)
6313 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
6315 TRACE("%p, %u, %p.\n", iface, index, feature);
6317 if (index >= typography->count)
6318 return E_INVALIDARG;
6320 *feature = typography->features[index];
6321 return S_OK;
6324 static const IDWriteTypographyVtbl dwritetypographyvtbl = {
6325 dwritetypography_QueryInterface,
6326 dwritetypography_AddRef,
6327 dwritetypography_Release,
6328 dwritetypography_AddFontFeature,
6329 dwritetypography_GetFontFeatureCount,
6330 dwritetypography_GetFontFeature
6333 HRESULT create_typography(IDWriteTypography **ret)
6335 struct dwrite_typography *typography;
6337 *ret = NULL;
6339 typography = heap_alloc_zero(sizeof(*typography));
6340 if (!typography)
6341 return E_OUTOFMEMORY;
6343 typography->IDWriteTypography_iface.lpVtbl = &dwritetypographyvtbl;
6344 typography->refcount = 1;
6346 *ret = &typography->IDWriteTypography_iface;
6348 return S_OK;