include: Make sure __int64 is correctly defined on PPC64.
[wine.git] / dlls / dwrite / layout.c
bloba24752c9bffeb2d39bf8d3e7b46328b2e60f3ef0
1 /*
2 * Text format and layout
4 * Copyright 2012, 2014-2017 Nikolay Sivov for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <math.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "dwrite_private.h"
31 #include "scripts.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
35 struct dwrite_textformat_data
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;
67 enum layout_range_attr_kind {
68 LAYOUT_RANGE_ATTR_WEIGHT,
69 LAYOUT_RANGE_ATTR_STYLE,
70 LAYOUT_RANGE_ATTR_STRETCH,
71 LAYOUT_RANGE_ATTR_FONTSIZE,
72 LAYOUT_RANGE_ATTR_EFFECT,
73 LAYOUT_RANGE_ATTR_INLINE,
74 LAYOUT_RANGE_ATTR_UNDERLINE,
75 LAYOUT_RANGE_ATTR_STRIKETHROUGH,
76 LAYOUT_RANGE_ATTR_PAIR_KERNING,
77 LAYOUT_RANGE_ATTR_FONTCOLL,
78 LAYOUT_RANGE_ATTR_LOCALE,
79 LAYOUT_RANGE_ATTR_FONTFAMILY,
80 LAYOUT_RANGE_ATTR_SPACING,
81 LAYOUT_RANGE_ATTR_TYPOGRAPHY
84 struct layout_range_attr_value {
85 DWRITE_TEXT_RANGE range;
86 union {
87 DWRITE_FONT_WEIGHT weight;
88 DWRITE_FONT_STYLE style;
89 DWRITE_FONT_STRETCH stretch;
90 FLOAT fontsize;
91 IDWriteInlineObject *object;
92 IUnknown *effect;
93 BOOL underline;
94 BOOL strikethrough;
95 BOOL pair_kerning;
96 IDWriteFontCollection *collection;
97 const WCHAR *locale;
98 const WCHAR *fontfamily;
99 struct {
100 FLOAT leading;
101 FLOAT trailing;
102 FLOAT min_advance;
103 } spacing;
104 IDWriteTypography *typography;
105 } u;
108 enum layout_range_kind {
109 LAYOUT_RANGE_REGULAR,
110 LAYOUT_RANGE_UNDERLINE,
111 LAYOUT_RANGE_STRIKETHROUGH,
112 LAYOUT_RANGE_EFFECT,
113 LAYOUT_RANGE_SPACING,
114 LAYOUT_RANGE_TYPOGRAPHY
117 struct layout_range_header {
118 struct list entry;
119 enum layout_range_kind kind;
120 DWRITE_TEXT_RANGE range;
123 struct layout_range {
124 struct layout_range_header h;
125 DWRITE_FONT_WEIGHT weight;
126 DWRITE_FONT_STYLE style;
127 FLOAT fontsize;
128 DWRITE_FONT_STRETCH stretch;
129 IDWriteInlineObject *object;
130 BOOL pair_kerning;
131 IDWriteFontCollection *collection;
132 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
133 WCHAR *fontfamily;
136 struct layout_range_bool {
137 struct layout_range_header h;
138 BOOL value;
141 struct layout_range_iface {
142 struct layout_range_header h;
143 IUnknown *iface;
146 struct layout_range_spacing {
147 struct layout_range_header h;
148 FLOAT leading;
149 FLOAT trailing;
150 FLOAT min_advance;
153 enum layout_run_kind {
154 LAYOUT_RUN_REGULAR,
155 LAYOUT_RUN_INLINE
158 struct inline_object_run {
159 IDWriteInlineObject *object;
160 UINT16 length;
163 struct regular_layout_run {
164 DWRITE_GLYPH_RUN_DESCRIPTION descr;
165 DWRITE_GLYPH_RUN run;
166 DWRITE_SCRIPT_ANALYSIS sa;
167 UINT16 *glyphs;
168 UINT16 *clustermap;
169 FLOAT *advances;
170 DWRITE_GLYPH_OFFSET *offsets;
171 UINT32 glyphcount; /* actual glyph count after shaping, not necessarily the same as reported to Draw() */
174 struct layout_run
176 struct list entry;
177 enum layout_run_kind kind;
178 union
180 struct inline_object_run object;
181 struct regular_layout_run regular;
182 } u;
183 float baseline;
184 float height;
185 unsigned int start_position; /* run text position in range [0, layout-text-length) */
188 struct layout_effective_run {
189 struct list entry;
190 const struct layout_run *run; /* nominal run this one is based on */
191 UINT32 start; /* relative text position, 0 means first text position of a nominal run */
192 UINT32 length; /* length in codepoints that this run covers */
193 UINT32 glyphcount; /* total glyph count in this run */
194 IUnknown *effect; /* original reference is kept only at range level */
195 D2D1_POINT_2F origin; /* baseline origin */
196 FLOAT align_dx; /* adjustment from text alignment */
197 FLOAT width; /* run width */
198 UINT16 *clustermap; /* effective clustermap, allocated separately, is not reused from nominal map */
199 UINT32 line; /* 0-based line index in line metrics array */
200 BOOL underlined; /* set if this run is underlined */
201 D2D1_RECT_F bbox; /* ink run box, top == bottom means it wasn't estimated yet */
204 struct layout_effective_inline {
205 struct list entry;
206 IDWriteInlineObject *object; /* inline object, set explicitly or added when trimming a line */
207 IUnknown *effect; /* original reference is kept only at range level */
208 FLOAT baseline;
209 D2D1_POINT_2F origin; /* left top corner */
210 FLOAT align_dx; /* adjustment from text alignment */
211 FLOAT width; /* object width as it's reported it */
212 BOOL is_sideways; /* vertical flow direction flag passed to Draw */
213 BOOL is_rtl; /* bidi flag passed to Draw */
214 UINT32 line; /* 0-based line index in line metrics array */
217 struct layout_underline {
218 struct list entry;
219 const struct layout_effective_run *run;
220 DWRITE_UNDERLINE u;
223 struct layout_strikethrough {
224 struct list entry;
225 const struct layout_effective_run *run;
226 DWRITE_STRIKETHROUGH s;
229 struct layout_cluster {
230 const struct layout_run *run; /* link to nominal run this cluster belongs to */
231 UINT32 position; /* relative to run, first cluster has 0 position */
234 struct layout_line
236 float height; /* height based on content */
237 float baseline; /* baseline based on content */
238 DWRITE_LINE_METRICS1 metrics;
241 enum layout_recompute_mask {
242 RECOMPUTE_CLUSTERS = 1 << 0,
243 RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
244 RECOMPUTE_LINES = 1 << 2,
245 RECOMPUTE_OVERHANGS = 1 << 3,
246 RECOMPUTE_LINES_AND_OVERHANGS = RECOMPUTE_LINES | RECOMPUTE_OVERHANGS,
247 RECOMPUTE_EVERYTHING = 0xffff
250 struct dwrite_textlayout
252 IDWriteTextLayout4 IDWriteTextLayout4_iface;
253 IDWriteTextFormat3 IDWriteTextFormat3_iface;
254 IDWriteTextAnalysisSink1 IDWriteTextAnalysisSink1_iface;
255 IDWriteTextAnalysisSource1 IDWriteTextAnalysisSource1_iface;
256 LONG refcount;
258 IDWriteFactory7 *factory;
260 WCHAR *str;
261 UINT32 len;
262 struct dwrite_textformat_data format;
263 struct list strike_ranges;
264 struct list underline_ranges;
265 struct list typographies;
266 struct list effects;
267 struct list spacing;
268 struct list ranges;
269 struct list runs;
270 /* lists ready to use by Draw() */
271 struct list eruns;
272 struct list inlineobjects;
273 struct list underlines;
274 struct list strikethrough;
275 USHORT recompute;
277 DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
278 DWRITE_LINE_BREAKPOINT *actual_breakpoints;
280 struct layout_cluster *clusters;
281 DWRITE_CLUSTER_METRICS *clustermetrics;
282 UINT32 cluster_count;
283 FLOAT minwidth;
285 struct layout_line *lines;
286 size_t lines_size;
288 DWRITE_TEXT_METRICS1 metrics;
289 DWRITE_OVERHANG_METRICS overhangs;
291 DWRITE_MEASURING_MODE measuringmode;
293 /* gdi-compatible layout specifics */
294 FLOAT ppdip;
295 DWRITE_MATRIX transform;
298 struct dwrite_textformat
300 IDWriteTextFormat3 IDWriteTextFormat3_iface;
301 LONG refcount;
302 struct dwrite_textformat_data format;
305 struct dwrite_trimmingsign
307 IDWriteInlineObject IDWriteInlineObject_iface;
308 LONG refcount;
310 IDWriteTextLayout *layout;
313 struct dwrite_typography {
314 IDWriteTypography IDWriteTypography_iface;
315 LONG refcount;
317 DWRITE_FONT_FEATURE *features;
318 size_t capacity;
319 size_t count;
322 static const IDWriteTextFormat3Vtbl dwritetextformatvtbl;
324 static void release_format_data(struct dwrite_textformat_data *data)
326 if (data->collection) IDWriteFontCollection_Release(data->collection);
327 if (data->fallback) IDWriteFontFallback_Release(data->fallback);
328 if (data->trimmingsign) IDWriteInlineObject_Release(data->trimmingsign);
329 heap_free(data->family_name);
330 heap_free(data->locale);
333 static inline struct dwrite_textlayout *impl_from_IDWriteTextLayout4(IDWriteTextLayout4 *iface)
335 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextLayout4_iface);
338 static inline struct dwrite_textlayout *impl_layout_from_IDWriteTextFormat3(IDWriteTextFormat3 *iface)
340 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextFormat3_iface);
343 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSink1(IDWriteTextAnalysisSink1 *iface)
345 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSink1_iface);
348 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSource1(IDWriteTextAnalysisSource1 *iface)
350 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSource1_iface);
353 static inline struct dwrite_textformat *impl_from_IDWriteTextFormat3(IDWriteTextFormat3 *iface)
355 return CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat3_iface);
358 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat*);
360 static inline struct dwrite_trimmingsign *impl_from_IDWriteInlineObject(IDWriteInlineObject *iface)
362 return CONTAINING_RECORD(iface, struct dwrite_trimmingsign, IDWriteInlineObject_iface);
365 static inline struct dwrite_typography *impl_from_IDWriteTypography(IDWriteTypography *iface)
367 return CONTAINING_RECORD(iface, struct dwrite_typography, IDWriteTypography_iface);
370 static inline const char *debugstr_rundescr(const DWRITE_GLYPH_RUN_DESCRIPTION *descr)
372 return wine_dbg_sprintf("[%u,%u)", descr->textPosition, descr->textPosition + descr->stringLength);
375 static inline BOOL is_layout_gdi_compatible(struct dwrite_textlayout *layout)
377 return layout->measuringmode != DWRITE_MEASURING_MODE_NATURAL;
380 static inline HRESULT format_set_textalignment(struct dwrite_textformat_data *format, DWRITE_TEXT_ALIGNMENT alignment,
381 BOOL *changed)
383 if ((UINT32)alignment > DWRITE_TEXT_ALIGNMENT_JUSTIFIED)
384 return E_INVALIDARG;
385 if (changed) *changed = format->textalignment != alignment;
386 format->textalignment = alignment;
387 return S_OK;
390 static inline HRESULT format_set_paralignment(struct dwrite_textformat_data *format,
391 DWRITE_PARAGRAPH_ALIGNMENT alignment, BOOL *changed)
393 if ((UINT32)alignment > DWRITE_PARAGRAPH_ALIGNMENT_CENTER)
394 return E_INVALIDARG;
395 if (changed) *changed = format->paralign != alignment;
396 format->paralign = alignment;
397 return S_OK;
400 static inline HRESULT format_set_readingdirection(struct dwrite_textformat_data *format,
401 DWRITE_READING_DIRECTION direction, BOOL *changed)
403 if ((UINT32)direction > DWRITE_READING_DIRECTION_BOTTOM_TO_TOP)
404 return E_INVALIDARG;
405 if (changed) *changed = format->readingdir != direction;
406 format->readingdir = direction;
407 return S_OK;
410 static inline HRESULT format_set_wordwrapping(struct dwrite_textformat_data *format,
411 DWRITE_WORD_WRAPPING wrapping, BOOL *changed)
413 if ((UINT32)wrapping > DWRITE_WORD_WRAPPING_CHARACTER)
414 return E_INVALIDARG;
415 if (changed) *changed = format->wrapping != wrapping;
416 format->wrapping = wrapping;
417 return S_OK;
420 static inline HRESULT format_set_flowdirection(struct dwrite_textformat_data *format,
421 DWRITE_FLOW_DIRECTION direction, BOOL *changed)
423 if ((UINT32)direction > DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT)
424 return E_INVALIDARG;
425 if (changed) *changed = format->flow != direction;
426 format->flow = direction;
427 return S_OK;
430 static inline HRESULT format_set_trimming(struct dwrite_textformat_data *format,
431 DWRITE_TRIMMING const *trimming, IDWriteInlineObject *trimming_sign, BOOL *changed)
433 if (changed)
434 *changed = FALSE;
436 if ((UINT32)trimming->granularity > DWRITE_TRIMMING_GRANULARITY_WORD)
437 return E_INVALIDARG;
439 if (changed) {
440 *changed = !!memcmp(&format->trimming, trimming, sizeof(*trimming));
441 if (format->trimmingsign != trimming_sign)
442 *changed = TRUE;
445 format->trimming = *trimming;
446 if (format->trimmingsign)
447 IDWriteInlineObject_Release(format->trimmingsign);
448 format->trimmingsign = trimming_sign;
449 if (format->trimmingsign)
450 IDWriteInlineObject_AddRef(format->trimmingsign);
451 return S_OK;
454 static inline HRESULT format_set_linespacing(struct dwrite_textformat_data *format,
455 DWRITE_LINE_SPACING const *spacing, BOOL *changed)
457 if (spacing->height < 0.0f || spacing->leadingBefore < 0.0f || spacing->leadingBefore > 1.0f ||
458 (UINT32)spacing->method > DWRITE_LINE_SPACING_METHOD_PROPORTIONAL)
459 return E_INVALIDARG;
461 if (changed)
462 *changed = memcmp(spacing, &format->spacing, sizeof(*spacing));
464 format->spacing = *spacing;
465 return S_OK;
468 static HRESULT get_fontfallback_from_format(const struct dwrite_textformat_data *format, IDWriteFontFallback **fallback)
470 *fallback = format->fallback;
471 if (*fallback)
472 IDWriteFontFallback_AddRef(*fallback);
473 return S_OK;
476 static HRESULT set_fontfallback_for_format(struct dwrite_textformat_data *format, IDWriteFontFallback *fallback)
478 if (format->fallback)
479 IDWriteFontFallback_Release(format->fallback);
480 format->fallback = fallback;
481 if (fallback)
482 IDWriteFontFallback_AddRef(fallback);
483 return S_OK;
486 static HRESULT format_set_optical_alignment(struct dwrite_textformat_data *format,
487 DWRITE_OPTICAL_ALIGNMENT alignment)
489 if ((UINT32)alignment > DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS)
490 return E_INVALIDARG;
491 format->optical_alignment = alignment;
492 return S_OK;
495 static HRESULT format_set_vertical_orientation(struct dwrite_textformat_data *format,
496 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation, BOOL *changed)
498 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
499 return E_INVALIDARG;
501 if (changed)
502 *changed = format->vertical_orientation != orientation;
504 format->vertical_orientation = orientation;
505 return S_OK;
508 static BOOL is_run_rtl(const struct layout_effective_run *run)
510 return run->run->u.regular.run.bidiLevel & 1;
513 static HRESULT alloc_layout_run(enum layout_run_kind kind, unsigned int start_position,
514 struct layout_run **run)
516 if (!(*run = heap_alloc_zero(sizeof(**run))))
517 return E_OUTOFMEMORY;
519 (*run)->kind = kind;
520 (*run)->start_position = start_position;
522 return S_OK;
525 static void free_layout_runs(struct dwrite_textlayout *layout)
527 struct layout_run *cur, *cur2;
528 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->runs, struct layout_run, entry) {
529 list_remove(&cur->entry);
530 if (cur->kind == LAYOUT_RUN_REGULAR) {
531 if (cur->u.regular.run.fontFace)
532 IDWriteFontFace_Release(cur->u.regular.run.fontFace);
533 heap_free(cur->u.regular.glyphs);
534 heap_free(cur->u.regular.clustermap);
535 heap_free(cur->u.regular.advances);
536 heap_free(cur->u.regular.offsets);
538 heap_free(cur);
542 static void free_layout_eruns(struct dwrite_textlayout *layout)
544 struct layout_effective_inline *in, *in2;
545 struct layout_effective_run *cur, *cur2;
546 struct layout_strikethrough *s, *s2;
547 struct layout_underline *u, *u2;
549 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->eruns, struct layout_effective_run, entry) {
550 list_remove(&cur->entry);
551 heap_free(cur->clustermap);
552 heap_free(cur);
555 LIST_FOR_EACH_ENTRY_SAFE(in, in2, &layout->inlineobjects, struct layout_effective_inline, entry) {
556 list_remove(&in->entry);
557 heap_free(in);
560 LIST_FOR_EACH_ENTRY_SAFE(u, u2, &layout->underlines, struct layout_underline, entry) {
561 list_remove(&u->entry);
562 heap_free(u);
565 LIST_FOR_EACH_ENTRY_SAFE(s, s2, &layout->strikethrough, struct layout_strikethrough, entry) {
566 list_remove(&s->entry);
567 heap_free(s);
571 /* Used to resolve break condition by forcing stronger condition over weaker. */
572 static inline DWRITE_BREAK_CONDITION override_break_condition(DWRITE_BREAK_CONDITION existingbreak, DWRITE_BREAK_CONDITION newbreak)
574 switch (existingbreak) {
575 case DWRITE_BREAK_CONDITION_NEUTRAL:
576 return newbreak;
577 case DWRITE_BREAK_CONDITION_CAN_BREAK:
578 return newbreak == DWRITE_BREAK_CONDITION_NEUTRAL ? existingbreak : newbreak;
579 /* let's keep stronger conditions as is */
580 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK:
581 case DWRITE_BREAK_CONDITION_MUST_BREAK:
582 break;
583 default:
584 ERR("unknown break condition %d\n", existingbreak);
587 return existingbreak;
590 /* This helper should be used to get effective range length, in other words it returns number of text
591 positions from range starting point to the end of the range, limited by layout text length */
592 static inline UINT32 get_clipped_range_length(const struct dwrite_textlayout *layout, const struct layout_range *range)
594 if (range->h.range.startPosition + range->h.range.length <= layout->len)
595 return range->h.range.length;
596 return layout->len - range->h.range.startPosition;
599 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
600 static HRESULT layout_update_breakpoints_range(struct dwrite_textlayout *layout, const struct layout_range *cur)
602 DWRITE_BREAK_CONDITION before, after;
603 UINT32 i, length;
604 HRESULT hr;
606 /* ignore returned conditions if failed */
607 hr = IDWriteInlineObject_GetBreakConditions(cur->object, &before, &after);
608 if (FAILED(hr))
609 after = before = DWRITE_BREAK_CONDITION_NEUTRAL;
611 if (!layout->actual_breakpoints) {
612 layout->actual_breakpoints = heap_calloc(layout->len, sizeof(*layout->actual_breakpoints));
613 if (!layout->actual_breakpoints)
614 return E_OUTOFMEMORY;
615 memcpy(layout->actual_breakpoints, layout->nominal_breakpoints, sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
618 length = get_clipped_range_length(layout, cur);
619 for (i = cur->h.range.startPosition; i < length + cur->h.range.startPosition; i++) {
620 /* for first codepoint check if there's anything before it and update accordingly */
621 if (i == cur->h.range.startPosition) {
622 if (i > 0)
623 layout->actual_breakpoints[i].breakConditionBefore = layout->actual_breakpoints[i-1].breakConditionAfter =
624 override_break_condition(layout->actual_breakpoints[i-1].breakConditionAfter, before);
625 else
626 layout->actual_breakpoints[i].breakConditionBefore = before;
627 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
629 /* similar check for last codepoint */
630 else if (i == cur->h.range.startPosition + length - 1) {
631 if (i == layout->len - 1)
632 layout->actual_breakpoints[i].breakConditionAfter = after;
633 else
634 layout->actual_breakpoints[i].breakConditionAfter = layout->actual_breakpoints[i+1].breakConditionBefore =
635 override_break_condition(layout->actual_breakpoints[i+1].breakConditionBefore, after);
636 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
638 /* for all positions within a range disable breaks */
639 else {
640 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
641 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
644 layout->actual_breakpoints[i].isWhitespace = 0;
645 layout->actual_breakpoints[i].isSoftHyphen = 0;
648 return S_OK;
651 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos);
653 static inline DWRITE_LINE_BREAKPOINT get_effective_breakpoint(const struct dwrite_textlayout *layout, UINT32 pos)
655 if (layout->actual_breakpoints)
656 return layout->actual_breakpoints[pos];
657 return layout->nominal_breakpoints[pos];
660 static inline void init_cluster_metrics(const struct dwrite_textlayout *layout, const struct regular_layout_run *run,
661 UINT16 start_glyph, UINT16 stop_glyph, UINT32 stop_position, UINT16 length, DWRITE_CLUSTER_METRICS *metrics)
663 UINT8 breakcondition;
664 UINT32 position;
665 UINT16 j;
667 /* For clusters made of control chars we report zero glyphs, and we need zero cluster
668 width as well; advances are already computed at this point and are not necessary zero. */
669 metrics->width = 0.0f;
670 if (run->run.glyphCount) {
671 for (j = start_glyph; j < stop_glyph; j++)
672 metrics->width += run->run.glyphAdvances[j];
674 metrics->length = length;
676 position = run->descr.textPosition + stop_position;
677 if (stop_glyph == run->glyphcount)
678 breakcondition = get_effective_breakpoint(layout, position).breakConditionAfter;
679 else {
680 breakcondition = get_effective_breakpoint(layout, position).breakConditionBefore;
681 if (stop_position) position -= 1;
684 metrics->canWrapLineAfter = breakcondition == DWRITE_BREAK_CONDITION_CAN_BREAK ||
685 breakcondition == DWRITE_BREAK_CONDITION_MUST_BREAK;
686 if (metrics->length == 1) {
687 DWRITE_LINE_BREAKPOINT bp = get_effective_breakpoint(layout, position);
688 metrics->isWhitespace = bp.isWhitespace;
689 metrics->isNewline = metrics->canWrapLineAfter && lb_is_newline_char(layout->str[position]);
690 metrics->isSoftHyphen = bp.isSoftHyphen;
692 else {
693 metrics->isWhitespace = 0;
694 metrics->isNewline = 0;
695 metrics->isSoftHyphen = 0;
697 metrics->isRightToLeft = run->run.bidiLevel & 1;
698 metrics->padding = 0;
703 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
704 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
705 Note that there's no need to reallocate anything at this point as we allocate one cluster per
706 codepoint initially.
709 static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 *cluster)
711 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[*cluster];
712 struct layout_cluster *c = &layout->clusters[*cluster];
713 const struct regular_layout_run *run = &r->u.regular;
714 UINT32 i, start = 0;
716 assert(r->kind == LAYOUT_RUN_REGULAR);
718 for (i = 0; i < run->descr.stringLength; i++) {
719 BOOL end = i == run->descr.stringLength - 1;
721 if (run->descr.clusterMap[start] != run->descr.clusterMap[i]) {
722 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->descr.clusterMap[i], i,
723 i - start, metrics);
724 c->position = start;
725 c->run = r;
727 *cluster += 1;
728 metrics++;
729 c++;
730 start = i;
733 if (end) {
734 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->glyphcount, i,
735 i - start + 1, metrics);
736 c->position = start;
737 c->run = r;
739 *cluster += 1;
740 return;
745 #define SCALE_FONT_METRIC(metric, emSize, metrics) ((FLOAT)(metric) * (emSize) / (FLOAT)(metrics)->designUnitsPerEm)
747 static void layout_get_font_metrics(struct dwrite_textlayout *layout, IDWriteFontFace *fontface, FLOAT emsize,
748 DWRITE_FONT_METRICS *fontmetrics)
750 if (is_layout_gdi_compatible(layout)) {
751 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(fontface, emsize, layout->ppdip, &layout->transform, fontmetrics);
752 if (FAILED(hr))
753 WARN("failed to get compat metrics, 0x%08x\n", hr);
755 else
756 IDWriteFontFace_GetMetrics(fontface, fontmetrics);
759 static void layout_get_font_height(FLOAT emsize, DWRITE_FONT_METRICS *fontmetrics, FLOAT *baseline, FLOAT *height)
761 *baseline = SCALE_FONT_METRIC(fontmetrics->ascent + fontmetrics->lineGap, emsize, fontmetrics);
762 *height = SCALE_FONT_METRIC(fontmetrics->ascent + fontmetrics->descent + fontmetrics->lineGap, emsize, fontmetrics);
765 static HRESULT layout_itemize(struct dwrite_textlayout *layout)
767 IDWriteTextAnalyzer *analyzer;
768 struct layout_range *range;
769 struct layout_run *r;
770 HRESULT hr = S_OK;
772 analyzer = get_text_analyzer();
774 LIST_FOR_EACH_ENTRY(range, &layout->ranges, struct layout_range, h.entry) {
775 /* We don't care about ranges that don't contain any text. */
776 if (range->h.range.startPosition >= layout->len)
777 break;
779 /* Inline objects override actual text in range. */
780 if (range->object) {
781 hr = layout_update_breakpoints_range(layout, range);
782 if (FAILED(hr))
783 return hr;
785 if (FAILED(hr = alloc_layout_run(LAYOUT_RUN_INLINE, range->h.range.startPosition, &r)))
786 return hr;
788 r->u.object.object = range->object;
789 r->u.object.length = get_clipped_range_length(layout, range);
790 list_add_tail(&layout->runs, &r->entry);
791 continue;
794 /* Initial splitting by script. */
795 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, (IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
796 range->h.range.startPosition, get_clipped_range_length(layout, range),
797 (IDWriteTextAnalysisSink *)&layout->IDWriteTextAnalysisSink1_iface);
798 if (FAILED(hr))
799 break;
801 /* Splitting further by bidi levels. */
802 hr = IDWriteTextAnalyzer_AnalyzeBidi(analyzer, (IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
803 range->h.range.startPosition, get_clipped_range_length(layout, range),
804 (IDWriteTextAnalysisSink *)&layout->IDWriteTextAnalysisSink1_iface);
805 if (FAILED(hr))
806 break;
809 return hr;
812 static HRESULT layout_resolve_fonts(struct dwrite_textlayout *layout)
814 IDWriteFontCollection *sys_collection;
815 IDWriteFontFallback *fallback = NULL;
816 struct layout_range *range;
817 struct layout_run *r;
818 HRESULT hr;
820 if (FAILED(hr = IDWriteFactory5_GetSystemFontCollection((IDWriteFactory5 *)layout->factory, FALSE,
821 (IDWriteFontCollection1 **)&sys_collection, FALSE))) {
822 WARN("Failed to get system collection, hr %#x.\n", hr);
823 return hr;
826 if (layout->format.fallback) {
827 fallback = layout->format.fallback;
828 IDWriteFontFallback_AddRef(fallback);
830 else {
831 if (FAILED(hr = IDWriteFactory7_GetSystemFontFallback(layout->factory, &fallback))) {
832 WARN("Failed to get system fallback, hr %#x.\n", hr);
833 goto fatal;
837 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
838 struct regular_layout_run *run = &r->u.regular;
839 IDWriteFont *font;
840 UINT32 length;
842 if (r->kind == LAYOUT_RUN_INLINE)
843 continue;
845 range = get_layout_range_by_pos(layout, run->descr.textPosition);
847 if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL) {
848 IDWriteFontCollection *collection;
850 collection = range->collection ? range->collection : sys_collection;
852 if (FAILED(hr = create_matching_font(collection, range->fontfamily, range->weight, range->style,
853 range->stretch, &font))) {
854 WARN("%s: failed to create matching font for non visual run, family %s, collection %p\n",
855 debugstr_rundescr(&run->descr), debugstr_w(range->fontfamily), range->collection);
856 break;
859 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
860 IDWriteFont_Release(font);
861 if (FAILED(hr)) {
862 WARN("Failed to create font face, hr %#x.\n", hr);
863 break;
866 run->run.fontEmSize = range->fontsize;
867 continue;
870 length = run->descr.stringLength;
872 while (length) {
873 UINT32 mapped_length;
874 FLOAT scale;
876 run = &r->u.regular;
878 hr = IDWriteFontFallback_MapCharacters(fallback,
879 (IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
880 run->descr.textPosition,
881 run->descr.stringLength,
882 range->collection,
883 range->fontfamily,
884 range->weight,
885 range->style,
886 range->stretch,
887 &mapped_length,
888 &font,
889 &scale);
890 if (FAILED(hr)) {
891 WARN("%s: failed to map family %s, collection %p, hr %#x.\n", debugstr_rundescr(&run->descr),
892 debugstr_w(range->fontfamily), range->collection, hr);
893 goto fatal;
896 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
897 IDWriteFont_Release(font);
898 if (FAILED(hr)) {
899 WARN("Failed to create font face, hr %#x.\n", hr);
900 goto fatal;
903 run->run.fontEmSize = range->fontsize * scale;
905 if (mapped_length < length)
907 struct regular_layout_run *nextrun;
908 struct layout_run *nextr;
910 /* keep mapped part for current run, add another run for the rest */
911 if (FAILED(hr = alloc_layout_run(LAYOUT_RUN_REGULAR, 0, &nextr)))
912 goto fatal;
914 *nextr = *r;
915 nextr->start_position = run->descr.textPosition + mapped_length;
916 nextrun = &nextr->u.regular;
917 nextrun->descr.textPosition = nextr->start_position;
918 nextrun->descr.stringLength = run->descr.stringLength - mapped_length;
919 nextrun->descr.string = &layout->str[nextrun->descr.textPosition];
920 run->descr.stringLength = mapped_length;
921 list_add_after(&r->entry, &nextr->entry);
922 r = nextr;
925 length -= mapped_length;
929 fatal:
930 IDWriteFontCollection_Release(sys_collection);
931 if (fallback)
932 IDWriteFontFallback_Release(fallback);
934 return hr;
937 static HRESULT layout_shape_run(struct dwrite_textlayout *layout, struct regular_layout_run *run)
939 DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props;
940 DWRITE_SHAPING_TEXT_PROPERTIES *text_props;
941 IDWriteTextAnalyzer *analyzer;
942 struct layout_range *range;
943 UINT32 max_count;
944 HRESULT hr;
946 range = get_layout_range_by_pos(layout, run->descr.textPosition);
947 run->descr.localeName = range->locale;
948 run->clustermap = heap_calloc(run->descr.stringLength, sizeof(*run->clustermap));
950 max_count = 3 * run->descr.stringLength / 2 + 16;
951 run->glyphs = heap_calloc(max_count, sizeof(*run->glyphs));
952 if (!run->clustermap || !run->glyphs)
953 return E_OUTOFMEMORY;
955 text_props = heap_calloc(run->descr.stringLength, sizeof(*text_props));
956 glyph_props = heap_calloc(max_count, sizeof(*glyph_props));
957 if (!text_props || !glyph_props) {
958 heap_free(text_props);
959 heap_free(glyph_props);
960 return E_OUTOFMEMORY;
963 analyzer = get_text_analyzer();
965 for (;;) {
966 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, run->descr.string, run->descr.stringLength, run->run.fontFace,
967 run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL /* FIXME */, NULL,
968 NULL, 0, max_count, run->clustermap, text_props, run->glyphs, glyph_props, &run->glyphcount);
969 if (hr == E_NOT_SUFFICIENT_BUFFER) {
970 heap_free(run->glyphs);
971 heap_free(glyph_props);
973 max_count = run->glyphcount;
975 run->glyphs = heap_calloc(max_count, sizeof(*run->glyphs));
976 glyph_props = heap_calloc(max_count, sizeof(*glyph_props));
977 if (!run->glyphs || !glyph_props) {
978 hr = E_OUTOFMEMORY;
979 break;
982 continue;
985 break;
988 if (FAILED(hr)) {
989 heap_free(text_props);
990 heap_free(glyph_props);
991 WARN("%s: shaping failed, hr %#x.\n", debugstr_rundescr(&run->descr), hr);
992 return hr;
995 run->run.glyphIndices = run->glyphs;
996 run->descr.clusterMap = run->clustermap;
998 run->advances = heap_calloc(run->glyphcount, sizeof(*run->advances));
999 run->offsets = heap_calloc(run->glyphcount, sizeof(*run->offsets));
1000 if (!run->advances || !run->offsets)
1001 return E_OUTOFMEMORY;
1003 /* Get advances and offsets. */
1004 if (is_layout_gdi_compatible(layout))
1005 hr = IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap,
1006 text_props, run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount,
1007 run->run.fontFace, run->run.fontEmSize, layout->ppdip, &layout->transform,
1008 layout->measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->run.isSideways, run->run.bidiLevel & 1,
1009 &run->sa, run->descr.localeName, NULL, NULL, 0, run->advances, run->offsets);
1010 else
1011 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap, text_props,
1012 run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount, run->run.fontFace,
1013 run->run.fontEmSize, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
1014 NULL, NULL, 0, run->advances, run->offsets);
1016 heap_free(text_props);
1017 heap_free(glyph_props);
1018 if (FAILED(hr)) {
1019 memset(run->advances, 0, run->glyphcount * sizeof(*run->advances));
1020 memset(run->offsets, 0, run->glyphcount * sizeof(*run->offsets));
1021 WARN("%s: failed to get glyph placement info, hr %#x.\n", debugstr_rundescr(&run->descr), hr);
1024 run->run.glyphAdvances = run->advances;
1025 run->run.glyphOffsets = run->offsets;
1027 /* Special treatment for runs that don't produce visual output, shaping code adds normal glyphs for them,
1028 with valid cluster map and potentially with non-zero advances; layout code exposes those as zero
1029 width clusters. */
1030 if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL)
1031 run->run.glyphCount = 0;
1032 else
1033 run->run.glyphCount = run->glyphcount;
1035 return S_OK;
1038 static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
1040 struct layout_run *r;
1041 UINT32 cluster = 0;
1042 HRESULT hr;
1044 free_layout_eruns(layout);
1045 free_layout_runs(layout);
1047 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
1048 if (!layout->clustermetrics && layout->len) {
1049 layout->clustermetrics = heap_calloc(layout->len, sizeof(*layout->clustermetrics));
1050 layout->clusters = heap_calloc(layout->len, sizeof(*layout->clusters));
1051 if (!layout->clustermetrics || !layout->clusters) {
1052 heap_free(layout->clustermetrics);
1053 heap_free(layout->clusters);
1054 return E_OUTOFMEMORY;
1057 layout->cluster_count = 0;
1059 if (FAILED(hr = layout_itemize(layout))) {
1060 WARN("Itemization failed, hr %#x.\n", hr);
1061 return hr;
1064 if (FAILED(hr = layout_resolve_fonts(layout))) {
1065 WARN("Failed to resolve layout fonts, hr %#x.\n", hr);
1066 return hr;
1069 /* fill run info */
1070 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
1071 struct regular_layout_run *run = &r->u.regular;
1072 DWRITE_FONT_METRICS fontmetrics = { 0 };
1074 /* we need to do very little in case of inline objects */
1075 if (r->kind == LAYOUT_RUN_INLINE) {
1076 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[cluster];
1077 struct layout_cluster *c = &layout->clusters[cluster];
1078 DWRITE_INLINE_OBJECT_METRICS inlinemetrics;
1080 metrics->width = 0.0f;
1081 metrics->length = r->u.object.length;
1082 metrics->canWrapLineAfter = 0;
1083 metrics->isWhitespace = 0;
1084 metrics->isNewline = 0;
1085 metrics->isSoftHyphen = 0;
1086 metrics->isRightToLeft = 0;
1087 metrics->padding = 0;
1088 c->run = r;
1089 c->position = 0; /* there's always one cluster per inline object, so 0 is valid value */
1090 cluster++;
1092 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
1093 hr = IDWriteInlineObject_GetMetrics(r->u.object.object, &inlinemetrics);
1094 if (FAILED(hr)) {
1095 memset(&inlinemetrics, 0, sizeof(inlinemetrics));
1096 hr = S_OK;
1098 metrics->width = inlinemetrics.width;
1099 r->baseline = inlinemetrics.baseline;
1100 r->height = inlinemetrics.height;
1102 /* FIXME: use resolved breakpoints in this case too */
1104 continue;
1107 if (FAILED(hr = layout_shape_run(layout, run)))
1108 WARN("%s: shaping failed, hr %#x.\n", debugstr_rundescr(&run->descr), hr);
1110 /* baseline derived from font metrics */
1111 layout_get_font_metrics(layout, run->run.fontFace, run->run.fontEmSize, &fontmetrics);
1112 layout_get_font_height(run->run.fontEmSize, &fontmetrics, &r->baseline, &r->height);
1114 layout_set_cluster_metrics(layout, r, &cluster);
1117 if (hr == S_OK) {
1118 layout->cluster_count = cluster;
1119 if (cluster)
1120 layout->clustermetrics[cluster-1].canWrapLineAfter = 1;
1123 return hr;
1126 static HRESULT layout_compute(struct dwrite_textlayout *layout)
1128 HRESULT hr;
1130 if (!(layout->recompute & RECOMPUTE_CLUSTERS))
1131 return S_OK;
1133 /* nominal breakpoints are evaluated only once, because string never changes */
1134 if (!layout->nominal_breakpoints) {
1135 IDWriteTextAnalyzer *analyzer;
1137 layout->nominal_breakpoints = heap_calloc(layout->len, sizeof(*layout->nominal_breakpoints));
1138 if (!layout->nominal_breakpoints)
1139 return E_OUTOFMEMORY;
1141 analyzer = get_text_analyzer();
1143 if (FAILED(hr = IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer,
1144 (IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
1145 0, layout->len, (IDWriteTextAnalysisSink *)&layout->IDWriteTextAnalysisSink1_iface)))
1146 WARN("Line breakpoints analysis failed, hr %#x.\n", hr);
1149 heap_free(layout->actual_breakpoints);
1150 layout->actual_breakpoints = NULL;
1152 hr = layout_compute_runs(layout);
1154 if (TRACE_ON(dwrite)) {
1155 struct layout_run *cur;
1157 LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
1158 if (cur->kind == LAYOUT_RUN_INLINE)
1159 TRACE("run inline object %p, len %u\n", cur->u.object.object, cur->u.object.length);
1160 else
1161 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur->u.regular.descr.textPosition, cur->u.regular.descr.textPosition +
1162 cur->u.regular.descr.stringLength-1, cur->u.regular.descr.stringLength, cur->u.regular.run.bidiLevel);
1166 layout->recompute &= ~RECOMPUTE_CLUSTERS;
1167 return hr;
1170 static inline FLOAT get_cluster_range_width(struct dwrite_textlayout *layout, UINT32 start, UINT32 end)
1172 FLOAT width = 0.0f;
1173 for (; start < end; start++)
1174 width += layout->clustermetrics[start].width;
1175 return width;
1178 static struct layout_range_header *get_layout_range_header_by_pos(struct list *ranges, UINT32 pos)
1180 struct layout_range_header *cur;
1182 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
1183 DWRITE_TEXT_RANGE *r = &cur->range;
1184 if (r->startPosition <= pos && pos < r->startPosition + r->length)
1185 return cur;
1188 return NULL;
1191 static inline IUnknown *layout_get_effect_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1193 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->effects, pos);
1194 return ((struct layout_range_iface*)h)->iface;
1197 static inline BOOL layout_is_erun_rtl(const struct layout_effective_run *erun)
1199 return erun->run->u.regular.run.bidiLevel & 1;
1202 /* A set of parameters that additionally splits resulting runs. It happens after shaping and all text processing,
1203 no glyph changes are possible. It's understandable for drawing effects, because DrawGlyphRun() reports them as
1204 one of the arguments, but it also happens for decorations, so every effective run has uniform
1205 underline/strikethough/effect tuple. */
1206 struct layout_final_splitting_params {
1207 BOOL strikethrough;
1208 BOOL underline;
1209 IUnknown *effect;
1212 static inline BOOL layout_get_strikethrough_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1214 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->strike_ranges, pos);
1215 return ((struct layout_range_bool*)h)->value;
1218 static inline BOOL layout_get_underline_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1220 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->underline_ranges, pos);
1221 return ((struct layout_range_bool*)h)->value;
1224 static void layout_splitting_params_from_pos(struct dwrite_textlayout *layout, UINT32 pos,
1225 struct layout_final_splitting_params *params)
1227 params->strikethrough = layout_get_strikethrough_from_pos(layout, pos);
1228 params->underline = layout_get_underline_from_pos(layout, pos);
1229 params->effect = layout_get_effect_from_pos(layout, pos);
1232 static BOOL is_same_splitting_params(const struct layout_final_splitting_params *left,
1233 const struct layout_final_splitting_params *right)
1235 return left->strikethrough == right->strikethrough &&
1236 left->underline == right->underline &&
1237 left->effect == right->effect;
1240 static void layout_get_erun_font_metrics(struct dwrite_textlayout *layout, struct layout_effective_run *erun,
1241 DWRITE_FONT_METRICS *metrics)
1243 memset(metrics, 0, sizeof(*metrics));
1244 if (is_layout_gdi_compatible(layout)) {
1245 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(
1246 erun->run->u.regular.run.fontFace,
1247 erun->run->u.regular.run.fontEmSize,
1248 layout->ppdip,
1249 &layout->transform,
1250 metrics);
1251 if (FAILED(hr))
1252 WARN("failed to get font metrics, 0x%08x\n", hr);
1254 else
1255 IDWriteFontFace_GetMetrics(erun->run->u.regular.run.fontFace, metrics);
1258 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
1259 'cluster_count' indicates how many clusters to add, including first one. */
1260 static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 first_cluster,
1261 UINT32 cluster_count, UINT32 line, FLOAT origin_x, struct layout_final_splitting_params *params)
1263 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1264 UINT32 i, start, length, last_cluster;
1265 struct layout_effective_run *run;
1267 if (r->kind == LAYOUT_RUN_INLINE) {
1268 struct layout_effective_inline *inlineobject;
1270 inlineobject = heap_alloc(sizeof(*inlineobject));
1271 if (!inlineobject)
1272 return E_OUTOFMEMORY;
1274 inlineobject->object = r->u.object.object;
1275 inlineobject->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1276 inlineobject->origin.x = is_rtl ? origin_x - inlineobject->width : origin_x;
1277 inlineobject->origin.y = 0.0f; /* set after line is built */
1278 inlineobject->align_dx = 0.0f;
1279 inlineobject->baseline = r->baseline;
1281 /* It's not clear how these two are set, possibly directionality
1282 is derived from surrounding text (replaced text could have
1283 different ranges which differ in reading direction). */
1284 inlineobject->is_sideways = FALSE;
1285 inlineobject->is_rtl = FALSE;
1286 inlineobject->line = line;
1288 /* effect assigned from start position and on is used for inline objects */
1289 inlineobject->effect = layout_get_effect_from_pos(layout, layout->clusters[first_cluster].position +
1290 layout->clusters[first_cluster].run->start_position);
1292 list_add_tail(&layout->inlineobjects, &inlineobject->entry);
1293 return S_OK;
1296 run = heap_alloc(sizeof(*run));
1297 if (!run)
1298 return E_OUTOFMEMORY;
1300 /* No need to iterate for that, use simple fact that:
1301 <last cluster position> = <first cluster position> + <sum of cluster lengths not including last one> */
1302 last_cluster = first_cluster + cluster_count - 1;
1303 length = layout->clusters[last_cluster].position - layout->clusters[first_cluster].position +
1304 layout->clustermetrics[last_cluster].length;
1306 run->clustermap = heap_calloc(length, sizeof(*run->clustermap));
1307 if (!run->clustermap) {
1308 heap_free(run);
1309 return E_OUTOFMEMORY;
1312 run->run = r;
1313 run->start = start = layout->clusters[first_cluster].position;
1314 run->length = length;
1315 run->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1316 memset(&run->bbox, 0, sizeof(run->bbox));
1318 /* Check if run direction matches paragraph direction, if it doesn't adjust by
1319 run width */
1320 if (layout_is_erun_rtl(run) ^ is_rtl)
1321 run->origin.x = is_rtl ? origin_x - run->width : origin_x + run->width;
1322 else
1323 run->origin.x = origin_x;
1325 run->origin.y = 0.0f; /* set after line is built */
1326 run->align_dx = 0.0f;
1327 run->line = line;
1329 if (r->u.regular.run.glyphCount) {
1330 /* Trim leading and trailing clusters. */
1331 run->glyphcount = r->u.regular.run.glyphCount - r->u.regular.clustermap[start];
1332 if (start + length < r->u.regular.descr.stringLength)
1333 run->glyphcount -= r->u.regular.run.glyphCount - r->u.regular.clustermap[start + length];
1335 else
1336 run->glyphcount = 0;
1338 /* cluster map needs to be shifted */
1339 for (i = 0; i < length; i++)
1340 run->clustermap[i] = r->u.regular.clustermap[start + i] - r->u.regular.clustermap[start];
1342 run->effect = params->effect;
1343 run->underlined = params->underline;
1344 list_add_tail(&layout->eruns, &run->entry);
1346 /* Strikethrough style is guaranteed to be consistent within effective run,
1347 its width equals to run width, thickness and offset are derived from
1348 font metrics, rest of the values are from layout or run itself */
1349 if (params->strikethrough) {
1350 struct layout_strikethrough *s;
1351 DWRITE_FONT_METRICS metrics;
1353 s = heap_alloc(sizeof(*s));
1354 if (!s)
1355 return E_OUTOFMEMORY;
1357 layout_get_erun_font_metrics(layout, run, &metrics);
1358 s->s.width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1359 s->s.thickness = SCALE_FONT_METRIC(metrics.strikethroughThickness, r->u.regular.run.fontEmSize, &metrics);
1360 /* Negative offset moves it above baseline as Y coordinate grows downward. */
1361 s->s.offset = -SCALE_FONT_METRIC(metrics.strikethroughPosition, r->u.regular.run.fontEmSize, &metrics);
1362 s->s.readingDirection = layout->format.readingdir;
1363 s->s.flowDirection = layout->format.flow;
1364 s->s.localeName = r->u.regular.descr.localeName;
1365 s->s.measuringMode = layout->measuringmode;
1366 s->run = run;
1368 list_add_tail(&layout->strikethrough, &s->entry);
1371 return S_OK;
1374 static void layout_apply_line_spacing(struct dwrite_textlayout *layout, UINT32 line)
1376 switch (layout->format.spacing.method)
1378 case DWRITE_LINE_SPACING_METHOD_DEFAULT:
1379 layout->lines[line].metrics.height = layout->lines[line].height;
1380 layout->lines[line].metrics.baseline = layout->lines[line].baseline;
1381 break;
1382 case DWRITE_LINE_SPACING_METHOD_UNIFORM:
1383 layout->lines[line].metrics.height = layout->format.spacing.height;
1384 layout->lines[line].metrics.baseline = layout->format.spacing.baseline;
1385 break;
1386 case DWRITE_LINE_SPACING_METHOD_PROPORTIONAL:
1387 layout->lines[line].metrics.height = layout->lines[line].height * layout->format.spacing.height;
1388 layout->lines[line].metrics.baseline = layout->lines[line].baseline * layout->format.spacing.baseline;
1389 break;
1390 default:
1391 ERR("Unknown spacing method %u\n", layout->format.spacing.method);
1395 static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_LINE_METRICS1 *metrics)
1397 size_t i = layout->metrics.lineCount;
1399 if (!dwrite_array_reserve((void **)&layout->lines, &layout->lines_size, layout->metrics.lineCount + 1,
1400 sizeof(*layout->lines)))
1402 return E_OUTOFMEMORY;
1405 layout->lines[i].metrics = *metrics;
1406 layout->lines[i].height = metrics->height;
1407 layout->lines[i].baseline = metrics->baseline;
1409 if (layout->format.spacing.method != DWRITE_LINE_SPACING_METHOD_DEFAULT)
1410 layout_apply_line_spacing(layout, i);
1412 layout->metrics.lineCount++;
1413 return S_OK;
1416 static inline struct layout_effective_run *layout_get_next_erun(struct dwrite_textlayout *layout,
1417 const struct layout_effective_run *cur)
1419 struct list *e;
1421 if (!cur)
1422 e = list_head(&layout->eruns);
1423 else
1424 e = list_next(&layout->eruns, &cur->entry);
1425 if (!e)
1426 return NULL;
1427 return LIST_ENTRY(e, struct layout_effective_run, entry);
1430 static inline struct layout_effective_run *layout_get_prev_erun(struct dwrite_textlayout *layout,
1431 const struct layout_effective_run *cur)
1433 struct list *e;
1435 if (!cur)
1436 e = list_tail(&layout->eruns);
1437 else
1438 e = list_prev(&layout->eruns, &cur->entry);
1439 if (!e)
1440 return NULL;
1441 return LIST_ENTRY(e, struct layout_effective_run, entry);
1444 static inline struct layout_effective_inline *layout_get_next_inline_run(struct dwrite_textlayout *layout,
1445 const struct layout_effective_inline *cur)
1447 struct list *e;
1449 if (!cur)
1450 e = list_head(&layout->inlineobjects);
1451 else
1452 e = list_next(&layout->inlineobjects, &cur->entry);
1453 if (!e)
1454 return NULL;
1455 return LIST_ENTRY(e, struct layout_effective_inline, entry);
1458 static FLOAT layout_get_line_width(struct dwrite_textlayout *layout,
1459 struct layout_effective_run *erun, struct layout_effective_inline *inrun, UINT32 line)
1461 FLOAT width = 0.0f;
1463 while (erun && erun->line == line) {
1464 width += erun->width;
1465 erun = layout_get_next_erun(layout, erun);
1466 if (!erun)
1467 break;
1470 while (inrun && inrun->line == line) {
1471 width += inrun->width;
1472 inrun = layout_get_next_inline_run(layout, inrun);
1473 if (!inrun)
1474 break;
1477 return width;
1480 static inline BOOL should_skip_transform(const DWRITE_MATRIX *m, FLOAT *det)
1482 *det = m->m11 * m->m22 - m->m12 * m->m21;
1483 /* on certain conditions we can skip transform */
1484 return (!memcmp(m, &identity, sizeof(*m)) || fabsf(*det) <= 1e-10f);
1487 static inline void layout_apply_snapping(D2D1_POINT_2F *vec, BOOL skiptransform, FLOAT ppdip,
1488 const DWRITE_MATRIX *m, FLOAT det)
1490 if (!skiptransform) {
1491 D2D1_POINT_2F vec2;
1493 /* apply transform */
1494 vec->x *= ppdip;
1495 vec->y *= ppdip;
1497 vec2.x = m->m11 * vec->x + m->m21 * vec->y + m->dx;
1498 vec2.y = m->m12 * vec->x + m->m22 * vec->y + m->dy;
1500 /* snap */
1501 vec2.x = floorf(vec2.x + 0.5f);
1502 vec2.y = floorf(vec2.y + 0.5f);
1504 /* apply inverted transform, we don't care about X component at this point */
1505 vec->x = (m->m22 * vec2.x - m->m21 * vec2.y + m->m21 * m->dy - m->m22 * m->dx) / det;
1506 vec->x /= ppdip;
1508 vec->y = (-m->m12 * vec2.x + m->m11 * vec2.y - (m->m11 * m->dy - m->m12 * m->dx)) / det;
1509 vec->y /= ppdip;
1511 else {
1512 vec->x = floorf(vec->x * ppdip + 0.5f) / ppdip;
1513 vec->y = floorf(vec->y * ppdip + 0.5f) / ppdip;
1517 static void layout_apply_leading_alignment(struct dwrite_textlayout *layout)
1519 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1520 struct layout_effective_inline *inrun;
1521 struct layout_effective_run *erun;
1523 erun = layout_get_next_erun(layout, NULL);
1524 inrun = layout_get_next_inline_run(layout, NULL);
1526 while (erun) {
1527 erun->align_dx = 0.0f;
1528 erun = layout_get_next_erun(layout, erun);
1531 while (inrun) {
1532 inrun->align_dx = 0.0f;
1533 inrun = layout_get_next_inline_run(layout, inrun);
1536 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
1539 static void layout_apply_trailing_alignment(struct dwrite_textlayout *layout)
1541 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1542 struct layout_effective_inline *inrun;
1543 struct layout_effective_run *erun;
1544 UINT32 line;
1546 erun = layout_get_next_erun(layout, NULL);
1547 inrun = layout_get_next_inline_run(layout, NULL);
1549 for (line = 0; line < layout->metrics.lineCount; line++) {
1550 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1551 FLOAT shift = layout->metrics.layoutWidth - width;
1553 if (is_rtl)
1554 shift *= -1.0f;
1556 while (erun && erun->line == line) {
1557 erun->align_dx = shift;
1558 erun = layout_get_next_erun(layout, erun);
1561 while (inrun && inrun->line == line) {
1562 inrun->align_dx = shift;
1563 inrun = layout_get_next_inline_run(layout, inrun);
1567 layout->metrics.left = is_rtl ? 0.0f : layout->metrics.layoutWidth - layout->metrics.width;
1570 static inline FLOAT layout_get_centered_shift(struct dwrite_textlayout *layout, BOOL skiptransform,
1571 FLOAT width, FLOAT det)
1573 if (is_layout_gdi_compatible(layout)) {
1574 D2D1_POINT_2F vec = { layout->metrics.layoutWidth - width, 0.0f};
1575 layout_apply_snapping(&vec, skiptransform, layout->ppdip, &layout->transform, det);
1576 return floorf(vec.x / 2.0f);
1578 else
1579 return (layout->metrics.layoutWidth - width) / 2.0f;
1582 static void layout_apply_centered_alignment(struct dwrite_textlayout *layout)
1584 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1585 struct layout_effective_inline *inrun;
1586 struct layout_effective_run *erun;
1587 BOOL skiptransform;
1588 UINT32 line;
1589 FLOAT det;
1591 erun = layout_get_next_erun(layout, NULL);
1592 inrun = layout_get_next_inline_run(layout, NULL);
1594 skiptransform = should_skip_transform(&layout->transform, &det);
1596 for (line = 0; line < layout->metrics.lineCount; line++) {
1597 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1598 FLOAT shift = layout_get_centered_shift(layout, skiptransform, width, det);
1600 if (is_rtl)
1601 shift *= -1.0f;
1603 while (erun && erun->line == line) {
1604 erun->align_dx = shift;
1605 erun = layout_get_next_erun(layout, erun);
1608 while (inrun && inrun->line == line) {
1609 inrun->align_dx = shift;
1610 inrun = layout_get_next_inline_run(layout, inrun);
1614 layout->metrics.left = (layout->metrics.layoutWidth - layout->metrics.width) / 2.0f;
1617 static void layout_apply_text_alignment(struct dwrite_textlayout *layout)
1619 switch (layout->format.textalignment)
1621 case DWRITE_TEXT_ALIGNMENT_LEADING:
1622 layout_apply_leading_alignment(layout);
1623 break;
1624 case DWRITE_TEXT_ALIGNMENT_TRAILING:
1625 layout_apply_trailing_alignment(layout);
1626 break;
1627 case DWRITE_TEXT_ALIGNMENT_CENTER:
1628 layout_apply_centered_alignment(layout);
1629 break;
1630 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED:
1631 FIXME("alignment %d not implemented\n", layout->format.textalignment);
1632 break;
1633 default:
1638 static void layout_apply_par_alignment(struct dwrite_textlayout *layout)
1640 struct layout_effective_inline *inrun;
1641 struct layout_effective_run *erun;
1642 FLOAT origin_y = 0.0f;
1643 UINT32 line;
1645 /* alignment mode defines origin, after that all run origins are updated
1646 the same way */
1648 switch (layout->format.paralign)
1650 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR:
1651 origin_y = 0.0f;
1652 break;
1653 case DWRITE_PARAGRAPH_ALIGNMENT_FAR:
1654 origin_y = layout->metrics.layoutHeight - layout->metrics.height;
1655 break;
1656 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER:
1657 origin_y = (layout->metrics.layoutHeight - layout->metrics.height) / 2.0f;
1658 break;
1659 default:
1663 layout->metrics.top = origin_y;
1665 erun = layout_get_next_erun(layout, NULL);
1666 inrun = layout_get_next_inline_run(layout, NULL);
1667 for (line = 0; line < layout->metrics.lineCount; line++)
1669 float pos_y = origin_y + layout->lines[line].metrics.baseline;
1671 while (erun && erun->line == line) {
1672 erun->origin.y = pos_y;
1673 erun = layout_get_next_erun(layout, erun);
1676 while (inrun && inrun->line == line) {
1677 inrun->origin.y = pos_y - inrun->baseline;
1678 inrun = layout_get_next_inline_run(layout, inrun);
1681 origin_y += layout->lines[line].metrics.height;
1685 struct layout_underline_splitting_params {
1686 const WCHAR *locale; /* points to range data, no additional allocation */
1687 IUnknown *effect; /* does not hold another reference */
1690 static void init_u_splitting_params_from_erun(struct layout_effective_run *erun,
1691 struct layout_underline_splitting_params *params)
1693 params->locale = erun->run->u.regular.descr.localeName;
1694 params->effect = erun->effect;
1697 static BOOL is_same_u_splitting(struct layout_underline_splitting_params *left,
1698 struct layout_underline_splitting_params *right)
1700 return left->effect == right->effect && !strcmpiW(left->locale, right->locale);
1703 static HRESULT layout_add_underline(struct dwrite_textlayout *layout, struct layout_effective_run *first,
1704 struct layout_effective_run *last)
1706 FLOAT thickness, offset, runheight;
1707 struct layout_effective_run *cur;
1708 DWRITE_FONT_METRICS metrics;
1710 if (first == layout_get_prev_erun(layout, last)) {
1711 layout_get_erun_font_metrics(layout, first, &metrics);
1712 thickness = SCALE_FONT_METRIC(metrics.underlineThickness, first->run->u.regular.run.fontEmSize, &metrics);
1713 offset = SCALE_FONT_METRIC(metrics.underlinePosition, first->run->u.regular.run.fontEmSize, &metrics);
1714 runheight = SCALE_FONT_METRIC(metrics.capHeight, first->run->u.regular.run.fontEmSize, &metrics);
1716 else {
1717 FLOAT width = 0.0f;
1719 /* Single underline is added for consecutive underlined runs. In this case underline parameters are
1720 calculated as weighted average, where run width acts as a weight. */
1721 thickness = offset = runheight = 0.0f;
1722 cur = first;
1723 do {
1724 layout_get_erun_font_metrics(layout, cur, &metrics);
1726 thickness += SCALE_FONT_METRIC(metrics.underlineThickness, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
1727 offset += SCALE_FONT_METRIC(metrics.underlinePosition, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
1728 runheight = max(SCALE_FONT_METRIC(metrics.capHeight, cur->run->u.regular.run.fontEmSize, &metrics), runheight);
1729 width += cur->width;
1731 cur = layout_get_next_erun(layout, cur);
1732 } while (cur != last);
1734 thickness /= width;
1735 offset /= width;
1738 cur = first;
1739 do {
1740 struct layout_underline_splitting_params params, prev_params;
1741 struct layout_effective_run *next, *w;
1742 struct layout_underline *u;
1744 init_u_splitting_params_from_erun(cur, &prev_params);
1745 while ((next = layout_get_next_erun(layout, cur)) != last) {
1746 init_u_splitting_params_from_erun(next, &params);
1747 if (!is_same_u_splitting(&prev_params, &params))
1748 break;
1749 cur = next;
1752 u = heap_alloc(sizeof(*u));
1753 if (!u)
1754 return E_OUTOFMEMORY;
1756 w = cur;
1757 u->u.width = 0.0f;
1758 while (w != next) {
1759 u->u.width += w->width;
1760 w = layout_get_next_erun(layout, w);
1763 u->u.thickness = thickness;
1764 /* Font metrics convention is to have it negative when below baseline, for rendering
1765 however Y grows from baseline down for horizontal baseline. */
1766 u->u.offset = -offset;
1767 u->u.runHeight = runheight;
1768 u->u.readingDirection = is_run_rtl(cur) ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
1769 DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
1770 u->u.flowDirection = layout->format.flow;
1771 u->u.localeName = cur->run->u.regular.descr.localeName;
1772 u->u.measuringMode = layout->measuringmode;
1773 u->run = cur;
1774 list_add_tail(&layout->underlines, &u->entry);
1776 cur = next;
1777 } while (cur != last);
1779 return S_OK;
1782 /* Adds zero width line, metrics are derived from font at specified text position. */
1783 static HRESULT layout_set_dummy_line_metrics(struct dwrite_textlayout *layout, UINT32 pos)
1785 DWRITE_LINE_METRICS1 metrics = { 0 };
1786 DWRITE_FONT_METRICS fontmetrics;
1787 struct layout_range *range;
1788 IDWriteFontFace *fontface;
1789 IDWriteFont *font;
1790 HRESULT hr;
1792 range = get_layout_range_by_pos(layout, pos);
1793 hr = create_matching_font(range->collection,
1794 range->fontfamily,
1795 range->weight,
1796 range->style,
1797 range->stretch,
1798 &font);
1799 if (FAILED(hr))
1800 return hr;
1801 hr = IDWriteFont_CreateFontFace(font, &fontface);
1802 IDWriteFont_Release(font);
1803 if (FAILED(hr))
1804 return hr;
1806 layout_get_font_metrics(layout, fontface, range->fontsize, &fontmetrics);
1807 layout_get_font_height(range->fontsize, &fontmetrics, &metrics.baseline, &metrics.height);
1808 IDWriteFontFace_Release(fontface);
1810 return layout_set_line_metrics(layout, &metrics);
1813 static void layout_add_line(struct dwrite_textlayout *layout, UINT32 first_cluster, UINT32 last_cluster,
1814 UINT32 *textpos)
1816 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1817 struct layout_final_splitting_params params, prev_params;
1818 DWRITE_INLINE_OBJECT_METRICS sign_metrics = { 0 };
1819 UINT32 line = layout->metrics.lineCount, i;
1820 DWRITE_LINE_METRICS1 metrics = { 0 };
1821 UINT32 index, start, pos = *textpos;
1822 FLOAT descent, trailingspacewidth;
1823 BOOL append_trimming_run = FALSE;
1824 const struct layout_run *run;
1825 float width = 0.0f, origin_x;
1826 HRESULT hr;
1828 /* Take a look at clusters we got for this line in reverse order to set trailing properties for current line */
1829 for (index = last_cluster, trailingspacewidth = 0.0f; index >= first_cluster; index--) {
1830 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1831 struct layout_cluster *lc = &layout->clusters[index];
1832 WCHAR ch;
1834 /* This also filters out clusters added from inline objects, those are never
1835 treated as a white space. */
1836 if (!cluster->isWhitespace)
1837 break;
1839 /* Every isNewline cluster is also isWhitespace, but not every
1840 newline character cluster has isNewline set, so go back to original string. */
1841 ch = lc->run->u.regular.descr.string[lc->position];
1842 if (cluster->length == 1 && lb_is_newline_char(ch))
1843 metrics.newlineLength += cluster->length;
1845 metrics.trailingWhitespaceLength += cluster->length;
1846 trailingspacewidth += cluster->width;
1848 if (index == 0)
1849 break;
1852 /* Line metrics length includes trailing whitespace length too */
1853 for (i = first_cluster; i <= last_cluster; i++)
1854 metrics.length += layout->clustermetrics[i].length;
1856 /* Ignore trailing whitespaces */
1857 while (last_cluster > first_cluster) {
1858 if (!layout->clustermetrics[last_cluster].isWhitespace)
1859 break;
1861 last_cluster--;
1864 /* Does not include trailing space width */
1865 if (!layout->clustermetrics[last_cluster].isWhitespace)
1866 width = get_cluster_range_width(layout, first_cluster, last_cluster + 1);
1868 /* Append trimming run if necessary */
1869 if (width > layout->metrics.layoutWidth && layout->format.trimmingsign != NULL &&
1870 layout->format.trimming.granularity != DWRITE_TRIMMING_GRANULARITY_NONE) {
1871 FLOAT trimmed_width = width;
1873 hr = IDWriteInlineObject_GetMetrics(layout->format.trimmingsign, &sign_metrics);
1874 if (SUCCEEDED(hr)) {
1875 while (last_cluster > first_cluster) {
1876 if (trimmed_width + sign_metrics.width <= layout->metrics.layoutWidth)
1877 break;
1878 if (layout->format.trimming.granularity == DWRITE_TRIMMING_GRANULARITY_CHARACTER)
1879 trimmed_width -= layout->clustermetrics[last_cluster--].width;
1880 else {
1881 while (last_cluster > first_cluster) {
1882 trimmed_width -= layout->clustermetrics[last_cluster].width;
1883 if (layout->clustermetrics[last_cluster--].canWrapLineAfter)
1884 break;
1888 append_trimming_run = TRUE;
1890 else
1891 WARN("Failed to get trimming sign metrics, lines won't be trimmed, hr %#x.\n", hr);
1893 width = trimmed_width + sign_metrics.width;
1896 layout_splitting_params_from_pos(layout, pos, &params);
1897 prev_params = params;
1898 run = layout->clusters[first_cluster].run;
1900 /* Form runs from a range of clusters; this is what will be reported with DrawGlyphRun() */
1901 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0f;
1902 for (start = first_cluster, i = first_cluster; i <= last_cluster; i++) {
1903 layout_splitting_params_from_pos(layout, pos, &params);
1905 if (run != layout->clusters[i].run || !is_same_splitting_params(&prev_params, &params)) {
1906 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, &prev_params);
1907 if (FAILED(hr))
1908 return;
1910 origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) :
1911 get_cluster_range_width(layout, start, i);
1912 run = layout->clusters[i].run;
1913 start = i;
1916 prev_params = params;
1917 pos += layout->clustermetrics[i].length;
1920 /* Final run from what's left from cluster range */
1921 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, &prev_params);
1922 if (FAILED(hr))
1923 return;
1925 if (get_cluster_range_width(layout, start, i) + sign_metrics.width > layout->metrics.layoutWidth)
1926 append_trimming_run = FALSE;
1928 if (append_trimming_run) {
1929 struct layout_effective_inline *trimming_sign;
1931 trimming_sign = heap_alloc(sizeof(*trimming_sign));
1932 if (!trimming_sign)
1933 return;
1935 trimming_sign->object = layout->format.trimmingsign;
1936 trimming_sign->width = sign_metrics.width;
1937 origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) : get_cluster_range_width(layout, start, i);
1938 trimming_sign->origin.x = is_rtl ? origin_x - trimming_sign->width : origin_x;
1939 trimming_sign->origin.y = 0.0f; /* set after line is built */
1940 trimming_sign->align_dx = 0.0f;
1941 trimming_sign->baseline = sign_metrics.baseline;
1943 trimming_sign->is_sideways = FALSE;
1944 trimming_sign->is_rtl = FALSE;
1945 trimming_sign->line = line;
1947 trimming_sign->effect = layout_get_effect_from_pos(layout, layout->clusters[i].position +
1948 layout->clusters[i].run->start_position);
1950 list_add_tail(&layout->inlineobjects, &trimming_sign->entry);
1953 /* Look for max baseline and descent for this line */
1954 for (index = first_cluster, metrics.baseline = 0.0f, descent = 0.0f; index <= last_cluster; index++) {
1955 const struct layout_run *cur = layout->clusters[index].run;
1956 FLOAT cur_descent = cur->height - cur->baseline;
1958 if (cur->baseline > metrics.baseline)
1959 metrics.baseline = cur->baseline;
1960 if (cur_descent > descent)
1961 descent = cur_descent;
1964 layout->metrics.width = max(width, layout->metrics.width);
1965 layout->metrics.widthIncludingTrailingWhitespace = max(width + trailingspacewidth,
1966 layout->metrics.widthIncludingTrailingWhitespace);
1968 metrics.height = descent + metrics.baseline;
1969 metrics.isTrimmed = append_trimming_run || width > layout->metrics.layoutWidth;
1970 layout_set_line_metrics(layout, &metrics);
1972 *textpos += metrics.length;
1975 static void layout_set_line_positions(struct dwrite_textlayout *layout)
1977 struct layout_effective_inline *inrun;
1978 struct layout_effective_run *erun;
1979 FLOAT origin_y;
1980 UINT32 line;
1982 /* Now all line info is here, update effective runs positions in flow direction */
1983 erun = layout_get_next_erun(layout, NULL);
1984 inrun = layout_get_next_inline_run(layout, NULL);
1986 for (line = 0, origin_y = 0.0f; line < layout->metrics.lineCount; line++)
1988 float pos_y = origin_y + layout->lines[line].metrics.baseline;
1990 /* For all runs on this line */
1991 while (erun && erun->line == line) {
1992 erun->origin.y = pos_y;
1993 erun = layout_get_next_erun(layout, erun);
1996 /* Same for inline runs */
1997 while (inrun && inrun->line == line) {
1998 inrun->origin.y = pos_y - inrun->baseline;
1999 inrun = layout_get_next_inline_run(layout, inrun);
2002 origin_y += layout->lines[line].metrics.height;
2005 layout->metrics.height = origin_y;
2007 /* Initial paragraph alignment is always near */
2008 if (layout->format.paralign != DWRITE_PARAGRAPH_ALIGNMENT_NEAR)
2009 layout_apply_par_alignment(layout);
2012 static BOOL layout_can_wrap_after(const struct dwrite_textlayout *layout, UINT32 cluster)
2014 if (layout->format.wrapping == DWRITE_WORD_WRAPPING_CHARACTER)
2015 return TRUE;
2017 return layout->clustermetrics[cluster].canWrapLineAfter;
2020 static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
2022 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
2023 struct layout_effective_run *erun, *first_underlined;
2024 UINT32 i, start, textpos, last_breaking_point;
2025 DWRITE_LINE_METRICS1 metrics;
2026 FLOAT width;
2027 UINT32 line;
2028 HRESULT hr;
2030 if (!(layout->recompute & RECOMPUTE_LINES))
2031 return S_OK;
2033 free_layout_eruns(layout);
2035 hr = layout_compute(layout);
2036 if (FAILED(hr))
2037 return hr;
2039 layout->metrics.lineCount = 0;
2040 memset(&metrics, 0, sizeof(metrics));
2042 layout->metrics.height = 0.0f;
2043 layout->metrics.width = 0.0f;
2044 layout->metrics.widthIncludingTrailingWhitespace = 0.0f;
2046 last_breaking_point = ~0u;
2048 for (i = 0, start = 0, width = 0.0f, textpos = 0; i < layout->cluster_count; i++) {
2049 BOOL overflow = FALSE;
2051 while (i < layout->cluster_count && !layout->clustermetrics[i].isNewline) {
2052 /* Check for overflow */
2053 overflow = ((width + layout->clustermetrics[i].width > layout->metrics.layoutWidth) &&
2054 (layout->format.wrapping != DWRITE_WORD_WRAPPING_NO_WRAP));
2055 if (overflow)
2056 break;
2058 if (layout_can_wrap_after(layout, i))
2059 last_breaking_point = i;
2060 width += layout->clustermetrics[i].width;
2061 i++;
2063 i = min(i, layout->cluster_count - 1);
2065 /* Ignore if overflown on whitespace */
2066 if (overflow && !(layout->clustermetrics[i].isWhitespace && layout_can_wrap_after(layout, i))) {
2067 /* Use most recently found breaking point */
2068 if (last_breaking_point != ~0u) {
2069 i = last_breaking_point;
2070 last_breaking_point = ~0u;
2072 else {
2073 /* Otherwise proceed forward to next newline or breaking point */
2074 for (; i < layout->cluster_count; i++)
2075 if (layout_can_wrap_after(layout, i) || layout->clustermetrics[i].isNewline)
2076 break;
2079 i = min(i, layout->cluster_count - 1);
2081 layout_add_line(layout, start, i, &textpos);
2082 start = i + 1;
2083 width = 0.0f;
2086 /* Add dummy line if:
2087 - there's no text, metrics come from first range in this case;
2088 - last ended with a mandatory break, metrics come from last text position.
2090 if (layout->len == 0)
2091 hr = layout_set_dummy_line_metrics(layout, 0);
2092 else if (layout->cluster_count && layout->clustermetrics[layout->cluster_count - 1].isNewline)
2093 hr = layout_set_dummy_line_metrics(layout, layout->len - 1);
2094 if (FAILED(hr))
2095 return hr;
2097 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
2098 layout->metrics.top = 0.0f;
2099 layout->metrics.maxBidiReorderingDepth = 1; /* FIXME */
2101 /* Add explicit underlined runs */
2102 erun = layout_get_next_erun(layout, NULL);
2103 first_underlined = erun && erun->underlined ? erun : NULL;
2104 for (line = 0; line < layout->metrics.lineCount; line++) {
2105 while (erun && erun->line == line) {
2106 erun = layout_get_next_erun(layout, erun);
2108 if (first_underlined && (!erun || !erun->underlined)) {
2109 layout_add_underline(layout, first_underlined, erun);
2110 first_underlined = NULL;
2112 else if (!first_underlined && erun && erun->underlined)
2113 first_underlined = erun;
2117 /* Position runs in flow direction */
2118 layout_set_line_positions(layout);
2120 /* Initial alignment is always leading */
2121 if (layout->format.textalignment != DWRITE_TEXT_ALIGNMENT_LEADING)
2122 layout_apply_text_alignment(layout);
2124 layout->recompute &= ~RECOMPUTE_LINES;
2125 return hr;
2128 static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum layout_range_attr_kind attr,
2129 struct layout_range_attr_value *value)
2131 struct layout_range_spacing const *range_spacing = (struct layout_range_spacing*)h;
2132 struct layout_range_iface const *range_iface = (struct layout_range_iface*)h;
2133 struct layout_range_bool const *range_bool = (struct layout_range_bool*)h;
2134 struct layout_range const *range = (struct layout_range*)h;
2136 switch (attr) {
2137 case LAYOUT_RANGE_ATTR_WEIGHT:
2138 return range->weight == value->u.weight;
2139 case LAYOUT_RANGE_ATTR_STYLE:
2140 return range->style == value->u.style;
2141 case LAYOUT_RANGE_ATTR_STRETCH:
2142 return range->stretch == value->u.stretch;
2143 case LAYOUT_RANGE_ATTR_FONTSIZE:
2144 return range->fontsize == value->u.fontsize;
2145 case LAYOUT_RANGE_ATTR_INLINE:
2146 return range->object == value->u.object;
2147 case LAYOUT_RANGE_ATTR_EFFECT:
2148 return range_iface->iface == value->u.effect;
2149 case LAYOUT_RANGE_ATTR_UNDERLINE:
2150 return range_bool->value == value->u.underline;
2151 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2152 return range_bool->value == value->u.strikethrough;
2153 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2154 return range->pair_kerning == value->u.pair_kerning;
2155 case LAYOUT_RANGE_ATTR_FONTCOLL:
2156 return range->collection == value->u.collection;
2157 case LAYOUT_RANGE_ATTR_LOCALE:
2158 return strcmpiW(range->locale, value->u.locale) == 0;
2159 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2160 return strcmpW(range->fontfamily, value->u.fontfamily) == 0;
2161 case LAYOUT_RANGE_ATTR_SPACING:
2162 return range_spacing->leading == value->u.spacing.leading &&
2163 range_spacing->trailing == value->u.spacing.trailing &&
2164 range_spacing->min_advance == value->u.spacing.min_advance;
2165 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2166 return range_iface->iface == (IUnknown*)value->u.typography;
2167 default:
2171 return FALSE;
2174 static inline BOOL is_same_layout_attributes(struct layout_range_header const *hleft, struct layout_range_header const *hright)
2176 switch (hleft->kind)
2178 case LAYOUT_RANGE_REGULAR:
2180 struct layout_range const *left = (struct layout_range const*)hleft;
2181 struct layout_range const *right = (struct layout_range const*)hright;
2182 return left->weight == right->weight &&
2183 left->style == right->style &&
2184 left->stretch == right->stretch &&
2185 left->fontsize == right->fontsize &&
2186 left->object == right->object &&
2187 left->pair_kerning == right->pair_kerning &&
2188 left->collection == right->collection &&
2189 !strcmpiW(left->locale, right->locale) &&
2190 !strcmpW(left->fontfamily, right->fontfamily);
2192 case LAYOUT_RANGE_UNDERLINE:
2193 case LAYOUT_RANGE_STRIKETHROUGH:
2195 struct layout_range_bool const *left = (struct layout_range_bool const*)hleft;
2196 struct layout_range_bool const *right = (struct layout_range_bool const*)hright;
2197 return left->value == right->value;
2199 case LAYOUT_RANGE_EFFECT:
2200 case LAYOUT_RANGE_TYPOGRAPHY:
2202 struct layout_range_iface const *left = (struct layout_range_iface const*)hleft;
2203 struct layout_range_iface const *right = (struct layout_range_iface const*)hright;
2204 return left->iface == right->iface;
2206 case LAYOUT_RANGE_SPACING:
2208 struct layout_range_spacing const *left = (struct layout_range_spacing const*)hleft;
2209 struct layout_range_spacing const *right = (struct layout_range_spacing const*)hright;
2210 return left->leading == right->leading &&
2211 left->trailing == right->trailing &&
2212 left->min_advance == right->min_advance;
2214 default:
2215 FIXME("unknown range kind %d\n", hleft->kind);
2216 return FALSE;
2220 static inline BOOL is_same_text_range(const DWRITE_TEXT_RANGE *left, const DWRITE_TEXT_RANGE *right)
2222 return left->startPosition == right->startPosition && left->length == right->length;
2225 /* Allocates range and inits it with default values from text format. */
2226 static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout *layout, const DWRITE_TEXT_RANGE *r,
2227 enum layout_range_kind kind)
2229 struct layout_range_header *h;
2231 switch (kind)
2233 case LAYOUT_RANGE_REGULAR:
2235 struct layout_range *range;
2237 range = heap_alloc_zero(sizeof(*range));
2238 if (!range) return NULL;
2240 range->weight = layout->format.weight;
2241 range->style = layout->format.style;
2242 range->stretch = layout->format.stretch;
2243 range->fontsize = layout->format.fontsize;
2245 range->fontfamily = heap_strdupW(layout->format.family_name);
2246 if (!range->fontfamily)
2248 heap_free(range);
2249 return NULL;
2252 range->collection = layout->format.collection;
2253 if (range->collection)
2254 IDWriteFontCollection_AddRef(range->collection);
2255 strcpyW(range->locale, layout->format.locale);
2257 h = &range->h;
2258 break;
2260 case LAYOUT_RANGE_UNDERLINE:
2261 case LAYOUT_RANGE_STRIKETHROUGH:
2263 struct layout_range_bool *range;
2265 range = heap_alloc_zero(sizeof(*range));
2266 if (!range) return NULL;
2268 h = &range->h;
2269 break;
2271 case LAYOUT_RANGE_EFFECT:
2272 case LAYOUT_RANGE_TYPOGRAPHY:
2274 struct layout_range_iface *range;
2276 range = heap_alloc_zero(sizeof(*range));
2277 if (!range) return NULL;
2279 h = &range->h;
2280 break;
2282 case LAYOUT_RANGE_SPACING:
2284 struct layout_range_spacing *range;
2286 range = heap_alloc_zero(sizeof(*range));
2287 if (!range) return NULL;
2289 h = &range->h;
2290 break;
2292 default:
2293 FIXME("unknown range kind %d\n", kind);
2294 return NULL;
2297 h->kind = kind;
2298 h->range = *r;
2299 return h;
2302 static struct layout_range_header *alloc_layout_range_from(struct layout_range_header *h, const DWRITE_TEXT_RANGE *r)
2304 struct layout_range_header *ret;
2306 switch (h->kind)
2308 case LAYOUT_RANGE_REGULAR:
2310 struct layout_range *from = (struct layout_range*)h;
2312 struct layout_range *range = heap_alloc(sizeof(*range));
2313 if (!range) return NULL;
2315 *range = *from;
2316 range->fontfamily = heap_strdupW(from->fontfamily);
2317 if (!range->fontfamily) {
2318 heap_free(range);
2319 return NULL;
2322 /* update refcounts */
2323 if (range->object)
2324 IDWriteInlineObject_AddRef(range->object);
2325 if (range->collection)
2326 IDWriteFontCollection_AddRef(range->collection);
2327 ret = &range->h;
2328 break;
2330 case LAYOUT_RANGE_UNDERLINE:
2331 case LAYOUT_RANGE_STRIKETHROUGH:
2333 struct layout_range_bool *strike = heap_alloc(sizeof(*strike));
2334 if (!strike) return NULL;
2336 *strike = *(struct layout_range_bool*)h;
2337 ret = &strike->h;
2338 break;
2340 case LAYOUT_RANGE_EFFECT:
2341 case LAYOUT_RANGE_TYPOGRAPHY:
2343 struct layout_range_iface *effect = heap_alloc(sizeof(*effect));
2344 if (!effect) return NULL;
2346 *effect = *(struct layout_range_iface*)h;
2347 if (effect->iface)
2348 IUnknown_AddRef(effect->iface);
2349 ret = &effect->h;
2350 break;
2352 case LAYOUT_RANGE_SPACING:
2354 struct layout_range_spacing *spacing = heap_alloc(sizeof(*spacing));
2355 if (!spacing) return NULL;
2357 *spacing = *(struct layout_range_spacing*)h;
2358 ret = &spacing->h;
2359 break;
2361 default:
2362 FIXME("unknown range kind %d\n", h->kind);
2363 return NULL;
2366 ret->range = *r;
2367 return ret;
2370 static void free_layout_range(struct layout_range_header *h)
2372 if (!h)
2373 return;
2375 switch (h->kind)
2377 case LAYOUT_RANGE_REGULAR:
2379 struct layout_range *range = (struct layout_range*)h;
2381 if (range->object)
2382 IDWriteInlineObject_Release(range->object);
2383 if (range->collection)
2384 IDWriteFontCollection_Release(range->collection);
2385 heap_free(range->fontfamily);
2386 break;
2388 case LAYOUT_RANGE_EFFECT:
2389 case LAYOUT_RANGE_TYPOGRAPHY:
2391 struct layout_range_iface *range = (struct layout_range_iface*)h;
2392 if (range->iface)
2393 IUnknown_Release(range->iface);
2394 break;
2396 default:
2400 heap_free(h);
2403 static void free_layout_ranges_list(struct dwrite_textlayout *layout)
2405 struct layout_range_header *cur, *cur2;
2407 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->ranges, struct layout_range_header, entry) {
2408 list_remove(&cur->entry);
2409 free_layout_range(cur);
2412 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->underline_ranges, struct layout_range_header, entry) {
2413 list_remove(&cur->entry);
2414 free_layout_range(cur);
2417 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->strike_ranges, struct layout_range_header, entry) {
2418 list_remove(&cur->entry);
2419 free_layout_range(cur);
2422 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->effects, struct layout_range_header, entry) {
2423 list_remove(&cur->entry);
2424 free_layout_range(cur);
2427 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->spacing, struct layout_range_header, entry) {
2428 list_remove(&cur->entry);
2429 free_layout_range(cur);
2432 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->typographies, struct layout_range_header, entry) {
2433 list_remove(&cur->entry);
2434 free_layout_range(cur);
2438 static struct layout_range_header *find_outer_range(struct list *ranges, const DWRITE_TEXT_RANGE *range)
2440 struct layout_range_header *cur;
2442 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
2444 if (cur->range.startPosition > range->startPosition)
2445 return NULL;
2447 if ((cur->range.startPosition + cur->range.length < range->startPosition + range->length) &&
2448 (range->startPosition < cur->range.startPosition + cur->range.length))
2449 return NULL;
2450 if (cur->range.startPosition + cur->range.length >= range->startPosition + range->length)
2451 return cur;
2454 return NULL;
2457 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos)
2459 struct layout_range *cur;
2461 LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, h.entry) {
2462 DWRITE_TEXT_RANGE *r = &cur->h.range;
2463 if (r->startPosition <= pos && pos < r->startPosition + r->length)
2464 return cur;
2467 return NULL;
2470 static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
2472 if (*dest == value) return FALSE;
2474 if (*dest)
2475 IUnknown_Release(*dest);
2476 *dest = value;
2477 if (*dest)
2478 IUnknown_AddRef(*dest);
2480 return TRUE;
2483 static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2485 struct layout_range_spacing *dest_spacing = (struct layout_range_spacing*)h;
2486 struct layout_range_iface *dest_iface = (struct layout_range_iface*)h;
2487 struct layout_range_bool *dest_bool = (struct layout_range_bool*)h;
2488 struct layout_range *dest = (struct layout_range*)h;
2490 BOOL changed = FALSE;
2492 switch (attr) {
2493 case LAYOUT_RANGE_ATTR_WEIGHT:
2494 changed = dest->weight != value->u.weight;
2495 dest->weight = value->u.weight;
2496 break;
2497 case LAYOUT_RANGE_ATTR_STYLE:
2498 changed = dest->style != value->u.style;
2499 dest->style = value->u.style;
2500 break;
2501 case LAYOUT_RANGE_ATTR_STRETCH:
2502 changed = dest->stretch != value->u.stretch;
2503 dest->stretch = value->u.stretch;
2504 break;
2505 case LAYOUT_RANGE_ATTR_FONTSIZE:
2506 changed = dest->fontsize != value->u.fontsize;
2507 dest->fontsize = value->u.fontsize;
2508 break;
2509 case LAYOUT_RANGE_ATTR_INLINE:
2510 changed = set_layout_range_iface_attr((IUnknown**)&dest->object, (IUnknown*)value->u.object);
2511 break;
2512 case LAYOUT_RANGE_ATTR_EFFECT:
2513 changed = set_layout_range_iface_attr(&dest_iface->iface, value->u.effect);
2514 break;
2515 case LAYOUT_RANGE_ATTR_UNDERLINE:
2516 changed = dest_bool->value != value->u.underline;
2517 dest_bool->value = value->u.underline;
2518 break;
2519 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2520 changed = dest_bool->value != value->u.strikethrough;
2521 dest_bool->value = value->u.strikethrough;
2522 break;
2523 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2524 changed = dest->pair_kerning != value->u.pair_kerning;
2525 dest->pair_kerning = value->u.pair_kerning;
2526 break;
2527 case LAYOUT_RANGE_ATTR_FONTCOLL:
2528 changed = set_layout_range_iface_attr((IUnknown**)&dest->collection, (IUnknown*)value->u.collection);
2529 break;
2530 case LAYOUT_RANGE_ATTR_LOCALE:
2531 changed = strcmpiW(dest->locale, value->u.locale) != 0;
2532 if (changed) {
2533 strcpyW(dest->locale, value->u.locale);
2534 strlwrW(dest->locale);
2536 break;
2537 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2538 changed = strcmpW(dest->fontfamily, value->u.fontfamily) != 0;
2539 if (changed) {
2540 heap_free(dest->fontfamily);
2541 dest->fontfamily = heap_strdupW(value->u.fontfamily);
2543 break;
2544 case LAYOUT_RANGE_ATTR_SPACING:
2545 changed = dest_spacing->leading != value->u.spacing.leading ||
2546 dest_spacing->trailing != value->u.spacing.trailing ||
2547 dest_spacing->min_advance != value->u.spacing.min_advance;
2548 dest_spacing->leading = value->u.spacing.leading;
2549 dest_spacing->trailing = value->u.spacing.trailing;
2550 dest_spacing->min_advance = value->u.spacing.min_advance;
2551 break;
2552 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2553 changed = set_layout_range_iface_attr(&dest_iface->iface, (IUnknown*)value->u.typography);
2554 break;
2555 default:
2559 return changed;
2562 static inline BOOL is_in_layout_range(const DWRITE_TEXT_RANGE *outer, const DWRITE_TEXT_RANGE *inner)
2564 return (inner->startPosition >= outer->startPosition) &&
2565 (inner->startPosition + inner->length <= outer->startPosition + outer->length);
2568 static inline HRESULT return_range(const struct layout_range_header *h, DWRITE_TEXT_RANGE *r)
2570 if (r) *r = h->range;
2571 return S_OK;
2574 /* Sets attribute value for given range, does all needed splitting/merging of existing ranges. */
2575 static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2577 struct layout_range_header *cur, *right, *left, *outer;
2578 BOOL changed = FALSE;
2579 struct list *ranges;
2580 DWRITE_TEXT_RANGE r;
2582 /* ignore zero length ranges */
2583 if (value->range.length == 0)
2584 return S_OK;
2586 /* select from ranges lists */
2587 switch (attr)
2589 case LAYOUT_RANGE_ATTR_WEIGHT:
2590 case LAYOUT_RANGE_ATTR_STYLE:
2591 case LAYOUT_RANGE_ATTR_STRETCH:
2592 case LAYOUT_RANGE_ATTR_FONTSIZE:
2593 case LAYOUT_RANGE_ATTR_INLINE:
2594 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2595 case LAYOUT_RANGE_ATTR_FONTCOLL:
2596 case LAYOUT_RANGE_ATTR_LOCALE:
2597 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2598 ranges = &layout->ranges;
2599 break;
2600 case LAYOUT_RANGE_ATTR_UNDERLINE:
2601 ranges = &layout->underline_ranges;
2602 break;
2603 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2604 ranges = &layout->strike_ranges;
2605 break;
2606 case LAYOUT_RANGE_ATTR_EFFECT:
2607 ranges = &layout->effects;
2608 break;
2609 case LAYOUT_RANGE_ATTR_SPACING:
2610 ranges = &layout->spacing;
2611 break;
2612 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2613 ranges = &layout->typographies;
2614 break;
2615 default:
2616 FIXME("unknown attr kind %d\n", attr);
2617 return E_FAIL;
2620 /* If new range is completely within existing range, split existing range in two */
2621 if ((outer = find_outer_range(ranges, &value->range))) {
2623 /* no need to add same range */
2624 if (is_same_layout_attrvalue(outer, attr, value))
2625 return S_OK;
2627 /* for matching range bounds just replace data */
2628 if (is_same_text_range(&outer->range, &value->range)) {
2629 changed = set_layout_range_attrval(outer, attr, value);
2630 goto done;
2633 /* add new range to the left */
2634 if (value->range.startPosition == outer->range.startPosition) {
2635 left = alloc_layout_range_from(outer, &value->range);
2636 if (!left) return E_OUTOFMEMORY;
2638 changed = set_layout_range_attrval(left, attr, value);
2639 list_add_before(&outer->entry, &left->entry);
2640 outer->range.startPosition += value->range.length;
2641 outer->range.length -= value->range.length;
2642 goto done;
2645 /* add new range to the right */
2646 if (value->range.startPosition + value->range.length == outer->range.startPosition + outer->range.length) {
2647 right = alloc_layout_range_from(outer, &value->range);
2648 if (!right) return E_OUTOFMEMORY;
2650 changed = set_layout_range_attrval(right, attr, value);
2651 list_add_after(&outer->entry, &right->entry);
2652 outer->range.length -= value->range.length;
2653 goto done;
2656 r.startPosition = value->range.startPosition + value->range.length;
2657 r.length = outer->range.length + outer->range.startPosition - r.startPosition;
2659 /* right part */
2660 right = alloc_layout_range_from(outer, &r);
2661 /* new range in the middle */
2662 cur = alloc_layout_range_from(outer, &value->range);
2663 if (!right || !cur) {
2664 free_layout_range(right);
2665 free_layout_range(cur);
2666 return E_OUTOFMEMORY;
2669 /* reuse container range as a left part */
2670 outer->range.length = value->range.startPosition - outer->range.startPosition;
2672 /* new part */
2673 set_layout_range_attrval(cur, attr, value);
2675 list_add_after(&outer->entry, &cur->entry);
2676 list_add_after(&cur->entry, &right->entry);
2678 layout->recompute = RECOMPUTE_EVERYTHING;
2679 return S_OK;
2682 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2683 Update all of them. */
2684 left = get_layout_range_header_by_pos(ranges, value->range.startPosition);
2685 if (left->range.startPosition == value->range.startPosition)
2686 changed = set_layout_range_attrval(left, attr, value);
2687 else /* need to split */ {
2688 r.startPosition = value->range.startPosition;
2689 r.length = left->range.length - value->range.startPosition + left->range.startPosition;
2690 left->range.length -= r.length;
2691 cur = alloc_layout_range_from(left, &r);
2692 changed = set_layout_range_attrval(cur, attr, value);
2693 list_add_after(&left->entry, &cur->entry);
2695 cur = LIST_ENTRY(list_next(ranges, &left->entry), struct layout_range_header, entry);
2697 /* for all existing ranges covered by new one update value */
2698 while (cur && is_in_layout_range(&value->range, &cur->range)) {
2699 changed |= set_layout_range_attrval(cur, attr, value);
2700 cur = LIST_ENTRY(list_next(ranges, &cur->entry), struct layout_range_header, entry);
2703 /* it's possible rightmost range intersects */
2704 if (cur && (cur->range.startPosition < value->range.startPosition + value->range.length)) {
2705 r.startPosition = cur->range.startPosition;
2706 r.length = value->range.startPosition + value->range.length - cur->range.startPosition;
2707 left = alloc_layout_range_from(cur, &r);
2708 changed |= set_layout_range_attrval(left, attr, value);
2709 cur->range.startPosition += left->range.length;
2710 cur->range.length -= left->range.length;
2711 list_add_before(&cur->entry, &left->entry);
2714 done:
2715 if (changed) {
2716 struct list *next, *i;
2718 layout->recompute = RECOMPUTE_EVERYTHING;
2719 i = list_head(ranges);
2720 while ((next = list_next(ranges, i))) {
2721 struct layout_range_header *next_range = LIST_ENTRY(next, struct layout_range_header, entry);
2723 cur = LIST_ENTRY(i, struct layout_range_header, entry);
2724 if (is_same_layout_attributes(cur, next_range)) {
2725 /* remove similar range */
2726 cur->range.length += next_range->range.length;
2727 list_remove(next);
2728 free_layout_range(next_range);
2730 else
2731 i = list_next(ranges, i);
2735 return S_OK;
2738 static inline const WCHAR *get_string_attribute_ptr(struct layout_range *range, enum layout_range_attr_kind kind)
2740 const WCHAR *str;
2742 switch (kind) {
2743 case LAYOUT_RANGE_ATTR_LOCALE:
2744 str = range->locale;
2745 break;
2746 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2747 str = range->fontfamily;
2748 break;
2749 default:
2750 str = NULL;
2753 return str;
2756 static HRESULT get_string_attribute_length(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2757 UINT32 *length, DWRITE_TEXT_RANGE *r)
2759 struct layout_range *range;
2760 const WCHAR *str;
2762 range = get_layout_range_by_pos(layout, position);
2763 if (!range) {
2764 *length = 0;
2765 return S_OK;
2768 str = get_string_attribute_ptr(range, kind);
2769 *length = strlenW(str);
2770 return return_range(&range->h, r);
2773 static HRESULT get_string_attribute_value(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2774 WCHAR *ret, UINT32 length, DWRITE_TEXT_RANGE *r)
2776 struct layout_range *range;
2777 const WCHAR *str;
2779 if (length == 0)
2780 return E_INVALIDARG;
2782 ret[0] = 0;
2783 range = get_layout_range_by_pos(layout, position);
2784 if (!range)
2785 return E_INVALIDARG;
2787 str = get_string_attribute_ptr(range, kind);
2788 if (length < strlenW(str) + 1)
2789 return E_NOT_SUFFICIENT_BUFFER;
2791 strcpyW(ret, str);
2792 return return_range(&range->h, r);
2795 static HRESULT WINAPI dwritetextlayout_QueryInterface(IDWriteTextLayout4 *iface, REFIID riid, void **obj)
2797 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2799 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2801 *obj = NULL;
2803 if (IsEqualIID(riid, &IID_IDWriteTextLayout4) ||
2804 IsEqualIID(riid, &IID_IDWriteTextLayout3) ||
2805 IsEqualIID(riid, &IID_IDWriteTextLayout2) ||
2806 IsEqualIID(riid, &IID_IDWriteTextLayout1) ||
2807 IsEqualIID(riid, &IID_IDWriteTextLayout) ||
2808 IsEqualIID(riid, &IID_IUnknown))
2810 *obj = iface;
2812 else if (IsEqualIID(riid, &IID_IDWriteTextFormat3) ||
2813 IsEqualIID(riid, &IID_IDWriteTextFormat2) ||
2814 IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
2815 IsEqualIID(riid, &IID_IDWriteTextFormat))
2817 *obj = &layout->IDWriteTextFormat3_iface;
2820 if (*obj) {
2821 IDWriteTextLayout4_AddRef(iface);
2822 return S_OK;
2825 WARN("%s not implemented.\n", debugstr_guid(riid));
2827 return E_NOINTERFACE;
2830 static ULONG WINAPI dwritetextlayout_AddRef(IDWriteTextLayout4 *iface)
2832 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2833 ULONG refcount = InterlockedIncrement(&layout->refcount);
2835 TRACE("%p, refcount %u.\n", iface, refcount);
2837 return refcount;
2840 static ULONG WINAPI dwritetextlayout_Release(IDWriteTextLayout4 *iface)
2842 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2843 ULONG refcount = InterlockedDecrement(&layout->refcount);
2845 TRACE("%p, refcount %u.\n", iface, refcount);
2847 if (!refcount)
2849 IDWriteFactory7_Release(layout->factory);
2850 free_layout_ranges_list(layout);
2851 free_layout_eruns(layout);
2852 free_layout_runs(layout);
2853 release_format_data(&layout->format);
2854 heap_free(layout->nominal_breakpoints);
2855 heap_free(layout->actual_breakpoints);
2856 heap_free(layout->clustermetrics);
2857 heap_free(layout->clusters);
2858 heap_free(layout->lines);
2859 heap_free(layout->str);
2860 heap_free(layout);
2863 return refcount;
2866 static HRESULT WINAPI dwritetextlayout_SetTextAlignment(IDWriteTextLayout4 *iface, DWRITE_TEXT_ALIGNMENT alignment)
2868 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2869 return IDWriteTextFormat3_SetTextAlignment(&layout->IDWriteTextFormat3_iface, alignment);
2872 static HRESULT WINAPI dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout4 *iface,
2873 DWRITE_PARAGRAPH_ALIGNMENT alignment)
2875 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2876 return IDWriteTextFormat3_SetParagraphAlignment(&layout->IDWriteTextFormat3_iface, alignment);
2879 static HRESULT WINAPI dwritetextlayout_SetWordWrapping(IDWriteTextLayout4 *iface, DWRITE_WORD_WRAPPING wrapping)
2881 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2882 return IDWriteTextFormat3_SetWordWrapping(&layout->IDWriteTextFormat3_iface, wrapping);
2885 static HRESULT WINAPI dwritetextlayout_SetReadingDirection(IDWriteTextLayout4 *iface,
2886 DWRITE_READING_DIRECTION direction)
2888 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2889 return IDWriteTextFormat3_SetReadingDirection(&layout->IDWriteTextFormat3_iface, direction);
2892 static HRESULT WINAPI dwritetextlayout_SetFlowDirection(IDWriteTextLayout4 *iface, DWRITE_FLOW_DIRECTION direction)
2894 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2895 return IDWriteTextFormat3_SetFlowDirection(&layout->IDWriteTextFormat3_iface, direction);
2898 static HRESULT WINAPI dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout4 *iface, FLOAT tabstop)
2900 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2901 return IDWriteTextFormat3_SetIncrementalTabStop(&layout->IDWriteTextFormat3_iface, tabstop);
2904 static HRESULT WINAPI dwritetextlayout_SetTrimming(IDWriteTextLayout4 *iface, DWRITE_TRIMMING const *trimming,
2905 IDWriteInlineObject *trimming_sign)
2907 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2908 return IDWriteTextFormat3_SetTrimming(&layout->IDWriteTextFormat3_iface, trimming, trimming_sign);
2911 static HRESULT WINAPI dwritetextlayout_SetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING_METHOD spacing,
2912 FLOAT line_spacing, FLOAT baseline)
2914 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2915 return IDWriteTextFormat1_SetLineSpacing((IDWriteTextFormat1 *)&layout->IDWriteTextFormat3_iface, spacing,
2916 line_spacing, baseline);
2919 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextlayout_GetTextAlignment(IDWriteTextLayout4 *iface)
2921 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2922 return IDWriteTextFormat3_GetTextAlignment(&layout->IDWriteTextFormat3_iface);
2925 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout4 *iface)
2927 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2928 return IDWriteTextFormat3_GetParagraphAlignment(&layout->IDWriteTextFormat3_iface);
2931 static DWRITE_WORD_WRAPPING WINAPI dwritetextlayout_GetWordWrapping(IDWriteTextLayout4 *iface)
2933 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2934 return IDWriteTextFormat3_GetWordWrapping(&layout->IDWriteTextFormat3_iface);
2937 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_GetReadingDirection(IDWriteTextLayout4 *iface)
2939 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2940 return IDWriteTextFormat3_GetReadingDirection(&layout->IDWriteTextFormat3_iface);
2943 static DWRITE_FLOW_DIRECTION WINAPI dwritetextlayout_GetFlowDirection(IDWriteTextLayout4 *iface)
2945 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2946 return IDWriteTextFormat3_GetFlowDirection(&layout->IDWriteTextFormat3_iface);
2949 static FLOAT WINAPI dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout4 *iface)
2951 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2952 return IDWriteTextFormat3_GetIncrementalTabStop(&layout->IDWriteTextFormat3_iface);
2955 static HRESULT WINAPI dwritetextlayout_GetTrimming(IDWriteTextLayout4 *iface, DWRITE_TRIMMING *options,
2956 IDWriteInlineObject **trimming_sign)
2958 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2959 return IDWriteTextFormat3_GetTrimming(&layout->IDWriteTextFormat3_iface, options, trimming_sign);
2962 static HRESULT WINAPI dwritetextlayout_GetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING_METHOD *method,
2963 FLOAT *spacing, FLOAT *baseline)
2965 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2966 return IDWriteTextFormat_GetLineSpacing((IDWriteTextFormat *)&layout->IDWriteTextFormat3_iface, method,
2967 spacing, baseline);
2970 static HRESULT WINAPI dwritetextlayout_GetFontCollection(IDWriteTextLayout4 *iface, IDWriteFontCollection **collection)
2972 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2973 return IDWriteTextFormat3_GetFontCollection(&layout->IDWriteTextFormat3_iface, collection);
2976 static UINT32 WINAPI dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout4 *iface)
2978 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2979 return IDWriteTextFormat3_GetFontFamilyNameLength(&layout->IDWriteTextFormat3_iface);
2982 static HRESULT WINAPI dwritetextlayout_GetFontFamilyName(IDWriteTextLayout4 *iface, WCHAR *name, UINT32 size)
2984 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2985 return IDWriteTextFormat3_GetFontFamilyName(&layout->IDWriteTextFormat3_iface, name, size);
2988 static DWRITE_FONT_WEIGHT WINAPI dwritetextlayout_GetFontWeight(IDWriteTextLayout4 *iface)
2990 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2991 return IDWriteTextFormat3_GetFontWeight(&layout->IDWriteTextFormat3_iface);
2994 static DWRITE_FONT_STYLE WINAPI dwritetextlayout_GetFontStyle(IDWriteTextLayout4 *iface)
2996 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
2997 return IDWriteTextFormat3_GetFontStyle(&layout->IDWriteTextFormat3_iface);
3000 static DWRITE_FONT_STRETCH WINAPI dwritetextlayout_GetFontStretch(IDWriteTextLayout4 *iface)
3002 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3003 return IDWriteTextFormat3_GetFontStretch(&layout->IDWriteTextFormat3_iface);
3006 static FLOAT WINAPI dwritetextlayout_GetFontSize(IDWriteTextLayout4 *iface)
3008 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3009 return IDWriteTextFormat3_GetFontSize(&layout->IDWriteTextFormat3_iface);
3012 static UINT32 WINAPI dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout4 *iface)
3014 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3015 return IDWriteTextFormat3_GetLocaleNameLength(&layout->IDWriteTextFormat3_iface);
3018 static HRESULT WINAPI dwritetextlayout_GetLocaleName(IDWriteTextLayout4 *iface, WCHAR *name, UINT32 size)
3020 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3021 return IDWriteTextFormat3_GetLocaleName(&layout->IDWriteTextFormat3_iface, name, size);
3024 static HRESULT WINAPI dwritetextlayout_SetMaxWidth(IDWriteTextLayout4 *iface, FLOAT maxWidth)
3026 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3027 BOOL changed;
3029 TRACE("%p, %.8e.\n", iface, maxWidth);
3031 if (maxWidth < 0.0f)
3032 return E_INVALIDARG;
3034 changed = layout->metrics.layoutWidth != maxWidth;
3035 layout->metrics.layoutWidth = maxWidth;
3037 if (changed)
3038 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
3039 return S_OK;
3042 static HRESULT WINAPI dwritetextlayout_SetMaxHeight(IDWriteTextLayout4 *iface, FLOAT maxHeight)
3044 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3045 BOOL changed;
3047 TRACE("%p, %.8e.\n", iface, maxHeight);
3049 if (maxHeight < 0.0f)
3050 return E_INVALIDARG;
3052 changed = layout->metrics.layoutHeight != maxHeight;
3053 layout->metrics.layoutHeight = maxHeight;
3055 if (changed)
3056 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
3057 return S_OK;
3060 static HRESULT WINAPI dwritetextlayout_SetFontCollection(IDWriteTextLayout4 *iface, IDWriteFontCollection *collection,
3061 DWRITE_TEXT_RANGE range)
3063 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3064 struct layout_range_attr_value value;
3066 TRACE("%p, %p, %s.\n", iface, collection, debugstr_range(&range));
3068 value.range = range;
3069 value.u.collection = collection;
3070 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_FONTCOLL, &value);
3073 static HRESULT WINAPI dwritetextlayout_SetFontFamilyName(IDWriteTextLayout4 *iface, WCHAR const *name,
3074 DWRITE_TEXT_RANGE range)
3076 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3077 struct layout_range_attr_value value;
3079 TRACE("%p, %s, %s.\n", iface, debugstr_w(name), debugstr_range(&range));
3081 if (!name)
3082 return E_INVALIDARG;
3084 value.range = range;
3085 value.u.fontfamily = name;
3086 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_FONTFAMILY, &value);
3089 static HRESULT WINAPI dwritetextlayout_SetFontWeight(IDWriteTextLayout4 *iface, DWRITE_FONT_WEIGHT weight,
3090 DWRITE_TEXT_RANGE range)
3092 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3093 struct layout_range_attr_value value;
3095 TRACE("%p, %d, %s.\n", iface, weight, debugstr_range(&range));
3097 if ((UINT32)weight > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
3098 return E_INVALIDARG;
3100 value.range = range;
3101 value.u.weight = weight;
3102 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_WEIGHT, &value);
3105 static HRESULT WINAPI dwritetextlayout_SetFontStyle(IDWriteTextLayout4 *iface, DWRITE_FONT_STYLE style,
3106 DWRITE_TEXT_RANGE range)
3108 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3109 struct layout_range_attr_value value;
3111 TRACE("%p, %d, %s.\n", iface, style, debugstr_range(&range));
3113 if ((UINT32)style > DWRITE_FONT_STYLE_ITALIC)
3114 return E_INVALIDARG;
3116 value.range = range;
3117 value.u.style = style;
3118 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_STYLE, &value);
3121 static HRESULT WINAPI dwritetextlayout_SetFontStretch(IDWriteTextLayout4 *iface, DWRITE_FONT_STRETCH stretch,
3122 DWRITE_TEXT_RANGE range)
3124 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3125 struct layout_range_attr_value value;
3127 TRACE("%p, %d, %s.\n", iface, stretch, debugstr_range(&range));
3129 if (stretch == DWRITE_FONT_STRETCH_UNDEFINED || (UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
3130 return E_INVALIDARG;
3132 value.range = range;
3133 value.u.stretch = stretch;
3134 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_STRETCH, &value);
3137 static HRESULT WINAPI dwritetextlayout_SetFontSize(IDWriteTextLayout4 *iface, FLOAT size, DWRITE_TEXT_RANGE range)
3139 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3140 struct layout_range_attr_value value;
3142 TRACE("%p, %.8e, %s.\n", iface, size, debugstr_range(&range));
3144 if (size <= 0.0f)
3145 return E_INVALIDARG;
3147 value.range = range;
3148 value.u.fontsize = size;
3149 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_FONTSIZE, &value);
3152 static HRESULT WINAPI dwritetextlayout_SetUnderline(IDWriteTextLayout4 *iface, BOOL underline, DWRITE_TEXT_RANGE range)
3154 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3155 struct layout_range_attr_value value;
3157 TRACE("%p, %d, %s.\n", iface, underline, debugstr_range(&range));
3159 value.range = range;
3160 value.u.underline = underline;
3161 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_UNDERLINE, &value);
3164 static HRESULT WINAPI dwritetextlayout_SetStrikethrough(IDWriteTextLayout4 *iface, BOOL strikethrough,
3165 DWRITE_TEXT_RANGE range)
3167 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3168 struct layout_range_attr_value value;
3170 TRACE("%p, %d, %s.\n", iface, strikethrough, debugstr_range(&range));
3172 value.range = range;
3173 value.u.strikethrough = strikethrough;
3174 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_STRIKETHROUGH, &value);
3177 static HRESULT WINAPI dwritetextlayout_SetDrawingEffect(IDWriteTextLayout4 *iface, IUnknown* effect,
3178 DWRITE_TEXT_RANGE range)
3180 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3181 struct layout_range_attr_value value;
3183 TRACE("%p, %p, %s.\n", iface, effect, debugstr_range(&range));
3185 value.range = range;
3186 value.u.effect = effect;
3187 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_EFFECT, &value);
3190 static HRESULT WINAPI dwritetextlayout_SetInlineObject(IDWriteTextLayout4 *iface, IDWriteInlineObject *object,
3191 DWRITE_TEXT_RANGE range)
3193 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3194 struct layout_range_attr_value value;
3196 TRACE("%p, %p, %s.\n", iface, object, debugstr_range(&range));
3198 value.range = range;
3199 value.u.object = object;
3200 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_INLINE, &value);
3203 static HRESULT WINAPI dwritetextlayout_SetTypography(IDWriteTextLayout4 *iface, IDWriteTypography *typography,
3204 DWRITE_TEXT_RANGE range)
3206 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3207 struct layout_range_attr_value value;
3209 TRACE("%p, %p, %s.\n", iface, typography, debugstr_range(&range));
3211 value.range = range;
3212 value.u.typography = typography;
3213 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_TYPOGRAPHY, &value);
3216 static HRESULT WINAPI dwritetextlayout_SetLocaleName(IDWriteTextLayout4 *iface, WCHAR const* locale,
3217 DWRITE_TEXT_RANGE range)
3219 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3220 struct layout_range_attr_value value;
3222 TRACE("%p, %s, %s.\n", iface, debugstr_w(locale), debugstr_range(&range));
3224 if (!locale || strlenW(locale) > LOCALE_NAME_MAX_LENGTH-1)
3225 return E_INVALIDARG;
3227 value.range = range;
3228 value.u.locale = locale;
3229 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_LOCALE, &value);
3232 static FLOAT WINAPI dwritetextlayout_GetMaxWidth(IDWriteTextLayout4 *iface)
3234 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3236 TRACE("%p.\n", iface);
3238 return layout->metrics.layoutWidth;
3241 static FLOAT WINAPI dwritetextlayout_GetMaxHeight(IDWriteTextLayout4 *iface)
3243 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3245 TRACE("%p.\n", iface);
3247 return layout->metrics.layoutHeight;
3250 static HRESULT WINAPI dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout4 *iface, UINT32 position,
3251 IDWriteFontCollection **collection, DWRITE_TEXT_RANGE *r)
3253 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3254 struct layout_range *range;
3256 TRACE("%p, %u, %p, %p.\n", iface, position, collection, r);
3258 if (position >= layout->len)
3259 return S_OK;
3261 range = get_layout_range_by_pos(layout, position);
3262 *collection = range->collection;
3263 if (*collection)
3264 IDWriteFontCollection_AddRef(*collection);
3266 return return_range(&range->h, r);
3269 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout4 *iface,
3270 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
3272 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3274 TRACE("%p, %d, %p, %p.\n", iface, position, length, r);
3276 return get_string_attribute_length(layout, LAYOUT_RANGE_ATTR_FONTFAMILY, position, length, r);
3279 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout4 *iface,
3280 UINT32 position, WCHAR *name, UINT32 length, DWRITE_TEXT_RANGE *r)
3282 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3284 TRACE("%p, %u, %p, %u, %p.\n", iface, position, name, length, r);
3286 return get_string_attribute_value(layout, LAYOUT_RANGE_ATTR_FONTFAMILY, position, name, length, r);
3289 static HRESULT WINAPI dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout4 *iface,
3290 UINT32 position, DWRITE_FONT_WEIGHT *weight, DWRITE_TEXT_RANGE *r)
3292 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3293 struct layout_range *range;
3295 TRACE("%p, %u, %p, %p.\n", iface, position, weight, r);
3297 if (position >= layout->len)
3298 return S_OK;
3300 range = get_layout_range_by_pos(layout, position);
3301 *weight = range->weight;
3303 return return_range(&range->h, r);
3306 static HRESULT WINAPI dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout4 *iface,
3307 UINT32 position, DWRITE_FONT_STYLE *style, DWRITE_TEXT_RANGE *r)
3309 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3310 struct layout_range *range;
3312 TRACE("%p, %u, %p, %p.\n", iface, position, style, r);
3314 range = get_layout_range_by_pos(layout, position);
3315 *style = range->style;
3316 return return_range(&range->h, r);
3319 static HRESULT WINAPI dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout4 *iface,
3320 UINT32 position, DWRITE_FONT_STRETCH *stretch, DWRITE_TEXT_RANGE *r)
3322 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3323 struct layout_range *range;
3325 TRACE("%p, %u, %p, %p.\n", iface, position, stretch, r);
3327 range = get_layout_range_by_pos(layout, position);
3328 *stretch = range->stretch;
3329 return return_range(&range->h, r);
3332 static HRESULT WINAPI dwritetextlayout_layout_GetFontSize(IDWriteTextLayout4 *iface,
3333 UINT32 position, FLOAT *size, DWRITE_TEXT_RANGE *r)
3335 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3336 struct layout_range *range;
3338 TRACE("%p, %u, %p, %p.\n", iface, position, size, r);
3340 range = get_layout_range_by_pos(layout, position);
3341 *size = range->fontsize;
3342 return return_range(&range->h, r);
3345 static HRESULT WINAPI dwritetextlayout_GetUnderline(IDWriteTextLayout4 *iface,
3346 UINT32 position, BOOL *underline, DWRITE_TEXT_RANGE *r)
3348 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3349 struct layout_range_bool *range;
3351 TRACE("%p, %u, %p, %p.\n", iface, position, underline, r);
3353 range = (struct layout_range_bool *)get_layout_range_header_by_pos(&layout->underline_ranges, position);
3354 *underline = range->value;
3356 return return_range(&range->h, r);
3359 static HRESULT WINAPI dwritetextlayout_GetStrikethrough(IDWriteTextLayout4 *iface,
3360 UINT32 position, BOOL *strikethrough, DWRITE_TEXT_RANGE *r)
3362 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3363 struct layout_range_bool *range;
3365 TRACE("%p, %u, %p, %p.\n", iface, position, strikethrough, r);
3367 range = (struct layout_range_bool *)get_layout_range_header_by_pos(&layout->strike_ranges, position);
3368 *strikethrough = range->value;
3370 return return_range(&range->h, r);
3373 static HRESULT WINAPI dwritetextlayout_GetDrawingEffect(IDWriteTextLayout4 *iface,
3374 UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r)
3376 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3377 struct layout_range_iface *range;
3379 TRACE("%p, %u, %p, %p.\n", iface, position, effect, r);
3381 range = (struct layout_range_iface *)get_layout_range_header_by_pos(&layout->effects, position);
3382 *effect = range->iface;
3383 if (*effect)
3384 IUnknown_AddRef(*effect);
3386 return return_range(&range->h, r);
3389 static HRESULT WINAPI dwritetextlayout_GetInlineObject(IDWriteTextLayout4 *iface,
3390 UINT32 position, IDWriteInlineObject **object, DWRITE_TEXT_RANGE *r)
3392 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3393 struct layout_range *range;
3395 TRACE("%p, %u, %p, %p.\n", iface, position, object, r);
3397 if (position >= layout->len)
3398 return S_OK;
3400 range = get_layout_range_by_pos(layout, position);
3401 *object = range->object;
3402 if (*object)
3403 IDWriteInlineObject_AddRef(*object);
3405 return return_range(&range->h, r);
3408 static HRESULT WINAPI dwritetextlayout_GetTypography(IDWriteTextLayout4 *iface,
3409 UINT32 position, IDWriteTypography** typography, DWRITE_TEXT_RANGE *r)
3411 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3412 struct layout_range_iface *range;
3414 TRACE("%p, %u, %p, %p.\n", iface, position, typography, r);
3416 range = (struct layout_range_iface *)get_layout_range_header_by_pos(&layout->typographies, position);
3417 *typography = (IDWriteTypography *)range->iface;
3418 if (*typography)
3419 IDWriteTypography_AddRef(*typography);
3421 return return_range(&range->h, r);
3424 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout4 *iface,
3425 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
3427 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3429 TRACE("%p, %u, %p, %p.\n", iface, position, length, r);
3431 return get_string_attribute_length(layout, LAYOUT_RANGE_ATTR_LOCALE, position, length, r);
3434 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout4 *iface,
3435 UINT32 position, WCHAR *locale, UINT32 length, DWRITE_TEXT_RANGE *r)
3437 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3439 TRACE("%p, %u, %p, %u, %p.\n", iface, position, locale, length, r);
3441 return get_string_attribute_value(layout, LAYOUT_RANGE_ATTR_LOCALE, position, locale, length, r);
3444 static inline FLOAT renderer_apply_snapping(FLOAT coord, BOOL skiptransform, FLOAT ppdip, FLOAT det,
3445 const DWRITE_MATRIX *m)
3447 D2D1_POINT_2F vec, vec2;
3449 if (!skiptransform) {
3450 /* apply transform */
3451 vec.x = 0.0f;
3452 vec.y = coord * ppdip;
3454 vec2.x = m->m11 * vec.x + m->m21 * vec.y + m->dx;
3455 vec2.y = m->m12 * vec.x + m->m22 * vec.y + m->dy;
3457 /* snap */
3458 vec2.x = floorf(vec2.x + 0.5f);
3459 vec2.y = floorf(vec2.y + 0.5f);
3461 /* apply inverted transform, we don't care about X component at this point */
3462 vec.y = (-m->m12 * vec2.x + m->m11 * vec2.y - (m->m11 * m->dy - m->m12 * m->dx)) / det;
3463 vec.y /= ppdip;
3465 else
3466 vec.y = floorf(coord * ppdip + 0.5f) / ppdip;
3468 return vec.y;
3471 static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout4 *iface,
3472 void *context, IDWriteTextRenderer* renderer, FLOAT origin_x, FLOAT origin_y)
3474 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3475 BOOL disabled = FALSE, skiptransform = FALSE;
3476 struct layout_effective_inline *inlineobject;
3477 struct layout_effective_run *run;
3478 struct layout_strikethrough *s;
3479 struct layout_underline *u;
3480 FLOAT det = 0.0f, ppdip = 0.0f;
3481 DWRITE_MATRIX m = { 0 };
3482 HRESULT hr;
3484 TRACE("%p, %p, %p, %.8e, %.8e.\n", iface, context, renderer, origin_x, origin_y);
3486 hr = layout_compute_effective_runs(layout);
3487 if (FAILED(hr))
3488 return hr;
3490 hr = IDWriteTextRenderer_IsPixelSnappingDisabled(renderer, context, &disabled);
3491 if (FAILED(hr))
3492 return hr;
3494 if (!disabled) {
3495 hr = IDWriteTextRenderer_GetPixelsPerDip(renderer, context, &ppdip);
3496 if (FAILED(hr))
3497 return hr;
3499 hr = IDWriteTextRenderer_GetCurrentTransform(renderer, context, &m);
3500 if (FAILED(hr))
3501 return hr;
3503 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
3504 if (ppdip <= 0.0f ||
3505 (m.m11 * m.m22 != 0.0f && (m.m12 != 0.0f || m.m21 != 0.0f)) ||
3506 (m.m12 * m.m21 != 0.0f && (m.m11 != 0.0f || m.m22 != 0.0f)))
3507 disabled = TRUE;
3508 else
3509 skiptransform = should_skip_transform(&m, &det);
3512 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
3513 /* 1. Regular runs */
3514 LIST_FOR_EACH_ENTRY(run, &layout->eruns, struct layout_effective_run, entry)
3516 const struct regular_layout_run *regular = &run->run->u.regular;
3517 UINT32 start_glyph = regular->clustermap[run->start];
3518 DWRITE_GLYPH_RUN_DESCRIPTION descr;
3519 DWRITE_GLYPH_RUN glyph_run;
3521 /* Everything but cluster map will be reused from nominal run, as we only need
3522 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
3523 it can't be reused because it has to start with 0 index for each reported run. */
3524 glyph_run = regular->run;
3525 glyph_run.glyphCount = run->glyphcount;
3527 /* fixup glyph data arrays */
3528 glyph_run.glyphIndices += start_glyph;
3529 glyph_run.glyphAdvances += start_glyph;
3530 glyph_run.glyphOffsets += start_glyph;
3532 /* description */
3533 descr = regular->descr;
3534 descr.stringLength = run->length;
3535 descr.string += run->start;
3536 descr.clusterMap = run->clustermap;
3537 descr.textPosition += run->start;
3539 /* return value is ignored */
3540 IDWriteTextRenderer_DrawGlyphRun(renderer,
3541 context,
3542 run->origin.x + run->align_dx + origin_x,
3543 SNAP_COORD(run->origin.y + origin_y),
3544 layout->measuringmode,
3545 &glyph_run,
3546 &descr,
3547 run->effect);
3550 /* 2. Inline objects */
3551 LIST_FOR_EACH_ENTRY(inlineobject, &layout->inlineobjects, struct layout_effective_inline, entry)
3553 IDWriteTextRenderer_DrawInlineObject(renderer,
3554 context,
3555 inlineobject->origin.x + inlineobject->align_dx + origin_x,
3556 SNAP_COORD(inlineobject->origin.y + origin_y),
3557 inlineobject->object,
3558 inlineobject->is_sideways,
3559 inlineobject->is_rtl,
3560 inlineobject->effect);
3563 /* 3. Underlines */
3564 LIST_FOR_EACH_ENTRY(u, &layout->underlines, struct layout_underline, entry)
3566 IDWriteTextRenderer_DrawUnderline(renderer,
3567 context,
3568 /* horizontal underline always grows from left to right, width is always added to origin regardless of run direction */
3569 (is_run_rtl(u->run) ? u->run->origin.x - u->run->width : u->run->origin.x) + u->run->align_dx + origin_x,
3570 SNAP_COORD(u->run->origin.y + origin_y),
3571 &u->u,
3572 u->run->effect);
3575 /* 4. Strikethrough */
3576 LIST_FOR_EACH_ENTRY(s, &layout->strikethrough, struct layout_strikethrough, entry)
3578 IDWriteTextRenderer_DrawStrikethrough(renderer,
3579 context,
3580 s->run->origin.x + s->run->align_dx + origin_x,
3581 SNAP_COORD(s->run->origin.y + origin_y),
3582 &s->s,
3583 s->run->effect);
3585 #undef SNAP_COORD
3587 return S_OK;
3590 static HRESULT WINAPI dwritetextlayout_GetLineMetrics(IDWriteTextLayout4 *iface,
3591 DWRITE_LINE_METRICS *metrics, UINT32 max_count, UINT32 *count)
3593 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3594 unsigned int line_count;
3595 HRESULT hr;
3596 size_t i;
3598 TRACE("%p, %p, %u, %p.\n", iface, metrics, max_count, count);
3600 if (FAILED(hr = layout_compute_effective_runs(layout)))
3601 return hr;
3603 if (metrics)
3605 line_count = min(max_count, layout->metrics.lineCount);
3606 for (i = 0; i < line_count; ++i)
3607 memcpy(&metrics[i], &layout->lines[i].metrics, sizeof(*metrics));
3610 *count = layout->metrics.lineCount;
3611 return max_count >= layout->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3614 static HRESULT layout_update_metrics(struct dwrite_textlayout *layout)
3616 return layout_compute_effective_runs(layout);
3619 static HRESULT WINAPI dwritetextlayout_GetMetrics(IDWriteTextLayout4 *iface, DWRITE_TEXT_METRICS *metrics)
3621 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3622 HRESULT hr;
3624 TRACE("%p, %p.\n", iface, metrics);
3626 hr = layout_update_metrics(layout);
3627 if (hr == S_OK)
3628 memcpy(metrics, &layout->metrics, sizeof(*metrics));
3630 return hr;
3633 static void d2d_rect_offset(D2D1_RECT_F *rect, FLOAT x, FLOAT y)
3635 rect->left += x;
3636 rect->right += x;
3637 rect->top += y;
3638 rect->bottom += y;
3641 static BOOL d2d_rect_is_empty(const D2D1_RECT_F *rect)
3643 return ((rect->left >= rect->right) || (rect->top >= rect->bottom));
3646 static void d2d_rect_union(D2D1_RECT_F *dst, const D2D1_RECT_F *src)
3648 if (d2d_rect_is_empty(dst)) {
3649 if (d2d_rect_is_empty(src)) {
3650 dst->left = dst->right = dst->top = dst->bottom = 0.0f;
3651 return;
3653 else
3654 *dst = *src;
3656 else {
3657 if (!d2d_rect_is_empty(src)) {
3658 dst->left = min(dst->left, src->left);
3659 dst->right = max(dst->right, src->right);
3660 dst->top = min(dst->top, src->top);
3661 dst->bottom = max(dst->bottom, src->bottom);
3666 static void layout_get_erun_bbox(struct dwrite_textlayout *layout, struct layout_effective_run *run, D2D1_RECT_F *bbox)
3668 const struct regular_layout_run *regular = &run->run->u.regular;
3669 UINT32 start_glyph = regular->clustermap[run->start];
3670 const DWRITE_GLYPH_RUN *glyph_run = &regular->run;
3671 D2D1_POINT_2F origin = { 0 };
3672 float rtl_factor;
3673 UINT32 i;
3675 if (run->bbox.top == run->bbox.bottom)
3677 struct dwrite_glyphbitmap glyph_bitmap;
3678 RECT *bbox;
3680 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
3681 glyph_bitmap.fontface = (IDWriteFontFace4 *)glyph_run->fontFace;
3682 glyph_bitmap.simulations = IDWriteFontFace_GetSimulations(glyph_run->fontFace);
3683 glyph_bitmap.emsize = glyph_run->fontEmSize;
3684 glyph_bitmap.nohint = layout->measuringmode == DWRITE_MEASURING_MODE_NATURAL;
3686 bbox = &glyph_bitmap.bbox;
3688 rtl_factor = glyph_run->bidiLevel & 1 ? -1.0f : 1.0f;
3689 for (i = 0; i < run->glyphcount; i++) {
3690 D2D1_RECT_F glyph_bbox;
3692 /* FIXME: take care of vertical/rtl */
3693 if (glyph_run->bidiLevel & 1)
3694 origin.x -= glyph_run->glyphAdvances[i + start_glyph];
3696 glyph_bitmap.glyph = glyph_run->glyphIndices[i + start_glyph];
3697 freetype_get_glyph_bbox(&glyph_bitmap);
3699 glyph_bbox.left = bbox->left;
3700 glyph_bbox.top = bbox->top;
3701 glyph_bbox.right = bbox->right;
3702 glyph_bbox.bottom = bbox->bottom;
3704 d2d_rect_offset(&glyph_bbox, origin.x + rtl_factor * glyph_run->glyphOffsets[i + start_glyph].advanceOffset,
3705 origin.y - glyph_run->glyphOffsets[i + start_glyph].ascenderOffset);
3707 d2d_rect_union(&run->bbox, &glyph_bbox);
3709 if (!(glyph_run->bidiLevel & 1))
3710 origin.x += glyph_run->glyphAdvances[i + start_glyph];
3714 *bbox = run->bbox;
3715 d2d_rect_offset(bbox, run->origin.x + run->align_dx, run->origin.y);
3718 static void layout_get_inlineobj_bbox(struct dwrite_textlayout *layout, struct layout_effective_inline *run,
3719 D2D1_RECT_F *bbox)
3721 DWRITE_OVERHANG_METRICS overhang_metrics = { 0 };
3722 DWRITE_INLINE_OBJECT_METRICS metrics = { 0 };
3723 HRESULT hr;
3725 if (FAILED(hr = IDWriteInlineObject_GetMetrics(run->object, &metrics))) {
3726 WARN("Failed to get inline object metrics, hr %#x.\n", hr);
3727 memset(bbox, 0, sizeof(*bbox));
3728 return;
3731 bbox->left = run->origin.x + run->align_dx;
3732 bbox->right = bbox->left + metrics.width;
3733 bbox->top = run->origin.y;
3734 bbox->bottom = bbox->top + metrics.height;
3736 IDWriteInlineObject_GetOverhangMetrics(run->object, &overhang_metrics);
3738 bbox->left -= overhang_metrics.left;
3739 bbox->right += overhang_metrics.right;
3740 bbox->top -= overhang_metrics.top;
3741 bbox->bottom += overhang_metrics.bottom;
3744 static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout4 *iface,
3745 DWRITE_OVERHANG_METRICS *overhangs)
3747 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3748 struct layout_effective_inline *inline_run;
3749 struct layout_effective_run *run;
3750 D2D1_RECT_F bbox = { 0 };
3751 HRESULT hr;
3753 TRACE("%p, %p.\n", iface, overhangs);
3755 memset(overhangs, 0, sizeof(*overhangs));
3757 if (!(layout->recompute & RECOMPUTE_OVERHANGS))
3759 *overhangs = layout->overhangs;
3760 return S_OK;
3763 hr = layout_compute_effective_runs(layout);
3764 if (FAILED(hr))
3765 return hr;
3767 LIST_FOR_EACH_ENTRY(run, &layout->eruns, struct layout_effective_run, entry)
3769 D2D1_RECT_F run_bbox;
3771 layout_get_erun_bbox(layout, run, &run_bbox);
3772 d2d_rect_union(&bbox, &run_bbox);
3775 LIST_FOR_EACH_ENTRY(inline_run, &layout->inlineobjects, struct layout_effective_inline, entry)
3777 D2D1_RECT_F object_bbox;
3779 layout_get_inlineobj_bbox(layout, inline_run, &object_bbox);
3780 d2d_rect_union(&bbox, &object_bbox);
3783 /* Deltas from layout box. */
3784 layout->overhangs.left = -bbox.left;
3785 layout->overhangs.top = -bbox.top;
3786 layout->overhangs.right = bbox.right - layout->metrics.layoutWidth;
3787 layout->overhangs.bottom = bbox.bottom - layout->metrics.layoutHeight;
3788 layout->recompute &= ~RECOMPUTE_OVERHANGS;
3790 *overhangs = layout->overhangs;
3792 return S_OK;
3795 static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout4 *iface,
3796 DWRITE_CLUSTER_METRICS *metrics, UINT32 max_count, UINT32 *count)
3798 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3799 HRESULT hr;
3801 TRACE("%p, %p, %u, %p.\n", iface, metrics, max_count, count);
3803 hr = layout_compute(layout);
3804 if (FAILED(hr))
3805 return hr;
3807 if (metrics)
3808 memcpy(metrics, layout->clustermetrics, sizeof(DWRITE_CLUSTER_METRICS) * min(max_count, layout->cluster_count));
3810 *count = layout->cluster_count;
3811 return max_count >= layout->cluster_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3814 static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout4 *iface, FLOAT* min_width)
3816 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3817 UINT32 start;
3818 FLOAT width;
3819 HRESULT hr;
3821 TRACE("%p, %p.\n", iface, min_width);
3823 if (!min_width)
3824 return E_INVALIDARG;
3826 if (!(layout->recompute & RECOMPUTE_MINIMAL_WIDTH))
3827 goto width_done;
3829 *min_width = 0.0f;
3830 hr = layout_compute(layout);
3831 if (FAILED(hr))
3832 return hr;
3834 /* Find widest word without emergency breaking between clusters, trailing whitespaces
3835 preceding breaking point do not contribute to word width. */
3836 for (start = 0; start < layout->cluster_count;)
3838 UINT32 end = start, j, next;
3840 /* Last cluster always could be wrapped after. */
3841 while (!layout->clustermetrics[end].canWrapLineAfter)
3842 end++;
3843 /* make is so current cluster range that we can wrap after is [start,end) */
3844 end++;
3846 next = end;
3848 /* Ignore trailing whitespace clusters, in case of single space range will
3849 be reduced to empty range, or [start,start+1). */
3850 while (end > start && layout->clustermetrics[end-1].isWhitespace)
3851 end--;
3853 /* check if cluster range exceeds last minimal width */
3854 width = 0.0f;
3855 for (j = start; j < end; j++)
3856 width += layout->clustermetrics[j].width;
3858 start = next;
3860 if (width > layout->minwidth)
3861 layout->minwidth = width;
3863 layout->recompute &= ~RECOMPUTE_MINIMAL_WIDTH;
3865 width_done:
3866 *min_width = layout->minwidth;
3867 return S_OK;
3870 static HRESULT WINAPI dwritetextlayout_HitTestPoint(IDWriteTextLayout4 *iface,
3871 FLOAT pointX, FLOAT pointY, BOOL* is_trailinghit, BOOL* is_inside, DWRITE_HIT_TEST_METRICS *metrics)
3873 FIXME("%p, %.8e, %.8e, %p, %p, %p): stub\n", iface, pointX, pointY, is_trailinghit, is_inside, metrics);
3875 return E_NOTIMPL;
3878 static HRESULT WINAPI dwritetextlayout_HitTestTextPosition(IDWriteTextLayout4 *iface,
3879 UINT32 textPosition, BOOL is_trailinghit, FLOAT *pointX, FLOAT *pointY, DWRITE_HIT_TEST_METRICS *metrics)
3881 FIXME("%p, %u, %d, %p, %p, %p): stub\n", iface, textPosition, is_trailinghit, pointX, pointY, metrics);
3883 return E_NOTIMPL;
3886 static HRESULT WINAPI dwritetextlayout_HitTestTextRange(IDWriteTextLayout4 *iface,
3887 UINT32 textPosition, UINT32 textLength, FLOAT originX, FLOAT originY,
3888 DWRITE_HIT_TEST_METRICS *metrics, UINT32 max_metricscount, UINT32* actual_metricscount)
3890 FIXME("%p, %u, %u, %f, %f, %p, %u, %p): stub\n", iface, textPosition, textLength, originX, originY, metrics,
3891 max_metricscount, actual_metricscount);
3893 return E_NOTIMPL;
3896 static HRESULT WINAPI dwritetextlayout1_SetPairKerning(IDWriteTextLayout4 *iface, BOOL is_pairkerning_enabled,
3897 DWRITE_TEXT_RANGE range)
3899 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3900 struct layout_range_attr_value value;
3902 TRACE("%p, %d, %s.\n", iface, is_pairkerning_enabled, debugstr_range(&range));
3904 value.range = range;
3905 value.u.pair_kerning = !!is_pairkerning_enabled;
3906 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_PAIR_KERNING, &value);
3909 static HRESULT WINAPI dwritetextlayout1_GetPairKerning(IDWriteTextLayout4 *iface, UINT32 position,
3910 BOOL *is_pairkerning_enabled, DWRITE_TEXT_RANGE *r)
3912 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3913 struct layout_range *range;
3915 TRACE("%p, %u, %p, %p.\n", iface, position, is_pairkerning_enabled, r);
3917 if (position >= layout->len)
3918 return S_OK;
3920 range = get_layout_range_by_pos(layout, position);
3921 *is_pairkerning_enabled = range->pair_kerning;
3923 return return_range(&range->h, r);
3926 static HRESULT WINAPI dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout4 *iface, FLOAT leading, FLOAT trailing,
3927 FLOAT min_advance, DWRITE_TEXT_RANGE range)
3929 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3930 struct layout_range_attr_value value;
3932 TRACE("%p, %.8e, %.8e, %.8e, %s.\n", iface, leading, trailing, min_advance, debugstr_range(&range));
3934 if (min_advance < 0.0f)
3935 return E_INVALIDARG;
3937 value.range = range;
3938 value.u.spacing.leading = leading;
3939 value.u.spacing.trailing = trailing;
3940 value.u.spacing.min_advance = min_advance;
3941 return set_layout_range_attr(layout, LAYOUT_RANGE_ATTR_SPACING, &value);
3944 static HRESULT WINAPI dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout4 *iface, UINT32 position, FLOAT *leading,
3945 FLOAT *trailing, FLOAT *min_advance, DWRITE_TEXT_RANGE *r)
3947 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3948 struct layout_range_spacing *range;
3950 TRACE("%p, %u, %p, %p, %p, %p.\n", iface, position, leading, trailing, min_advance, r);
3952 range = (struct layout_range_spacing *)get_layout_range_header_by_pos(&layout->spacing, position);
3953 *leading = range->leading;
3954 *trailing = range->trailing;
3955 *min_advance = range->min_advance;
3957 return return_range(&range->h, r);
3960 static HRESULT WINAPI dwritetextlayout2_GetMetrics(IDWriteTextLayout4 *iface, DWRITE_TEXT_METRICS1 *metrics)
3962 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3963 HRESULT hr;
3965 TRACE("%p, %p.\n", iface, metrics);
3967 if (SUCCEEDED(hr = layout_update_metrics(layout)))
3968 *metrics = layout->metrics;
3970 return hr;
3973 static HRESULT layout_set_vertical_orientation(struct dwrite_textlayout *layout,
3974 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
3976 BOOL changed;
3977 HRESULT hr;
3979 if (FAILED(hr = format_set_vertical_orientation(&layout->format, orientation, &changed)))
3980 return hr;
3982 if (changed)
3983 layout->recompute = RECOMPUTE_EVERYTHING;
3985 return S_OK;
3988 static HRESULT WINAPI dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout4 *iface,
3989 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
3991 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
3993 TRACE("%p, %d.\n", iface, orientation);
3995 return layout_set_vertical_orientation(layout, orientation);
3998 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout4 *iface)
4000 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4002 TRACE("%p.\n", iface);
4004 return layout->format.vertical_orientation;
4007 static HRESULT WINAPI dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout4 *iface, BOOL lastline_wrapping_enabled)
4009 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4011 TRACE("%p, %d.\n", iface, lastline_wrapping_enabled);
4013 return IDWriteTextFormat3_SetLastLineWrapping(&layout->IDWriteTextFormat3_iface, lastline_wrapping_enabled);
4016 static BOOL WINAPI dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout4 *iface)
4018 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4020 TRACE("%p.\n", iface);
4022 return IDWriteTextFormat3_GetLastLineWrapping(&layout->IDWriteTextFormat3_iface);
4025 static HRESULT WINAPI dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout4 *iface,
4026 DWRITE_OPTICAL_ALIGNMENT alignment)
4028 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4030 TRACE("%p, %d.\n", iface, alignment);
4032 return IDWriteTextFormat3_SetOpticalAlignment(&layout->IDWriteTextFormat3_iface, alignment);
4035 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout4 *iface)
4037 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4039 TRACE("%p.\n", iface);
4041 return IDWriteTextFormat3_GetOpticalAlignment(&layout->IDWriteTextFormat3_iface);
4044 static HRESULT WINAPI dwritetextlayout2_SetFontFallback(IDWriteTextLayout4 *iface, IDWriteFontFallback *fallback)
4046 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4048 TRACE("%p, %p.\n", iface, fallback);
4050 return set_fontfallback_for_format(&layout->format, fallback);
4053 static HRESULT WINAPI dwritetextlayout2_GetFontFallback(IDWriteTextLayout4 *iface, IDWriteFontFallback **fallback)
4055 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4057 TRACE("%p, %p.\n", iface, fallback);
4059 return get_fontfallback_from_format(&layout->format, fallback);
4062 static HRESULT WINAPI dwritetextlayout3_InvalidateLayout(IDWriteTextLayout4 *iface)
4064 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4066 TRACE("%p.\n", iface);
4068 layout->recompute = RECOMPUTE_EVERYTHING;
4069 return S_OK;
4072 static HRESULT WINAPI dwritetextlayout3_SetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING const *spacing)
4074 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4075 BOOL changed;
4076 HRESULT hr;
4078 TRACE("%p, %p.\n", iface, spacing);
4080 hr = format_set_linespacing(&layout->format, spacing, &changed);
4081 if (FAILED(hr))
4082 return hr;
4084 if (changed)
4086 if (!(layout->recompute & RECOMPUTE_LINES))
4088 UINT32 line;
4090 for (line = 0; line < layout->metrics.lineCount; line++)
4091 layout_apply_line_spacing(layout, line);
4093 layout_set_line_positions(layout);
4096 layout->recompute |= RECOMPUTE_OVERHANGS;
4099 return S_OK;
4102 static HRESULT WINAPI dwritetextlayout3_GetLineSpacing(IDWriteTextLayout4 *iface, DWRITE_LINE_SPACING *spacing)
4104 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4106 TRACE("%p, %p.\n", iface, spacing);
4108 *spacing = layout->format.spacing;
4109 return S_OK;
4112 static HRESULT WINAPI dwritetextlayout3_GetLineMetrics(IDWriteTextLayout4 *iface, DWRITE_LINE_METRICS1 *metrics,
4113 UINT32 max_count, UINT32 *count)
4115 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4116 unsigned int line_count;
4117 HRESULT hr;
4118 size_t i;
4120 TRACE("%p, %p, %u, %p.\n", iface, metrics, max_count, count);
4122 if (FAILED(hr = layout_compute_effective_runs(layout)))
4123 return hr;
4125 if (metrics)
4127 line_count = min(max_count, layout->metrics.lineCount);
4128 for (i = 0; i < line_count; ++i)
4129 metrics[i] = layout->lines[i].metrics;
4132 *count = layout->metrics.lineCount;
4133 return max_count >= layout->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
4136 static HRESULT WINAPI dwritetextlayout4_SetFontAxisValues(IDWriteTextLayout4 *iface,
4137 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, DWRITE_TEXT_RANGE range)
4139 FIXME("%p, %p, %u, %s.\n", iface, axis_values, num_values, debugstr_range(&range));
4141 return E_NOTIMPL;
4144 static UINT32 WINAPI dwritetextlayout4_GetFontAxisValueCount(IDWriteTextLayout4 *iface, UINT32 pos)
4146 FIXME("%p, %u.\n", iface, pos);
4148 return 0;
4151 static HRESULT WINAPI dwritetextlayout4_GetFontAxisValues(IDWriteTextLayout4 *iface, UINT32 pos,
4152 DWRITE_FONT_AXIS_VALUE *values, UINT32 num_values, DWRITE_TEXT_RANGE *range)
4154 FIXME("%p, %u, %p, %u, %p.\n", iface, pos, values, num_values, range);
4156 return E_NOTIMPL;
4159 static DWRITE_AUTOMATIC_FONT_AXES WINAPI dwritetextlayout4_GetAutomaticFontAxes(IDWriteTextLayout4 *iface)
4161 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4163 TRACE("%p.\n", iface);
4165 return layout->format.automatic_axes;
4168 static HRESULT WINAPI dwritetextlayout4_SetAutomaticFontAxes(IDWriteTextLayout4 *iface,
4169 DWRITE_AUTOMATIC_FONT_AXES axes)
4171 struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface);
4173 TRACE("%p, %d.\n", iface, axes);
4175 if ((unsigned int)axes > DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE)
4176 return E_INVALIDARG;
4178 layout->format.automatic_axes = axes;
4179 return S_OK;
4182 static const IDWriteTextLayout4Vtbl dwritetextlayoutvtbl =
4184 dwritetextlayout_QueryInterface,
4185 dwritetextlayout_AddRef,
4186 dwritetextlayout_Release,
4187 dwritetextlayout_SetTextAlignment,
4188 dwritetextlayout_SetParagraphAlignment,
4189 dwritetextlayout_SetWordWrapping,
4190 dwritetextlayout_SetReadingDirection,
4191 dwritetextlayout_SetFlowDirection,
4192 dwritetextlayout_SetIncrementalTabStop,
4193 dwritetextlayout_SetTrimming,
4194 dwritetextlayout_SetLineSpacing,
4195 dwritetextlayout_GetTextAlignment,
4196 dwritetextlayout_GetParagraphAlignment,
4197 dwritetextlayout_GetWordWrapping,
4198 dwritetextlayout_GetReadingDirection,
4199 dwritetextlayout_GetFlowDirection,
4200 dwritetextlayout_GetIncrementalTabStop,
4201 dwritetextlayout_GetTrimming,
4202 dwritetextlayout_GetLineSpacing,
4203 dwritetextlayout_GetFontCollection,
4204 dwritetextlayout_GetFontFamilyNameLength,
4205 dwritetextlayout_GetFontFamilyName,
4206 dwritetextlayout_GetFontWeight,
4207 dwritetextlayout_GetFontStyle,
4208 dwritetextlayout_GetFontStretch,
4209 dwritetextlayout_GetFontSize,
4210 dwritetextlayout_GetLocaleNameLength,
4211 dwritetextlayout_GetLocaleName,
4212 dwritetextlayout_SetMaxWidth,
4213 dwritetextlayout_SetMaxHeight,
4214 dwritetextlayout_SetFontCollection,
4215 dwritetextlayout_SetFontFamilyName,
4216 dwritetextlayout_SetFontWeight,
4217 dwritetextlayout_SetFontStyle,
4218 dwritetextlayout_SetFontStretch,
4219 dwritetextlayout_SetFontSize,
4220 dwritetextlayout_SetUnderline,
4221 dwritetextlayout_SetStrikethrough,
4222 dwritetextlayout_SetDrawingEffect,
4223 dwritetextlayout_SetInlineObject,
4224 dwritetextlayout_SetTypography,
4225 dwritetextlayout_SetLocaleName,
4226 dwritetextlayout_GetMaxWidth,
4227 dwritetextlayout_GetMaxHeight,
4228 dwritetextlayout_layout_GetFontCollection,
4229 dwritetextlayout_layout_GetFontFamilyNameLength,
4230 dwritetextlayout_layout_GetFontFamilyName,
4231 dwritetextlayout_layout_GetFontWeight,
4232 dwritetextlayout_layout_GetFontStyle,
4233 dwritetextlayout_layout_GetFontStretch,
4234 dwritetextlayout_layout_GetFontSize,
4235 dwritetextlayout_GetUnderline,
4236 dwritetextlayout_GetStrikethrough,
4237 dwritetextlayout_GetDrawingEffect,
4238 dwritetextlayout_GetInlineObject,
4239 dwritetextlayout_GetTypography,
4240 dwritetextlayout_layout_GetLocaleNameLength,
4241 dwritetextlayout_layout_GetLocaleName,
4242 dwritetextlayout_Draw,
4243 dwritetextlayout_GetLineMetrics,
4244 dwritetextlayout_GetMetrics,
4245 dwritetextlayout_GetOverhangMetrics,
4246 dwritetextlayout_GetClusterMetrics,
4247 dwritetextlayout_DetermineMinWidth,
4248 dwritetextlayout_HitTestPoint,
4249 dwritetextlayout_HitTestTextPosition,
4250 dwritetextlayout_HitTestTextRange,
4251 dwritetextlayout1_SetPairKerning,
4252 dwritetextlayout1_GetPairKerning,
4253 dwritetextlayout1_SetCharacterSpacing,
4254 dwritetextlayout1_GetCharacterSpacing,
4255 dwritetextlayout2_GetMetrics,
4256 dwritetextlayout2_SetVerticalGlyphOrientation,
4257 dwritetextlayout2_GetVerticalGlyphOrientation,
4258 dwritetextlayout2_SetLastLineWrapping,
4259 dwritetextlayout2_GetLastLineWrapping,
4260 dwritetextlayout2_SetOpticalAlignment,
4261 dwritetextlayout2_GetOpticalAlignment,
4262 dwritetextlayout2_SetFontFallback,
4263 dwritetextlayout2_GetFontFallback,
4264 dwritetextlayout3_InvalidateLayout,
4265 dwritetextlayout3_SetLineSpacing,
4266 dwritetextlayout3_GetLineSpacing,
4267 dwritetextlayout3_GetLineMetrics,
4268 dwritetextlayout4_SetFontAxisValues,
4269 dwritetextlayout4_GetFontAxisValueCount,
4270 dwritetextlayout4_GetFontAxisValues,
4271 dwritetextlayout4_GetAutomaticFontAxes,
4272 dwritetextlayout4_SetAutomaticFontAxes,
4275 static HRESULT WINAPI dwritetextformat_layout_QueryInterface(IDWriteTextFormat3 *iface, REFIID riid, void **obj)
4277 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4279 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
4281 return IDWriteTextLayout4_QueryInterface(&layout->IDWriteTextLayout4_iface, riid, obj);
4284 static ULONG WINAPI dwritetextformat_layout_AddRef(IDWriteTextFormat3 *iface)
4286 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4287 return IDWriteTextLayout4_AddRef(&layout->IDWriteTextLayout4_iface);
4290 static ULONG WINAPI dwritetextformat_layout_Release(IDWriteTextFormat3 *iface)
4292 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4293 return IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
4296 static HRESULT WINAPI dwritetextformat_layout_SetTextAlignment(IDWriteTextFormat3 *iface,
4297 DWRITE_TEXT_ALIGNMENT alignment)
4299 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4300 BOOL changed;
4301 HRESULT hr;
4303 TRACE("%p, %d.\n", iface, alignment);
4305 hr = format_set_textalignment(&layout->format, alignment, &changed);
4306 if (FAILED(hr))
4307 return hr;
4309 if (changed)
4311 /* if layout is not ready there's nothing to align */
4312 if (!(layout->recompute & RECOMPUTE_LINES))
4313 layout_apply_text_alignment(layout);
4314 layout->recompute |= RECOMPUTE_OVERHANGS;
4317 return S_OK;
4320 static HRESULT WINAPI dwritetextformat_layout_SetParagraphAlignment(IDWriteTextFormat3 *iface,
4321 DWRITE_PARAGRAPH_ALIGNMENT alignment)
4323 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4324 BOOL changed;
4325 HRESULT hr;
4327 TRACE("%p, %d.\n", iface, alignment);
4329 hr = format_set_paralignment(&layout->format, alignment, &changed);
4330 if (FAILED(hr))
4331 return hr;
4333 if (changed)
4335 /* if layout is not ready there's nothing to align */
4336 if (!(layout->recompute & RECOMPUTE_LINES))
4337 layout_apply_par_alignment(layout);
4338 layout->recompute |= RECOMPUTE_OVERHANGS;
4341 return S_OK;
4344 static HRESULT WINAPI dwritetextformat_layout_SetWordWrapping(IDWriteTextFormat3 *iface, DWRITE_WORD_WRAPPING wrapping)
4346 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4347 BOOL changed;
4348 HRESULT hr;
4350 TRACE("%p, %d.\n", iface, wrapping);
4352 hr = format_set_wordwrapping(&layout->format, wrapping, &changed);
4353 if (FAILED(hr))
4354 return hr;
4356 if (changed)
4357 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
4359 return S_OK;
4362 static HRESULT WINAPI dwritetextformat_layout_SetReadingDirection(IDWriteTextFormat3 *iface,
4363 DWRITE_READING_DIRECTION direction)
4365 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4366 BOOL changed;
4367 HRESULT hr;
4369 TRACE("%p, %d.\n", iface, direction);
4371 hr = format_set_readingdirection(&layout->format, direction, &changed);
4372 if (FAILED(hr))
4373 return hr;
4375 if (changed)
4376 layout->recompute = RECOMPUTE_EVERYTHING;
4378 return S_OK;
4381 static HRESULT WINAPI dwritetextformat_layout_SetFlowDirection(IDWriteTextFormat3 *iface,
4382 DWRITE_FLOW_DIRECTION direction)
4384 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4385 BOOL changed;
4386 HRESULT hr;
4388 TRACE("%p, %d.\n", iface, direction);
4390 hr = format_set_flowdirection(&layout->format, direction, &changed);
4391 if (FAILED(hr))
4392 return hr;
4394 if (changed)
4395 layout->recompute = RECOMPUTE_EVERYTHING;
4397 return S_OK;
4400 static HRESULT WINAPI dwritetextformat_layout_SetIncrementalTabStop(IDWriteTextFormat3 *iface, FLOAT tabstop)
4402 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4404 TRACE("%p, %.8e.\n", iface, tabstop);
4406 if (tabstop <= 0.0f)
4407 return E_INVALIDARG;
4409 layout->format.tabstop = tabstop;
4410 return S_OK;
4413 static HRESULT WINAPI dwritetextformat_layout_SetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING const *trimming,
4414 IDWriteInlineObject *trimming_sign)
4416 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4417 BOOL changed;
4418 HRESULT hr;
4420 TRACE("%p, %p, %p.\n", iface, trimming, trimming_sign);
4422 hr = format_set_trimming(&layout->format, trimming, trimming_sign, &changed);
4424 if (changed)
4425 layout->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
4427 return hr;
4430 static HRESULT WINAPI dwritetextformat_layout_SetLineSpacing(IDWriteTextFormat3 *iface,
4431 DWRITE_LINE_SPACING_METHOD method, FLOAT height, FLOAT baseline)
4433 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4434 DWRITE_LINE_SPACING spacing;
4436 TRACE("%p, %d, %.8e, %.8e.\n", iface, method, height, baseline);
4438 spacing = layout->format.spacing;
4439 spacing.method = method;
4440 spacing.height = height;
4441 spacing.baseline = baseline;
4442 return IDWriteTextLayout4_SetLineSpacing(&layout->IDWriteTextLayout4_iface, &spacing);
4445 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_layout_GetTextAlignment(IDWriteTextFormat3 *iface)
4447 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4449 TRACE("%p.\n", iface);
4451 return layout->format.textalignment;
4454 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_layout_GetParagraphAlignment(IDWriteTextFormat3 *iface)
4456 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4458 TRACE("%p.\n", iface);
4460 return layout->format.paralign;
4463 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_layout_GetWordWrapping(IDWriteTextFormat3 *iface)
4465 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4467 TRACE("%p.\n", iface);
4469 return layout->format.wrapping;
4472 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_layout_GetReadingDirection(IDWriteTextFormat3 *iface)
4474 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4476 TRACE("%p.\n", iface);
4478 return layout->format.readingdir;
4481 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_layout_GetFlowDirection(IDWriteTextFormat3 *iface)
4483 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4485 TRACE("%p.\n", iface);
4487 return layout->format.flow;
4490 static FLOAT WINAPI dwritetextformat_layout_GetIncrementalTabStop(IDWriteTextFormat3 *iface)
4492 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4494 TRACE("%p.\n", iface);
4496 return layout->format.tabstop;
4499 static HRESULT WINAPI dwritetextformat_layout_GetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING *options,
4500 IDWriteInlineObject **trimming_sign)
4502 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4504 TRACE("%p, %p, %p.\n", iface, options, trimming_sign);
4506 *options = layout->format.trimming;
4507 *trimming_sign = layout->format.trimmingsign;
4508 if (*trimming_sign)
4509 IDWriteInlineObject_AddRef(*trimming_sign);
4510 return S_OK;
4513 static HRESULT WINAPI dwritetextformat_layout_GetLineSpacing(IDWriteTextFormat3 *iface,
4514 DWRITE_LINE_SPACING_METHOD *method, FLOAT *spacing, FLOAT *baseline)
4516 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4518 TRACE("%p, %p, %p, %p.\n", iface, method, spacing, baseline);
4520 *method = layout->format.spacing.method;
4521 *spacing = layout->format.spacing.height;
4522 *baseline = layout->format.spacing.baseline;
4523 return S_OK;
4526 static HRESULT WINAPI dwritetextformat_layout_GetFontCollection(IDWriteTextFormat3 *iface,
4527 IDWriteFontCollection **collection)
4529 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4531 TRACE("%p, %p.\n", iface, collection);
4533 *collection = layout->format.collection;
4534 if (*collection)
4535 IDWriteFontCollection_AddRef(*collection);
4536 return S_OK;
4539 static UINT32 WINAPI dwritetextformat_layout_GetFontFamilyNameLength(IDWriteTextFormat3 *iface)
4541 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4543 TRACE("%p.\n", iface);
4545 return layout->format.family_len;
4548 static HRESULT WINAPI dwritetextformat_layout_GetFontFamilyName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
4550 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4552 TRACE("%p, %p, %u.\n", iface, name, size);
4554 if (size <= layout->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
4555 strcpyW(name, layout->format.family_name);
4556 return S_OK;
4559 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_layout_GetFontWeight(IDWriteTextFormat3 *iface)
4561 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4563 TRACE("%p.\n", iface);
4565 return layout->format.weight;
4568 static DWRITE_FONT_STYLE WINAPI dwritetextformat_layout_GetFontStyle(IDWriteTextFormat3 *iface)
4570 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4572 TRACE("%p.\n", iface);
4574 return layout->format.style;
4577 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_layout_GetFontStretch(IDWriteTextFormat3 *iface)
4579 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4581 TRACE("%p.\n", iface);
4583 return layout->format.stretch;
4586 static FLOAT WINAPI dwritetextformat_layout_GetFontSize(IDWriteTextFormat3 *iface)
4588 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4590 TRACE("%p.\n", iface);
4592 return layout->format.fontsize;
4595 static UINT32 WINAPI dwritetextformat_layout_GetLocaleNameLength(IDWriteTextFormat3 *iface)
4597 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4599 TRACE("%p.\n", iface);
4601 return layout->format.locale_len;
4604 static HRESULT WINAPI dwritetextformat_layout_GetLocaleName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
4606 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4608 TRACE("%p, %p, %u.\n", iface, name, size);
4610 if (size <= layout->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
4611 strcpyW(name, layout->format.locale);
4612 return S_OK;
4615 static HRESULT WINAPI dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat3 *iface,
4616 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4618 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4620 TRACE("%p, %d.\n", iface, orientation);
4622 return layout_set_vertical_orientation(layout, orientation);
4625 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat3 *iface)
4627 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4629 TRACE("%p.\n", iface);
4631 return layout->format.vertical_orientation;
4634 static HRESULT WINAPI dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat3 *iface,
4635 BOOL lastline_wrapping_enabled)
4637 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4639 TRACE("%p, %d.\n", iface, lastline_wrapping_enabled);
4641 layout->format.last_line_wrapping = !!lastline_wrapping_enabled;
4642 return S_OK;
4645 static BOOL WINAPI dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat3 *iface)
4647 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4649 TRACE("%p.\n", iface);
4651 return layout->format.last_line_wrapping;
4654 static HRESULT WINAPI dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat3 *iface,
4655 DWRITE_OPTICAL_ALIGNMENT alignment)
4657 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4659 TRACE("%p, %d.\n", iface, alignment);
4661 return format_set_optical_alignment(&layout->format, alignment);
4664 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat3 *iface)
4666 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4668 TRACE("%p.\n", iface);
4670 return layout->format.optical_alignment;
4673 static HRESULT WINAPI dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat3 *iface,
4674 IDWriteFontFallback *fallback)
4676 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4678 TRACE("%p, %p.\n", iface, fallback);
4680 return IDWriteTextLayout4_SetFontFallback(&layout->IDWriteTextLayout4_iface, fallback);
4683 static HRESULT WINAPI dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat3 *iface,
4684 IDWriteFontFallback **fallback)
4686 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4688 TRACE("%p, %p.\n", iface, fallback);
4690 return IDWriteTextLayout4_GetFontFallback(&layout->IDWriteTextLayout4_iface, fallback);
4693 static HRESULT WINAPI dwritetextformat2_layout_SetLineSpacing(IDWriteTextFormat3 *iface,
4694 DWRITE_LINE_SPACING const *spacing)
4696 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4697 return IDWriteTextLayout4_SetLineSpacing(&layout->IDWriteTextLayout4_iface, spacing);
4700 static HRESULT WINAPI dwritetextformat2_layout_GetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING *spacing)
4702 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4703 return IDWriteTextLayout4_GetLineSpacing(&layout->IDWriteTextLayout4_iface, spacing);
4706 static HRESULT WINAPI dwritetextformat3_layout_SetFontAxisValues(IDWriteTextFormat3 *iface,
4707 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values)
4709 FIXME("%p, %p, %u.\n", iface, axis_values, num_values);
4711 return E_NOTIMPL;
4714 static UINT32 WINAPI dwritetextformat3_layout_GetFontAxisValueCount(IDWriteTextFormat3 *iface)
4716 FIXME("%p.\n", iface);
4718 return 0;
4721 static HRESULT WINAPI dwritetextformat3_layout_GetFontAxisValues(IDWriteTextFormat3 *iface,
4722 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values)
4724 FIXME("%p, %p, %u.\n", iface, axis_values, num_values);
4726 return E_NOTIMPL;
4729 static DWRITE_AUTOMATIC_FONT_AXES WINAPI dwritetextformat3_layout_GetAutomaticFontAxes(IDWriteTextFormat3 *iface)
4731 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4732 return IDWriteTextLayout4_GetAutomaticFontAxes(&layout->IDWriteTextLayout4_iface);
4735 static HRESULT WINAPI dwritetextformat3_layout_SetAutomaticFontAxes(IDWriteTextFormat3 *iface,
4736 DWRITE_AUTOMATIC_FONT_AXES axes)
4738 struct dwrite_textlayout *layout = impl_layout_from_IDWriteTextFormat3(iface);
4739 return IDWriteTextLayout4_SetAutomaticFontAxes(&layout->IDWriteTextLayout4_iface, axes);
4742 static const IDWriteTextFormat3Vtbl dwritetextformat3_layout_vtbl =
4744 dwritetextformat_layout_QueryInterface,
4745 dwritetextformat_layout_AddRef,
4746 dwritetextformat_layout_Release,
4747 dwritetextformat_layout_SetTextAlignment,
4748 dwritetextformat_layout_SetParagraphAlignment,
4749 dwritetextformat_layout_SetWordWrapping,
4750 dwritetextformat_layout_SetReadingDirection,
4751 dwritetextformat_layout_SetFlowDirection,
4752 dwritetextformat_layout_SetIncrementalTabStop,
4753 dwritetextformat_layout_SetTrimming,
4754 dwritetextformat_layout_SetLineSpacing,
4755 dwritetextformat_layout_GetTextAlignment,
4756 dwritetextformat_layout_GetParagraphAlignment,
4757 dwritetextformat_layout_GetWordWrapping,
4758 dwritetextformat_layout_GetReadingDirection,
4759 dwritetextformat_layout_GetFlowDirection,
4760 dwritetextformat_layout_GetIncrementalTabStop,
4761 dwritetextformat_layout_GetTrimming,
4762 dwritetextformat_layout_GetLineSpacing,
4763 dwritetextformat_layout_GetFontCollection,
4764 dwritetextformat_layout_GetFontFamilyNameLength,
4765 dwritetextformat_layout_GetFontFamilyName,
4766 dwritetextformat_layout_GetFontWeight,
4767 dwritetextformat_layout_GetFontStyle,
4768 dwritetextformat_layout_GetFontStretch,
4769 dwritetextformat_layout_GetFontSize,
4770 dwritetextformat_layout_GetLocaleNameLength,
4771 dwritetextformat_layout_GetLocaleName,
4772 dwritetextformat1_layout_SetVerticalGlyphOrientation,
4773 dwritetextformat1_layout_GetVerticalGlyphOrientation,
4774 dwritetextformat1_layout_SetLastLineWrapping,
4775 dwritetextformat1_layout_GetLastLineWrapping,
4776 dwritetextformat1_layout_SetOpticalAlignment,
4777 dwritetextformat1_layout_GetOpticalAlignment,
4778 dwritetextformat1_layout_SetFontFallback,
4779 dwritetextformat1_layout_GetFontFallback,
4780 dwritetextformat2_layout_SetLineSpacing,
4781 dwritetextformat2_layout_GetLineSpacing,
4782 dwritetextformat3_layout_SetFontAxisValues,
4783 dwritetextformat3_layout_GetFontAxisValueCount,
4784 dwritetextformat3_layout_GetFontAxisValues,
4785 dwritetextformat3_layout_GetAutomaticFontAxes,
4786 dwritetextformat3_layout_SetAutomaticFontAxes,
4789 static HRESULT WINAPI dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink1 *iface,
4790 REFIID riid, void **obj)
4792 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink1) ||
4793 IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) ||
4794 IsEqualIID(riid, &IID_IUnknown))
4796 *obj = iface;
4797 IDWriteTextAnalysisSink1_AddRef(iface);
4798 return S_OK;
4801 WARN("%s not implemented.\n", debugstr_guid(riid));
4803 *obj = NULL;
4804 return E_NOINTERFACE;
4807 static ULONG WINAPI dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink1 *iface)
4809 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4810 return IDWriteTextLayout4_AddRef(&layout->IDWriteTextLayout4_iface);
4813 static ULONG WINAPI dwritetextlayout_sink_Release(IDWriteTextAnalysisSink1 *iface)
4815 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4816 return IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
4819 static HRESULT WINAPI dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink1 *iface,
4820 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
4822 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4823 struct layout_run *run;
4824 HRESULT hr;
4826 TRACE("[%u,%u) script=%u:%s\n", position, position + length, sa->script, debugstr_sa_script(sa->script));
4828 if (FAILED(hr = alloc_layout_run(LAYOUT_RUN_REGULAR, position, &run)))
4829 return hr;
4831 run->u.regular.descr.string = &layout->str[position];
4832 run->u.regular.descr.stringLength = length;
4833 run->u.regular.descr.textPosition = position;
4834 run->u.regular.sa = *sa;
4835 list_add_tail(&layout->runs, &run->entry);
4836 return S_OK;
4839 static HRESULT WINAPI dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink1 *iface,
4840 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
4842 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4844 if (position + length > layout->len)
4845 return E_FAIL;
4847 memcpy(&layout->nominal_breakpoints[position], breakpoints, length*sizeof(DWRITE_LINE_BREAKPOINT));
4848 return S_OK;
4851 static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink1 *iface, UINT32 position,
4852 UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
4854 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4855 struct layout_run *cur_run;
4856 HRESULT hr;
4858 TRACE("[%u,%u) %u %u\n", position, position + length, explicitLevel, resolvedLevel);
4860 LIST_FOR_EACH_ENTRY(cur_run, &layout->runs, struct layout_run, entry) {
4861 struct regular_layout_run *cur = &cur_run->u.regular;
4862 struct layout_run *run;
4864 if (cur_run->kind == LAYOUT_RUN_INLINE)
4865 continue;
4867 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
4868 if (position < cur->descr.textPosition || position >= cur->descr.textPosition + cur->descr.stringLength)
4869 continue;
4871 /* full hit - just set run level */
4872 if (cur->descr.textPosition == position && cur->descr.stringLength == length) {
4873 cur->run.bidiLevel = resolvedLevel;
4874 break;
4877 /* current run is fully covered, move to next one */
4878 if (cur->descr.textPosition == position && cur->descr.stringLength < length) {
4879 cur->run.bidiLevel = resolvedLevel;
4880 position += cur->descr.stringLength;
4881 length -= cur->descr.stringLength;
4882 continue;
4885 /* all fully covered runs are processed at this point, reuse existing run for remaining
4886 reported bidi range and add another run for the rest of original one */
4888 if (FAILED(hr = alloc_layout_run(LAYOUT_RUN_REGULAR, position + length, &run)))
4889 return hr;
4891 *run = *cur_run;
4892 run->u.regular.descr.textPosition = position + length;
4893 run->u.regular.descr.stringLength = cur->descr.stringLength - length;
4894 run->u.regular.descr.string = &layout->str[position + length];
4896 /* reduce existing run */
4897 cur->run.bidiLevel = resolvedLevel;
4898 cur->descr.stringLength = length;
4900 list_add_after(&cur_run->entry, &run->entry);
4901 break;
4904 return S_OK;
4907 static HRESULT WINAPI dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink1 *iface,
4908 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
4910 return E_NOTIMPL;
4913 static HRESULT WINAPI dwritetextlayout_sink_SetGlyphOrientation(IDWriteTextAnalysisSink1 *iface,
4914 UINT32 position, UINT32 length, DWRITE_GLYPH_ORIENTATION_ANGLE angle, UINT8 adjusted_bidi_level,
4915 BOOL is_sideways, BOOL is_rtl)
4917 return E_NOTIMPL;
4920 static const IDWriteTextAnalysisSink1Vtbl dwritetextlayoutsinkvtbl = {
4921 dwritetextlayout_sink_QueryInterface,
4922 dwritetextlayout_sink_AddRef,
4923 dwritetextlayout_sink_Release,
4924 dwritetextlayout_sink_SetScriptAnalysis,
4925 dwritetextlayout_sink_SetLineBreakpoints,
4926 dwritetextlayout_sink_SetBidiLevel,
4927 dwritetextlayout_sink_SetNumberSubstitution,
4928 dwritetextlayout_sink_SetGlyphOrientation
4931 static HRESULT WINAPI dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource1 *iface,
4932 REFIID riid, void **obj)
4934 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource1) ||
4935 IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) ||
4936 IsEqualIID(riid, &IID_IUnknown))
4938 *obj = iface;
4939 IDWriteTextAnalysisSource1_AddRef(iface);
4940 return S_OK;
4943 WARN("%s not implemented.\n", debugstr_guid(riid));
4945 *obj = NULL;
4946 return E_NOINTERFACE;
4949 static ULONG WINAPI dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource1 *iface)
4951 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4952 return IDWriteTextLayout4_AddRef(&layout->IDWriteTextLayout4_iface);
4955 static ULONG WINAPI dwritetextlayout_source_Release(IDWriteTextAnalysisSource1 *iface)
4957 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4958 return IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
4961 static HRESULT WINAPI dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource1 *iface,
4962 UINT32 position, WCHAR const** text, UINT32* text_len)
4964 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4966 TRACE("%p, %u, %p, %p.\n", iface, position, text, text_len);
4968 if (position < layout->len) {
4969 *text = &layout->str[position];
4970 *text_len = layout->len - position;
4972 else {
4973 *text = NULL;
4974 *text_len = 0;
4977 return S_OK;
4980 static HRESULT WINAPI dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource1 *iface,
4981 UINT32 position, WCHAR const** text, UINT32* text_len)
4983 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4985 TRACE("%p, %u, %p, %p.\n", iface, position, text, text_len);
4987 if (position > 0 && position < layout->len) {
4988 *text = layout->str;
4989 *text_len = position;
4991 else {
4992 *text = NULL;
4993 *text_len = 0;
4996 return S_OK;
4999 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource1 *iface)
5001 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5002 return IDWriteTextLayout4_GetReadingDirection(&layout->IDWriteTextLayout4_iface);
5005 static HRESULT WINAPI dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource1 *iface,
5006 UINT32 position, UINT32* text_len, WCHAR const** locale)
5008 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
5009 struct layout_range *range = get_layout_range_by_pos(layout, position);
5011 if (position < layout->len) {
5012 struct layout_range *next;
5014 *locale = range->locale;
5015 *text_len = range->h.range.length - position;
5017 next = LIST_ENTRY(list_next(&layout->ranges, &range->h.entry), struct layout_range, h.entry);
5018 while (next && next->h.range.startPosition < layout->len && !strcmpW(range->locale, next->locale)) {
5019 *text_len += next->h.range.length;
5020 next = LIST_ENTRY(list_next(&layout->ranges, &next->h.entry), struct layout_range, h.entry);
5023 *text_len = min(*text_len, layout->len - position);
5025 else {
5026 *locale = NULL;
5027 *text_len = 0;
5030 return S_OK;
5033 static HRESULT WINAPI dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource1 *iface,
5034 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
5036 FIXME("%u %p %p: stub\n", position, text_len, substitution);
5037 return E_NOTIMPL;
5040 static HRESULT WINAPI dwritetextlayout_source_GetVerticalGlyphOrientation(IDWriteTextAnalysisSource1 *iface,
5041 UINT32 position, UINT32 *length, DWRITE_VERTICAL_GLYPH_ORIENTATION *orientation, UINT8 *bidi_level)
5043 FIXME("%u %p %p %p: stub\n", position, length, orientation, bidi_level);
5044 return E_NOTIMPL;
5047 static const IDWriteTextAnalysisSource1Vtbl dwritetextlayoutsourcevtbl = {
5048 dwritetextlayout_source_QueryInterface,
5049 dwritetextlayout_source_AddRef,
5050 dwritetextlayout_source_Release,
5051 dwritetextlayout_source_GetTextAtPosition,
5052 dwritetextlayout_source_GetTextBeforePosition,
5053 dwritetextlayout_source_GetParagraphReadingDirection,
5054 dwritetextlayout_source_GetLocaleName,
5055 dwritetextlayout_source_GetNumberSubstitution,
5056 dwritetextlayout_source_GetVerticalGlyphOrientation
5059 static HRESULT layout_format_from_textformat(struct dwrite_textlayout *layout, IDWriteTextFormat *format)
5061 struct dwrite_textformat *textformat;
5062 IDWriteTextFormat1 *format1;
5063 IDWriteTextFormat3 *format3;
5064 UINT32 len;
5065 HRESULT hr;
5067 if ((textformat = unsafe_impl_from_IDWriteTextFormat(format))) {
5068 layout->format = textformat->format;
5070 layout->format.locale = heap_strdupW(textformat->format.locale);
5071 layout->format.family_name = heap_strdupW(textformat->format.family_name);
5072 if (!layout->format.locale || !layout->format.family_name)
5074 heap_free(layout->format.locale);
5075 heap_free(layout->format.family_name);
5076 return E_OUTOFMEMORY;
5079 if (layout->format.trimmingsign)
5080 IDWriteInlineObject_AddRef(layout->format.trimmingsign);
5081 if (layout->format.collection)
5082 IDWriteFontCollection_AddRef(layout->format.collection);
5083 if (layout->format.fallback)
5084 IDWriteFontFallback_AddRef(layout->format.fallback);
5086 return S_OK;
5089 layout->format.weight = IDWriteTextFormat_GetFontWeight(format);
5090 layout->format.style = IDWriteTextFormat_GetFontStyle(format);
5091 layout->format.stretch = IDWriteTextFormat_GetFontStretch(format);
5092 layout->format.fontsize= IDWriteTextFormat_GetFontSize(format);
5093 layout->format.tabstop = IDWriteTextFormat_GetIncrementalTabStop(format);
5094 layout->format.textalignment = IDWriteTextFormat_GetTextAlignment(format);
5095 layout->format.paralign = IDWriteTextFormat_GetParagraphAlignment(format);
5096 layout->format.wrapping = IDWriteTextFormat_GetWordWrapping(format);
5097 layout->format.readingdir = IDWriteTextFormat_GetReadingDirection(format);
5098 layout->format.flow = IDWriteTextFormat_GetFlowDirection(format);
5099 hr = IDWriteTextFormat_GetLineSpacing(format, &layout->format.spacing.method,
5100 &layout->format.spacing.height, &layout->format.spacing.baseline);
5101 if (FAILED(hr))
5102 return hr;
5104 hr = IDWriteTextFormat_GetTrimming(format, &layout->format.trimming, &layout->format.trimmingsign);
5105 if (FAILED(hr))
5106 return hr;
5108 /* locale name and length */
5109 len = IDWriteTextFormat_GetLocaleNameLength(format);
5110 layout->format.locale = heap_alloc((len+1)*sizeof(WCHAR));
5111 if (!layout->format.locale)
5112 return E_OUTOFMEMORY;
5114 hr = IDWriteTextFormat_GetLocaleName(format, layout->format.locale, len+1);
5115 if (FAILED(hr))
5116 return hr;
5117 layout->format.locale_len = len;
5119 /* font family name and length */
5120 len = IDWriteTextFormat_GetFontFamilyNameLength(format);
5121 layout->format.family_name = heap_alloc((len+1)*sizeof(WCHAR));
5122 if (!layout->format.family_name)
5123 return E_OUTOFMEMORY;
5125 hr = IDWriteTextFormat_GetFontFamilyName(format, layout->format.family_name, len+1);
5126 if (FAILED(hr))
5127 return hr;
5128 layout->format.family_len = len;
5130 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
5131 if (hr == S_OK)
5133 IDWriteTextFormat2 *format2;
5135 layout->format.vertical_orientation = IDWriteTextFormat1_GetVerticalGlyphOrientation(format1);
5136 layout->format.optical_alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
5137 IDWriteTextFormat1_GetFontFallback(format1, &layout->format.fallback);
5139 if (IDWriteTextFormat1_QueryInterface(format1, &IID_IDWriteTextFormat2, (void**)&format2) == S_OK) {
5140 IDWriteTextFormat2_GetLineSpacing(format2, &layout->format.spacing);
5141 IDWriteTextFormat2_Release(format2);
5144 IDWriteTextFormat1_Release(format1);
5147 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat3, (void **)&format3);
5148 if (hr == S_OK)
5150 layout->format.automatic_axes = IDWriteTextFormat3_GetAutomaticFontAxes(format3);
5151 IDWriteTextFormat3_Release(format3);
5154 return IDWriteTextFormat_GetFontCollection(format, &layout->format.collection);
5157 static HRESULT init_textlayout(const struct textlayout_desc *desc, struct dwrite_textlayout *layout)
5159 struct layout_range_header *range, *strike, *underline, *effect, *spacing, *typography;
5160 static const DWRITE_TEXT_RANGE r = { 0, ~0u };
5161 HRESULT hr;
5163 layout->IDWriteTextLayout4_iface.lpVtbl = &dwritetextlayoutvtbl;
5164 layout->IDWriteTextFormat3_iface.lpVtbl = &dwritetextformat3_layout_vtbl;
5165 layout->IDWriteTextAnalysisSink1_iface.lpVtbl = &dwritetextlayoutsinkvtbl;
5166 layout->IDWriteTextAnalysisSource1_iface.lpVtbl = &dwritetextlayoutsourcevtbl;
5167 layout->refcount = 1;
5168 layout->len = desc->length;
5169 layout->recompute = RECOMPUTE_EVERYTHING;
5170 list_init(&layout->eruns);
5171 list_init(&layout->inlineobjects);
5172 list_init(&layout->underlines);
5173 list_init(&layout->strikethrough);
5174 list_init(&layout->runs);
5175 list_init(&layout->ranges);
5176 list_init(&layout->strike_ranges);
5177 list_init(&layout->underline_ranges);
5178 list_init(&layout->effects);
5179 list_init(&layout->spacing);
5180 list_init(&layout->typographies);
5181 layout->metrics.layoutWidth = desc->max_width;
5182 layout->metrics.layoutHeight = desc->max_height;
5184 layout->str = heap_strdupnW(desc->string, desc->length);
5185 if (desc->length && !layout->str) {
5186 hr = E_OUTOFMEMORY;
5187 goto fail;
5190 hr = layout_format_from_textformat(layout, desc->format);
5191 if (FAILED(hr))
5192 goto fail;
5194 range = alloc_layout_range(layout, &r, LAYOUT_RANGE_REGULAR);
5195 strike = alloc_layout_range(layout, &r, LAYOUT_RANGE_STRIKETHROUGH);
5196 underline = alloc_layout_range(layout, &r, LAYOUT_RANGE_UNDERLINE);
5197 effect = alloc_layout_range(layout, &r, LAYOUT_RANGE_EFFECT);
5198 spacing = alloc_layout_range(layout, &r, LAYOUT_RANGE_SPACING);
5199 typography = alloc_layout_range(layout, &r, LAYOUT_RANGE_TYPOGRAPHY);
5200 if (!range || !strike || !effect || !spacing || !typography || !underline) {
5201 free_layout_range(range);
5202 free_layout_range(strike);
5203 free_layout_range(underline);
5204 free_layout_range(effect);
5205 free_layout_range(spacing);
5206 free_layout_range(typography);
5207 hr = E_OUTOFMEMORY;
5208 goto fail;
5211 layout->measuringmode = desc->is_gdi_compatible ? (desc->use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL :
5212 DWRITE_MEASURING_MODE_GDI_CLASSIC) : DWRITE_MEASURING_MODE_NATURAL;
5213 layout->ppdip = desc->ppdip;
5214 layout->transform = desc->transform ? *desc->transform : identity;
5216 layout->factory = desc->factory;
5217 IDWriteFactory7_AddRef(layout->factory);
5218 list_add_head(&layout->ranges, &range->entry);
5219 list_add_head(&layout->strike_ranges, &strike->entry);
5220 list_add_head(&layout->underline_ranges, &underline->entry);
5221 list_add_head(&layout->effects, &effect->entry);
5222 list_add_head(&layout->spacing, &spacing->entry);
5223 list_add_head(&layout->typographies, &typography->entry);
5224 return S_OK;
5226 fail:
5227 IDWriteTextLayout4_Release(&layout->IDWriteTextLayout4_iface);
5228 return hr;
5231 HRESULT create_textlayout(const struct textlayout_desc *desc, IDWriteTextLayout **layout)
5233 struct dwrite_textlayout *object;
5234 HRESULT hr;
5236 *layout = NULL;
5238 if (desc->max_width < 0.0f || desc->max_height < 0.0f)
5239 return E_INVALIDARG;
5241 if (!desc->format || !desc->string)
5242 return E_INVALIDARG;
5244 if (!(object = heap_alloc_zero(sizeof(*object))))
5245 return E_OUTOFMEMORY;
5247 hr = init_textlayout(desc, object);
5248 if (hr == S_OK)
5249 *layout = (IDWriteTextLayout *)&object->IDWriteTextLayout4_iface;
5251 return hr;
5254 static HRESULT WINAPI dwritetrimmingsign_QueryInterface(IDWriteInlineObject *iface, REFIID riid, void **obj)
5256 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5258 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteInlineObject)) {
5259 *obj = iface;
5260 IDWriteInlineObject_AddRef(iface);
5261 return S_OK;
5264 WARN("%s not implemented.\n", debugstr_guid(riid));
5266 *obj = NULL;
5267 return E_NOINTERFACE;
5270 static ULONG WINAPI dwritetrimmingsign_AddRef(IDWriteInlineObject *iface)
5272 struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
5273 ULONG refcount = InterlockedIncrement(&sign->refcount);
5275 TRACE("%p, refcount %d.\n", iface, refcount);
5277 return refcount;
5280 static ULONG WINAPI dwritetrimmingsign_Release(IDWriteInlineObject *iface)
5282 struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
5283 ULONG refcount = InterlockedDecrement(&sign->refcount);
5285 TRACE("%p, refcount %d.\n", iface, refcount);
5287 if (!refcount)
5289 IDWriteTextLayout_Release(sign->layout);
5290 heap_free(sign);
5293 return refcount;
5296 static HRESULT WINAPI dwritetrimmingsign_Draw(IDWriteInlineObject *iface, void *context, IDWriteTextRenderer *renderer,
5297 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *effect)
5299 struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
5300 DWRITE_LINE_METRICS line;
5301 UINT32 line_count;
5303 TRACE("%p, %p, %p, %.2f, %.2f, %d, %d, %p.\n", iface, context, renderer, originX, originY,
5304 is_sideways, is_rtl, effect);
5306 IDWriteTextLayout_GetLineMetrics(sign->layout, &line, 1, &line_count);
5307 return IDWriteTextLayout_Draw(sign->layout, context, renderer, originX, originY - line.baseline);
5310 static HRESULT WINAPI dwritetrimmingsign_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *ret)
5312 struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
5313 DWRITE_TEXT_METRICS metrics;
5314 HRESULT hr;
5316 TRACE("%p, %p.\n", iface, ret);
5318 hr = IDWriteTextLayout_GetMetrics(sign->layout, &metrics);
5319 if (FAILED(hr))
5321 memset(ret, 0, sizeof(*ret));
5322 return hr;
5325 ret->width = metrics.width;
5326 ret->height = 0.0f;
5327 ret->baseline = 0.0f;
5328 ret->supportsSideways = FALSE;
5329 return S_OK;
5332 static HRESULT WINAPI dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
5334 struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
5336 TRACE("%p, %p.\n", iface, overhangs);
5338 return IDWriteTextLayout_GetOverhangMetrics(sign->layout, overhangs);
5341 static HRESULT WINAPI dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
5342 DWRITE_BREAK_CONDITION *after)
5344 TRACE("%p, %p, %p.\n", iface, before, after);
5346 *before = *after = DWRITE_BREAK_CONDITION_NEUTRAL;
5347 return S_OK;
5350 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl =
5352 dwritetrimmingsign_QueryInterface,
5353 dwritetrimmingsign_AddRef,
5354 dwritetrimmingsign_Release,
5355 dwritetrimmingsign_Draw,
5356 dwritetrimmingsign_GetMetrics,
5357 dwritetrimmingsign_GetOverhangMetrics,
5358 dwritetrimmingsign_GetBreakConditions
5361 static inline BOOL is_reading_direction_horz(DWRITE_READING_DIRECTION direction)
5363 return (direction == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT) ||
5364 (direction == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
5367 static inline BOOL is_reading_direction_vert(DWRITE_READING_DIRECTION direction)
5369 return (direction == DWRITE_READING_DIRECTION_TOP_TO_BOTTOM) ||
5370 (direction == DWRITE_READING_DIRECTION_BOTTOM_TO_TOP);
5373 static inline BOOL is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction)
5375 return (direction == DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT) ||
5376 (direction == DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT);
5379 static inline BOOL is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction)
5381 return (direction == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM) ||
5382 (direction == DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP);
5385 HRESULT create_trimmingsign(IDWriteFactory7 *factory, IDWriteTextFormat *format, IDWriteInlineObject **sign)
5387 static const WCHAR ellipsisW = 0x2026;
5388 struct dwrite_trimmingsign *object;
5389 DWRITE_READING_DIRECTION reading;
5390 DWRITE_FLOW_DIRECTION flow;
5391 HRESULT hr;
5393 *sign = NULL;
5395 if (!format)
5396 return E_INVALIDARG;
5398 /* Validate reading/flow direction here, layout creation won't complain about
5399 invalid combinations. */
5400 reading = IDWriteTextFormat_GetReadingDirection(format);
5401 flow = IDWriteTextFormat_GetFlowDirection(format);
5403 if ((is_reading_direction_horz(reading) && is_flow_direction_horz(flow)) ||
5404 (is_reading_direction_vert(reading) && is_flow_direction_vert(flow)))
5405 return DWRITE_E_FLOWDIRECTIONCONFLICTS;
5407 if (!(object = heap_alloc(sizeof(*object))))
5408 return E_OUTOFMEMORY;
5410 object->IDWriteInlineObject_iface.lpVtbl = &dwritetrimmingsignvtbl;
5411 object->refcount = 1;
5413 hr = IDWriteFactory7_CreateTextLayout(factory, &ellipsisW, 1, format, 0.0f, 0.0f, &object->layout);
5414 if (FAILED(hr))
5416 heap_free(object);
5417 return hr;
5420 IDWriteTextLayout_SetWordWrapping(object->layout, DWRITE_WORD_WRAPPING_NO_WRAP);
5421 IDWriteTextLayout_SetParagraphAlignment(object->layout, DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
5422 IDWriteTextLayout_SetTextAlignment(object->layout, DWRITE_TEXT_ALIGNMENT_LEADING);
5424 *sign = &object->IDWriteInlineObject_iface;
5426 return S_OK;
5429 static HRESULT WINAPI dwritetextformat_QueryInterface(IDWriteTextFormat3 *iface, REFIID riid, void **obj)
5431 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5433 if (IsEqualIID(riid, &IID_IDWriteTextFormat3) ||
5434 IsEqualIID(riid, &IID_IDWriteTextFormat2) ||
5435 IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
5436 IsEqualIID(riid, &IID_IDWriteTextFormat) ||
5437 IsEqualIID(riid, &IID_IUnknown))
5439 *obj = iface;
5440 IDWriteTextFormat3_AddRef(iface);
5441 return S_OK;
5444 WARN("%s not implemented.\n", debugstr_guid(riid));
5446 *obj = NULL;
5448 return E_NOINTERFACE;
5451 static ULONG WINAPI dwritetextformat_AddRef(IDWriteTextFormat3 *iface)
5453 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5454 ULONG refcount = InterlockedIncrement(&format->refcount);
5456 TRACE("%p, refcount %d.\n", iface, refcount);
5458 return refcount;
5461 static ULONG WINAPI dwritetextformat_Release(IDWriteTextFormat3 *iface)
5463 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5464 ULONG refcount = InterlockedDecrement(&format->refcount);
5466 TRACE("%p, refcount %d.\n", iface, refcount);
5468 if (!refcount)
5470 release_format_data(&format->format);
5471 heap_free(format);
5474 return refcount;
5477 static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat3 *iface, DWRITE_TEXT_ALIGNMENT alignment)
5479 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5481 TRACE("%p, %d.\n", iface, alignment);
5483 return format_set_textalignment(&format->format, alignment, NULL);
5486 static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat3 *iface,
5487 DWRITE_PARAGRAPH_ALIGNMENT alignment)
5489 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5491 TRACE("%p, %d.\n", iface, alignment);
5493 return format_set_paralignment(&format->format, alignment, NULL);
5496 static HRESULT WINAPI dwritetextformat_SetWordWrapping(IDWriteTextFormat3 *iface, DWRITE_WORD_WRAPPING wrapping)
5498 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5500 TRACE("%p, %d.\n", iface, wrapping);
5502 return format_set_wordwrapping(&format->format, wrapping, NULL);
5505 static HRESULT WINAPI dwritetextformat_SetReadingDirection(IDWriteTextFormat3 *iface, DWRITE_READING_DIRECTION direction)
5507 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5509 TRACE("%p, %d.\n", iface, direction);
5511 return format_set_readingdirection(&format->format, direction, NULL);
5514 static HRESULT WINAPI dwritetextformat_SetFlowDirection(IDWriteTextFormat3 *iface, DWRITE_FLOW_DIRECTION direction)
5516 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5518 TRACE("%p, %d.\n", iface, direction);
5520 return format_set_flowdirection(&format->format, direction, NULL);
5523 static HRESULT WINAPI dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat3 *iface, FLOAT tabstop)
5525 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5527 TRACE("%p, %f.\n", iface, tabstop);
5529 if (tabstop <= 0.0f)
5530 return E_INVALIDARG;
5532 format->format.tabstop = tabstop;
5533 return S_OK;
5536 static HRESULT WINAPI dwritetextformat_SetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING const *trimming,
5537 IDWriteInlineObject *trimming_sign)
5539 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5541 TRACE("%p, %p, %p.\n", iface, trimming, trimming_sign);
5543 return format_set_trimming(&format->format, trimming, trimming_sign, NULL);
5546 static HRESULT WINAPI dwritetextformat_SetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING_METHOD method,
5547 FLOAT height, FLOAT baseline)
5549 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5550 DWRITE_LINE_SPACING spacing;
5552 TRACE("%p, %d, %f, %f.\n", iface, method, height, baseline);
5554 spacing = format->format.spacing;
5555 spacing.method = method;
5556 spacing.height = height;
5557 spacing.baseline = baseline;
5559 return format_set_linespacing(&format->format, &spacing, NULL);
5562 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_GetTextAlignment(IDWriteTextFormat3 *iface)
5564 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5566 TRACE("%p.\n", iface);
5568 return format->format.textalignment;
5571 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_GetParagraphAlignment(IDWriteTextFormat3 *iface)
5573 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5575 TRACE("%p.\n", iface);
5577 return format->format.paralign;
5580 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_GetWordWrapping(IDWriteTextFormat3 *iface)
5582 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5584 TRACE("%p.\n", iface);
5586 return format->format.wrapping;
5589 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_GetReadingDirection(IDWriteTextFormat3 *iface)
5591 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5593 TRACE("%p.\n", iface);
5595 return format->format.readingdir;
5598 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_GetFlowDirection(IDWriteTextFormat3 *iface)
5600 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5602 TRACE("%p.\n", iface);
5604 return format->format.flow;
5607 static FLOAT WINAPI dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat3 *iface)
5609 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5611 TRACE("%p.\n", iface);
5613 return format->format.tabstop;
5616 static HRESULT WINAPI dwritetextformat_GetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING *options,
5617 IDWriteInlineObject **trimming_sign)
5619 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5621 TRACE("%p, %p, %p.\n", iface, options, trimming_sign);
5623 *options = format->format.trimming;
5624 if ((*trimming_sign = format->format.trimmingsign))
5625 IDWriteInlineObject_AddRef(*trimming_sign);
5627 return S_OK;
5630 static HRESULT WINAPI dwritetextformat_GetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING_METHOD *method,
5631 FLOAT *spacing, FLOAT *baseline)
5633 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5635 TRACE("%p, %p, %p, %p.\n", iface, method, spacing, baseline);
5637 *method = format->format.spacing.method;
5638 *spacing = format->format.spacing.height;
5639 *baseline = format->format.spacing.baseline;
5640 return S_OK;
5643 static HRESULT WINAPI dwritetextformat_GetFontCollection(IDWriteTextFormat3 *iface, IDWriteFontCollection **collection)
5645 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5647 TRACE("%p, %p.\n", iface, collection);
5649 *collection = format->format.collection;
5650 IDWriteFontCollection_AddRef(*collection);
5652 return S_OK;
5655 static UINT32 WINAPI dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat3 *iface)
5657 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5659 TRACE("%p.\n", iface);
5661 return format->format.family_len;
5664 static HRESULT WINAPI dwritetextformat_GetFontFamilyName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
5666 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5668 TRACE("%p, %p, %u.\n", iface, name, size);
5670 if (size <= format->format.family_len)
5671 return E_NOT_SUFFICIENT_BUFFER;
5672 strcpyW(name, format->format.family_name);
5673 return S_OK;
5676 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_GetFontWeight(IDWriteTextFormat3 *iface)
5678 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5680 TRACE("%p.\n", iface);
5682 return format->format.weight;
5685 static DWRITE_FONT_STYLE WINAPI dwritetextformat_GetFontStyle(IDWriteTextFormat3 *iface)
5687 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5689 TRACE("%p.\n", iface);
5691 return format->format.style;
5694 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_GetFontStretch(IDWriteTextFormat3 *iface)
5696 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5698 TRACE("%p.\n", iface);
5700 return format->format.stretch;
5703 static FLOAT WINAPI dwritetextformat_GetFontSize(IDWriteTextFormat3 *iface)
5705 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5707 TRACE("%p.\n", iface);
5709 return format->format.fontsize;
5712 static UINT32 WINAPI dwritetextformat_GetLocaleNameLength(IDWriteTextFormat3 *iface)
5714 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5716 TRACE("%p.\n", iface);
5718 return format->format.locale_len;
5721 static HRESULT WINAPI dwritetextformat_GetLocaleName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
5723 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5725 TRACE("%p, %p %u.\n", iface, name, size);
5727 if (size <= format->format.locale_len)
5728 return E_NOT_SUFFICIENT_BUFFER;
5729 strcpyW(name, format->format.locale);
5730 return S_OK;
5733 static HRESULT WINAPI dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat3 *iface,
5734 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
5736 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5738 TRACE("%p, %d.\n", iface, orientation);
5740 return format_set_vertical_orientation(&format->format, orientation, NULL);
5743 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat3 *iface)
5745 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5747 TRACE("%p.\n", iface);
5749 return format->format.vertical_orientation;
5752 static HRESULT WINAPI dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat3 *iface, BOOL lastline_wrapping_enabled)
5754 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5756 TRACE("%p, %d.\n", iface, lastline_wrapping_enabled);
5758 format->format.last_line_wrapping = !!lastline_wrapping_enabled;
5759 return S_OK;
5762 static BOOL WINAPI dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat3 *iface)
5764 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5766 TRACE("%p.\n", iface);
5768 return format->format.last_line_wrapping;
5771 static HRESULT WINAPI dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat3 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
5773 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5775 TRACE("%p, %d.\n", iface, alignment);
5777 return format_set_optical_alignment(&format->format, alignment);
5780 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat3 *iface)
5782 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5784 TRACE("%p.\n", iface);
5786 return format->format.optical_alignment;
5789 static HRESULT WINAPI dwritetextformat1_SetFontFallback(IDWriteTextFormat3 *iface, IDWriteFontFallback *fallback)
5791 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5793 TRACE("%p, %p.\n", iface, fallback);
5795 return set_fontfallback_for_format(&format->format, fallback);
5798 static HRESULT WINAPI dwritetextformat1_GetFontFallback(IDWriteTextFormat3 *iface, IDWriteFontFallback **fallback)
5800 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5802 TRACE("%p, %p.\n", iface, fallback);
5804 return get_fontfallback_from_format(&format->format, fallback);
5807 static HRESULT WINAPI dwritetextformat2_SetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING const *spacing)
5809 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5811 TRACE("%p, %p.\n", iface, spacing);
5813 return format_set_linespacing(&format->format, spacing, NULL);
5816 static HRESULT WINAPI dwritetextformat2_GetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING *spacing)
5818 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5820 TRACE("%p, %p.\n", iface, spacing);
5822 *spacing = format->format.spacing;
5823 return S_OK;
5826 static HRESULT WINAPI dwritetextformat3_SetFontAxisValues(IDWriteTextFormat3 *iface,
5827 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values)
5829 FIXME("%p, %p, %u.\n", iface, axis_values, num_values);
5831 return E_NOTIMPL;
5834 static UINT32 WINAPI dwritetextformat3_GetFontAxisValueCount(IDWriteTextFormat3 *iface)
5836 FIXME("%p.\n", iface);
5838 return 0;
5841 static HRESULT WINAPI dwritetextformat3_GetFontAxisValues(IDWriteTextFormat3 *iface,
5842 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values)
5844 FIXME("%p, %p, %u.\n", iface, axis_values, num_values);
5846 return E_NOTIMPL;
5849 static DWRITE_AUTOMATIC_FONT_AXES WINAPI dwritetextformat3_GetAutomaticFontAxes(IDWriteTextFormat3 *iface)
5851 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5853 TRACE("%p.\n", iface);
5855 return format->format.automatic_axes;
5858 static HRESULT WINAPI dwritetextformat3_SetAutomaticFontAxes(IDWriteTextFormat3 *iface, DWRITE_AUTOMATIC_FONT_AXES axes)
5860 struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
5862 TRACE("%p, %d.\n", iface, axes);
5864 format->format.automatic_axes = axes;
5866 return S_OK;
5869 static const IDWriteTextFormat3Vtbl dwritetextformatvtbl =
5871 dwritetextformat_QueryInterface,
5872 dwritetextformat_AddRef,
5873 dwritetextformat_Release,
5874 dwritetextformat_SetTextAlignment,
5875 dwritetextformat_SetParagraphAlignment,
5876 dwritetextformat_SetWordWrapping,
5877 dwritetextformat_SetReadingDirection,
5878 dwritetextformat_SetFlowDirection,
5879 dwritetextformat_SetIncrementalTabStop,
5880 dwritetextformat_SetTrimming,
5881 dwritetextformat_SetLineSpacing,
5882 dwritetextformat_GetTextAlignment,
5883 dwritetextformat_GetParagraphAlignment,
5884 dwritetextformat_GetWordWrapping,
5885 dwritetextformat_GetReadingDirection,
5886 dwritetextformat_GetFlowDirection,
5887 dwritetextformat_GetIncrementalTabStop,
5888 dwritetextformat_GetTrimming,
5889 dwritetextformat_GetLineSpacing,
5890 dwritetextformat_GetFontCollection,
5891 dwritetextformat_GetFontFamilyNameLength,
5892 dwritetextformat_GetFontFamilyName,
5893 dwritetextformat_GetFontWeight,
5894 dwritetextformat_GetFontStyle,
5895 dwritetextformat_GetFontStretch,
5896 dwritetextformat_GetFontSize,
5897 dwritetextformat_GetLocaleNameLength,
5898 dwritetextformat_GetLocaleName,
5899 dwritetextformat1_SetVerticalGlyphOrientation,
5900 dwritetextformat1_GetVerticalGlyphOrientation,
5901 dwritetextformat1_SetLastLineWrapping,
5902 dwritetextformat1_GetLastLineWrapping,
5903 dwritetextformat1_SetOpticalAlignment,
5904 dwritetextformat1_GetOpticalAlignment,
5905 dwritetextformat1_SetFontFallback,
5906 dwritetextformat1_GetFontFallback,
5907 dwritetextformat2_SetLineSpacing,
5908 dwritetextformat2_GetLineSpacing,
5909 dwritetextformat3_SetFontAxisValues,
5910 dwritetextformat3_GetFontAxisValueCount,
5911 dwritetextformat3_GetFontAxisValues,
5912 dwritetextformat3_GetAutomaticFontAxes,
5913 dwritetextformat3_SetAutomaticFontAxes,
5916 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat *iface)
5918 return (iface->lpVtbl == (IDWriteTextFormatVtbl*)&dwritetextformatvtbl) ?
5919 CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat3_iface) : NULL;
5922 HRESULT create_textformat(const WCHAR *family_name, IDWriteFontCollection *collection, DWRITE_FONT_WEIGHT weight,
5923 DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, FLOAT size, const WCHAR *locale, IDWriteTextFormat **format)
5925 struct dwrite_textformat *object;
5927 *format = NULL;
5929 if (size <= 0.0f)
5930 return E_INVALIDARG;
5932 if (((UINT32)weight > DWRITE_FONT_WEIGHT_ULTRA_BLACK) ||
5933 ((UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED) ||
5934 ((UINT32)style > DWRITE_FONT_STYLE_ITALIC))
5935 return E_INVALIDARG;
5937 if (!(object = heap_alloc_zero(sizeof(*object))))
5938 return E_OUTOFMEMORY;
5940 object->IDWriteTextFormat3_iface.lpVtbl = &dwritetextformatvtbl;
5941 object->refcount = 1;
5942 object->format.family_name = heap_strdupW(family_name);
5943 object->format.family_len = strlenW(family_name);
5944 object->format.locale = heap_strdupW(locale);
5945 object->format.locale_len = strlenW(locale);
5946 /* Force locale name to lower case, layout will inherit this modified value. */
5947 strlwrW(object->format.locale);
5948 object->format.weight = weight;
5949 object->format.style = style;
5950 object->format.fontsize = size;
5951 object->format.tabstop = 4.0f * size;
5952 object->format.stretch = stretch;
5953 object->format.last_line_wrapping = TRUE;
5954 object->format.collection = collection;
5955 IDWriteFontCollection_AddRef(object->format.collection);
5957 *format = (IDWriteTextFormat *)&object->IDWriteTextFormat3_iface;
5959 return S_OK;
5962 static HRESULT WINAPI dwritetypography_QueryInterface(IDWriteTypography *iface, REFIID riid, void **obj)
5964 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5966 if (IsEqualIID(riid, &IID_IDWriteTypography) || IsEqualIID(riid, &IID_IUnknown)) {
5967 *obj = iface;
5968 IDWriteTypography_AddRef(iface);
5969 return S_OK;
5972 WARN("%s not implemented.\n", debugstr_guid(riid));
5974 *obj = NULL;
5976 return E_NOINTERFACE;
5979 static ULONG WINAPI dwritetypography_AddRef(IDWriteTypography *iface)
5981 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5982 ULONG refcount = InterlockedIncrement(&typography->refcount);
5984 TRACE("%p, refcount %d.\n", iface, refcount);
5986 return refcount;
5989 static ULONG WINAPI dwritetypography_Release(IDWriteTypography *iface)
5991 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5992 ULONG refcount = InterlockedDecrement(&typography->refcount);
5994 TRACE("%p, refcount %d.\n", iface, refcount);
5996 if (!refcount)
5998 heap_free(typography->features);
5999 heap_free(typography);
6002 return refcount;
6005 static HRESULT WINAPI dwritetypography_AddFontFeature(IDWriteTypography *iface, DWRITE_FONT_FEATURE feature)
6007 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
6009 TRACE("%p, %s, %u.\n", iface, debugstr_tag(feature.nameTag), feature.parameter);
6011 if (!dwrite_array_reserve((void **)&typography->features, &typography->capacity, typography->count + 1,
6012 sizeof(*typography->features)))
6014 return E_OUTOFMEMORY;
6017 typography->features[typography->count++] = feature;
6019 return S_OK;
6022 static UINT32 WINAPI dwritetypography_GetFontFeatureCount(IDWriteTypography *iface)
6024 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
6026 TRACE("%p.\n", iface);
6028 return typography->count;
6031 static HRESULT WINAPI dwritetypography_GetFontFeature(IDWriteTypography *iface, UINT32 index,
6032 DWRITE_FONT_FEATURE *feature)
6034 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
6036 TRACE("%p, %u, %p.\n", iface, index, feature);
6038 if (index >= typography->count)
6039 return E_INVALIDARG;
6041 *feature = typography->features[index];
6042 return S_OK;
6045 static const IDWriteTypographyVtbl dwritetypographyvtbl = {
6046 dwritetypography_QueryInterface,
6047 dwritetypography_AddRef,
6048 dwritetypography_Release,
6049 dwritetypography_AddFontFeature,
6050 dwritetypography_GetFontFeatureCount,
6051 dwritetypography_GetFontFeature
6054 HRESULT create_typography(IDWriteTypography **ret)
6056 struct dwrite_typography *typography;
6058 *ret = NULL;
6060 typography = heap_alloc_zero(sizeof(*typography));
6061 if (!typography)
6062 return E_OUTOFMEMORY;
6064 typography->IDWriteTypography_iface.lpVtbl = &dwritetypographyvtbl;
6065 typography->refcount = 1;
6067 *ret = &typography->IDWriteTypography_iface;
6069 return S_OK;