d3dx9/tests: Avoid SIZE_T in traces.
[wine.git] / dlls / dwrite / layout.c
blob2f59c0c4e729bd91dd600d31a2cdb8bd18ed3f39
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 <stdarg.h>
24 #include <math.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "dwrite_private.h"
30 #include "scripts.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
34 struct dwrite_textformat_data {
35 WCHAR *family_name;
36 UINT32 family_len;
37 WCHAR *locale;
38 UINT32 locale_len;
40 DWRITE_FONT_WEIGHT weight;
41 DWRITE_FONT_STYLE style;
42 DWRITE_FONT_STRETCH stretch;
44 DWRITE_PARAGRAPH_ALIGNMENT paralign;
45 DWRITE_READING_DIRECTION readingdir;
46 DWRITE_WORD_WRAPPING wrapping;
47 BOOL last_line_wrapping;
48 DWRITE_TEXT_ALIGNMENT textalignment;
49 DWRITE_FLOW_DIRECTION flow;
50 DWRITE_VERTICAL_GLYPH_ORIENTATION vertical_orientation;
51 DWRITE_OPTICAL_ALIGNMENT optical_alignment;
52 DWRITE_LINE_SPACING spacing;
54 FLOAT fontsize;
56 DWRITE_TRIMMING trimming;
57 IDWriteInlineObject *trimmingsign;
59 IDWriteFontCollection *collection;
60 IDWriteFontFallback *fallback;
63 enum layout_range_attr_kind {
64 LAYOUT_RANGE_ATTR_WEIGHT,
65 LAYOUT_RANGE_ATTR_STYLE,
66 LAYOUT_RANGE_ATTR_STRETCH,
67 LAYOUT_RANGE_ATTR_FONTSIZE,
68 LAYOUT_RANGE_ATTR_EFFECT,
69 LAYOUT_RANGE_ATTR_INLINE,
70 LAYOUT_RANGE_ATTR_UNDERLINE,
71 LAYOUT_RANGE_ATTR_STRIKETHROUGH,
72 LAYOUT_RANGE_ATTR_PAIR_KERNING,
73 LAYOUT_RANGE_ATTR_FONTCOLL,
74 LAYOUT_RANGE_ATTR_LOCALE,
75 LAYOUT_RANGE_ATTR_FONTFAMILY,
76 LAYOUT_RANGE_ATTR_SPACING,
77 LAYOUT_RANGE_ATTR_TYPOGRAPHY
80 struct layout_range_attr_value {
81 DWRITE_TEXT_RANGE range;
82 union {
83 DWRITE_FONT_WEIGHT weight;
84 DWRITE_FONT_STYLE style;
85 DWRITE_FONT_STRETCH stretch;
86 FLOAT fontsize;
87 IDWriteInlineObject *object;
88 IUnknown *effect;
89 BOOL underline;
90 BOOL strikethrough;
91 BOOL pair_kerning;
92 IDWriteFontCollection *collection;
93 const WCHAR *locale;
94 const WCHAR *fontfamily;
95 FLOAT spacing[3]; /* in arguments order - leading, trailing, advance */
96 IDWriteTypography *typography;
97 } u;
100 enum layout_range_kind {
101 LAYOUT_RANGE_REGULAR,
102 LAYOUT_RANGE_UNDERLINE,
103 LAYOUT_RANGE_STRIKETHROUGH,
104 LAYOUT_RANGE_EFFECT,
105 LAYOUT_RANGE_SPACING,
106 LAYOUT_RANGE_TYPOGRAPHY
109 struct layout_range_header {
110 struct list entry;
111 enum layout_range_kind kind;
112 DWRITE_TEXT_RANGE range;
115 struct layout_range {
116 struct layout_range_header h;
117 DWRITE_FONT_WEIGHT weight;
118 DWRITE_FONT_STYLE style;
119 FLOAT fontsize;
120 DWRITE_FONT_STRETCH stretch;
121 IDWriteInlineObject *object;
122 BOOL pair_kerning;
123 IDWriteFontCollection *collection;
124 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
125 WCHAR *fontfamily;
128 struct layout_range_bool {
129 struct layout_range_header h;
130 BOOL value;
133 struct layout_range_iface {
134 struct layout_range_header h;
135 IUnknown *iface;
138 struct layout_range_spacing {
139 struct layout_range_header h;
140 FLOAT leading;
141 FLOAT trailing;
142 FLOAT min_advance;
145 enum layout_run_kind {
146 LAYOUT_RUN_REGULAR,
147 LAYOUT_RUN_INLINE
150 struct inline_object_run {
151 IDWriteInlineObject *object;
152 UINT16 length;
155 struct regular_layout_run {
156 DWRITE_GLYPH_RUN_DESCRIPTION descr;
157 DWRITE_GLYPH_RUN run;
158 DWRITE_SCRIPT_ANALYSIS sa;
159 UINT16 *glyphs;
160 UINT16 *clustermap;
161 FLOAT *advances;
162 DWRITE_GLYPH_OFFSET *offsets;
163 /* this is actual glyph count after shaping, it's not necessary the same as reported to Draw() */
164 UINT32 glyphcount;
167 struct layout_run {
168 struct list entry;
169 enum layout_run_kind kind;
170 union {
171 struct inline_object_run object;
172 struct regular_layout_run regular;
173 } u;
174 FLOAT baseline;
175 FLOAT height;
178 struct layout_effective_run {
179 struct list entry;
180 const struct layout_run *run; /* nominal run this one is based on */
181 UINT32 start; /* relative text position, 0 means first text position of a nominal run */
182 UINT32 length; /* length in codepoints that this run covers */
183 UINT32 glyphcount; /* total glyph count in this run */
184 IUnknown *effect; /* original reference is kept only at range level */
185 D2D1_POINT_2F origin; /* baseline origin */
186 FLOAT align_dx; /* adjustment from text alignment */
187 FLOAT width; /* run width */
188 UINT16 *clustermap; /* effective clustermap, allocated separately, is not reused from nominal map */
189 UINT32 line; /* 0-based line index in line metrics array */
190 BOOL underlined; /* set if this run is underlined */
191 D2D1_RECT_F bbox; /* ink run box, top == bottom means it wasn't estimated yet */
194 struct layout_effective_inline {
195 struct list entry;
196 IDWriteInlineObject *object; /* inline object, set explicitly or added when trimming a line */
197 IUnknown *effect; /* original reference is kept only at range level */
198 FLOAT baseline;
199 D2D1_POINT_2F origin; /* left top corner */
200 FLOAT align_dx; /* adjustment from text alignment */
201 FLOAT width; /* object width as it's reported it */
202 BOOL is_sideways; /* vertical flow direction flag passed to Draw */
203 BOOL is_rtl; /* bidi flag passed to Draw */
204 UINT32 line; /* 0-based line index in line metrics array */
207 struct layout_underline {
208 struct list entry;
209 const struct layout_effective_run *run;
210 DWRITE_UNDERLINE u;
213 struct layout_strikethrough {
214 struct list entry;
215 const struct layout_effective_run *run;
216 DWRITE_STRIKETHROUGH s;
219 struct layout_cluster {
220 const struct layout_run *run; /* link to nominal run this cluster belongs to */
221 UINT32 position; /* relative to run, first cluster has 0 position */
224 struct layout_line {
225 FLOAT height; /* height based on content */
226 FLOAT baseline; /* baseline based on content */
229 enum layout_recompute_mask {
230 RECOMPUTE_CLUSTERS = 1 << 0,
231 RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
232 RECOMPUTE_LINES = 1 << 2,
233 RECOMPUTE_OVERHANGS = 1 << 3,
234 RECOMPUTE_LINES_AND_OVERHANGS = RECOMPUTE_LINES | RECOMPUTE_OVERHANGS,
235 RECOMPUTE_EVERYTHING = 0xffff
238 struct dwrite_textlayout {
239 IDWriteTextLayout3 IDWriteTextLayout3_iface;
240 IDWriteTextFormat1 IDWriteTextFormat1_iface;
241 IDWriteTextAnalysisSink1 IDWriteTextAnalysisSink1_iface;
242 IDWriteTextAnalysisSource1 IDWriteTextAnalysisSource1_iface;
243 LONG ref;
245 IDWriteFactory5 *factory;
247 WCHAR *str;
248 UINT32 len;
249 struct dwrite_textformat_data format;
250 struct list strike_ranges;
251 struct list underline_ranges;
252 struct list typographies;
253 struct list effects;
254 struct list spacing;
255 struct list ranges;
256 struct list runs;
257 /* lists ready to use by Draw() */
258 struct list eruns;
259 struct list inlineobjects;
260 struct list underlines;
261 struct list strikethrough;
262 USHORT recompute;
264 DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
265 DWRITE_LINE_BREAKPOINT *actual_breakpoints;
267 struct layout_cluster *clusters;
268 DWRITE_CLUSTER_METRICS *clustermetrics;
269 UINT32 cluster_count;
270 FLOAT minwidth;
272 struct layout_line *lines;
273 DWRITE_LINE_METRICS1 *linemetrics;
274 UINT32 line_alloc;
276 DWRITE_TEXT_METRICS1 metrics;
277 DWRITE_OVERHANG_METRICS overhangs;
279 DWRITE_MEASURING_MODE measuringmode;
281 /* gdi-compatible layout specifics */
282 FLOAT ppdip;
283 DWRITE_MATRIX transform;
286 struct dwrite_textformat {
287 IDWriteTextFormat2 IDWriteTextFormat2_iface;
288 LONG ref;
289 struct dwrite_textformat_data format;
292 struct dwrite_trimmingsign {
293 IDWriteInlineObject IDWriteInlineObject_iface;
294 LONG ref;
296 IDWriteTextLayout *layout;
299 struct dwrite_typography {
300 IDWriteTypography IDWriteTypography_iface;
301 LONG ref;
303 DWRITE_FONT_FEATURE *features;
304 UINT32 allocated;
305 UINT32 count;
308 static const IDWriteTextFormat2Vtbl dwritetextformatvtbl;
310 static void release_format_data(struct dwrite_textformat_data *data)
312 if (data->collection) IDWriteFontCollection_Release(data->collection);
313 if (data->fallback) IDWriteFontFallback_Release(data->fallback);
314 if (data->trimmingsign) IDWriteInlineObject_Release(data->trimmingsign);
315 heap_free(data->family_name);
316 heap_free(data->locale);
319 static inline struct dwrite_textlayout *impl_from_IDWriteTextLayout3(IDWriteTextLayout3 *iface)
321 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextLayout3_iface);
324 static inline struct dwrite_textlayout *impl_layout_from_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
326 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextFormat1_iface);
329 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSink1(IDWriteTextAnalysisSink1 *iface)
331 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSink1_iface);
334 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSource1(IDWriteTextAnalysisSource1 *iface)
336 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSource1_iface);
339 static inline struct dwrite_textformat *impl_from_IDWriteTextFormat2(IDWriteTextFormat2 *iface)
341 return CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat2_iface);
344 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat*);
346 static inline struct dwrite_trimmingsign *impl_from_IDWriteInlineObject(IDWriteInlineObject *iface)
348 return CONTAINING_RECORD(iface, struct dwrite_trimmingsign, IDWriteInlineObject_iface);
351 static inline struct dwrite_typography *impl_from_IDWriteTypography(IDWriteTypography *iface)
353 return CONTAINING_RECORD(iface, struct dwrite_typography, IDWriteTypography_iface);
356 static inline const char *debugstr_rundescr(const DWRITE_GLYPH_RUN_DESCRIPTION *descr)
358 return wine_dbg_sprintf("[%u,%u)", descr->textPosition, descr->textPosition + descr->stringLength);
361 static inline BOOL is_layout_gdi_compatible(struct dwrite_textlayout *layout)
363 return layout->measuringmode != DWRITE_MEASURING_MODE_NATURAL;
366 static inline HRESULT format_set_textalignment(struct dwrite_textformat_data *format, DWRITE_TEXT_ALIGNMENT alignment,
367 BOOL *changed)
369 if ((UINT32)alignment > DWRITE_TEXT_ALIGNMENT_JUSTIFIED)
370 return E_INVALIDARG;
371 if (changed) *changed = format->textalignment != alignment;
372 format->textalignment = alignment;
373 return S_OK;
376 static inline HRESULT format_set_paralignment(struct dwrite_textformat_data *format,
377 DWRITE_PARAGRAPH_ALIGNMENT alignment, BOOL *changed)
379 if ((UINT32)alignment > DWRITE_PARAGRAPH_ALIGNMENT_CENTER)
380 return E_INVALIDARG;
381 if (changed) *changed = format->paralign != alignment;
382 format->paralign = alignment;
383 return S_OK;
386 static inline HRESULT format_set_readingdirection(struct dwrite_textformat_data *format,
387 DWRITE_READING_DIRECTION direction, BOOL *changed)
389 if ((UINT32)direction > DWRITE_READING_DIRECTION_BOTTOM_TO_TOP)
390 return E_INVALIDARG;
391 if (changed) *changed = format->readingdir != direction;
392 format->readingdir = direction;
393 return S_OK;
396 static inline HRESULT format_set_wordwrapping(struct dwrite_textformat_data *format,
397 DWRITE_WORD_WRAPPING wrapping, BOOL *changed)
399 if ((UINT32)wrapping > DWRITE_WORD_WRAPPING_CHARACTER)
400 return E_INVALIDARG;
401 if (changed) *changed = format->wrapping != wrapping;
402 format->wrapping = wrapping;
403 return S_OK;
406 static inline HRESULT format_set_flowdirection(struct dwrite_textformat_data *format,
407 DWRITE_FLOW_DIRECTION direction, BOOL *changed)
409 if ((UINT32)direction > DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT)
410 return E_INVALIDARG;
411 if (changed) *changed = format->flow != direction;
412 format->flow = direction;
413 return S_OK;
416 static inline HRESULT format_set_trimming(struct dwrite_textformat_data *format,
417 DWRITE_TRIMMING const *trimming, IDWriteInlineObject *trimming_sign, BOOL *changed)
419 if (changed)
420 *changed = FALSE;
422 if ((UINT32)trimming->granularity > DWRITE_TRIMMING_GRANULARITY_WORD)
423 return E_INVALIDARG;
425 if (changed) {
426 *changed = !!memcmp(&format->trimming, trimming, sizeof(*trimming));
427 if (format->trimmingsign != trimming_sign)
428 *changed = TRUE;
431 format->trimming = *trimming;
432 if (format->trimmingsign)
433 IDWriteInlineObject_Release(format->trimmingsign);
434 format->trimmingsign = trimming_sign;
435 if (format->trimmingsign)
436 IDWriteInlineObject_AddRef(format->trimmingsign);
437 return S_OK;
440 static inline HRESULT format_set_linespacing(struct dwrite_textformat_data *format,
441 DWRITE_LINE_SPACING const *spacing, BOOL *changed)
443 if (spacing->height < 0.0f || spacing->leadingBefore < 0.0f || spacing->leadingBefore > 1.0f ||
444 (UINT32)spacing->method > DWRITE_LINE_SPACING_METHOD_PROPORTIONAL)
445 return E_INVALIDARG;
447 if (changed)
448 *changed = memcmp(spacing, &format->spacing, sizeof(*spacing));
450 format->spacing = *spacing;
451 return S_OK;
454 static HRESULT get_fontfallback_from_format(const struct dwrite_textformat_data *format, IDWriteFontFallback **fallback)
456 *fallback = format->fallback;
457 if (*fallback)
458 IDWriteFontFallback_AddRef(*fallback);
459 return S_OK;
462 static HRESULT set_fontfallback_for_format(struct dwrite_textformat_data *format, IDWriteFontFallback *fallback)
464 if (format->fallback)
465 IDWriteFontFallback_Release(format->fallback);
466 format->fallback = fallback;
467 if (fallback)
468 IDWriteFontFallback_AddRef(fallback);
469 return S_OK;
472 static HRESULT format_set_optical_alignment(struct dwrite_textformat_data *format,
473 DWRITE_OPTICAL_ALIGNMENT alignment)
475 if ((UINT32)alignment > DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS)
476 return E_INVALIDARG;
477 format->optical_alignment = alignment;
478 return S_OK;
481 static BOOL is_run_rtl(const struct layout_effective_run *run)
483 return run->run->u.regular.run.bidiLevel & 1;
486 static struct layout_run *alloc_layout_run(enum layout_run_kind kind)
488 struct layout_run *ret;
490 ret = heap_alloc(sizeof(*ret));
491 if (!ret) return NULL;
493 memset(ret, 0, sizeof(*ret));
494 ret->kind = kind;
495 if (kind == LAYOUT_RUN_REGULAR) {
496 ret->u.regular.sa.script = Script_Unknown;
497 ret->u.regular.sa.shapes = DWRITE_SCRIPT_SHAPES_DEFAULT;
500 return ret;
503 static void free_layout_runs(struct dwrite_textlayout *layout)
505 struct layout_run *cur, *cur2;
506 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->runs, struct layout_run, entry) {
507 list_remove(&cur->entry);
508 if (cur->kind == LAYOUT_RUN_REGULAR) {
509 if (cur->u.regular.run.fontFace)
510 IDWriteFontFace_Release(cur->u.regular.run.fontFace);
511 heap_free(cur->u.regular.glyphs);
512 heap_free(cur->u.regular.clustermap);
513 heap_free(cur->u.regular.advances);
514 heap_free(cur->u.regular.offsets);
516 heap_free(cur);
520 static void free_layout_eruns(struct dwrite_textlayout *layout)
522 struct layout_effective_inline *in, *in2;
523 struct layout_effective_run *cur, *cur2;
524 struct layout_strikethrough *s, *s2;
525 struct layout_underline *u, *u2;
527 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->eruns, struct layout_effective_run, entry) {
528 list_remove(&cur->entry);
529 heap_free(cur->clustermap);
530 heap_free(cur);
533 LIST_FOR_EACH_ENTRY_SAFE(in, in2, &layout->inlineobjects, struct layout_effective_inline, entry) {
534 list_remove(&in->entry);
535 heap_free(in);
538 LIST_FOR_EACH_ENTRY_SAFE(u, u2, &layout->underlines, struct layout_underline, entry) {
539 list_remove(&u->entry);
540 heap_free(u);
543 LIST_FOR_EACH_ENTRY_SAFE(s, s2, &layout->strikethrough, struct layout_strikethrough, entry) {
544 list_remove(&s->entry);
545 heap_free(s);
549 /* Used to resolve break condition by forcing stronger condition over weaker. */
550 static inline DWRITE_BREAK_CONDITION override_break_condition(DWRITE_BREAK_CONDITION existingbreak, DWRITE_BREAK_CONDITION newbreak)
552 switch (existingbreak) {
553 case DWRITE_BREAK_CONDITION_NEUTRAL:
554 return newbreak;
555 case DWRITE_BREAK_CONDITION_CAN_BREAK:
556 return newbreak == DWRITE_BREAK_CONDITION_NEUTRAL ? existingbreak : newbreak;
557 /* let's keep stronger conditions as is */
558 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK:
559 case DWRITE_BREAK_CONDITION_MUST_BREAK:
560 break;
561 default:
562 ERR("unknown break condition %d\n", existingbreak);
565 return existingbreak;
568 /* This helper should be used to get effective range length, in other words it returns number of text
569 positions from range starting point to the end of the range, limited by layout text length */
570 static inline UINT32 get_clipped_range_length(const struct dwrite_textlayout *layout, const struct layout_range *range)
572 if (range->h.range.startPosition + range->h.range.length <= layout->len)
573 return range->h.range.length;
574 return layout->len - range->h.range.startPosition;
577 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
578 static HRESULT layout_update_breakpoints_range(struct dwrite_textlayout *layout, const struct layout_range *cur)
580 DWRITE_BREAK_CONDITION before, after;
581 UINT32 i, length;
582 HRESULT hr;
584 /* ignore returned conditions if failed */
585 hr = IDWriteInlineObject_GetBreakConditions(cur->object, &before, &after);
586 if (FAILED(hr))
587 after = before = DWRITE_BREAK_CONDITION_NEUTRAL;
589 if (!layout->actual_breakpoints) {
590 layout->actual_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
591 if (!layout->actual_breakpoints)
592 return E_OUTOFMEMORY;
593 memcpy(layout->actual_breakpoints, layout->nominal_breakpoints, sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
596 length = get_clipped_range_length(layout, cur);
597 for (i = cur->h.range.startPosition; i < length + cur->h.range.startPosition; i++) {
598 /* for first codepoint check if there's anything before it and update accordingly */
599 if (i == cur->h.range.startPosition) {
600 if (i > 0)
601 layout->actual_breakpoints[i].breakConditionBefore = layout->actual_breakpoints[i-1].breakConditionAfter =
602 override_break_condition(layout->actual_breakpoints[i-1].breakConditionAfter, before);
603 else
604 layout->actual_breakpoints[i].breakConditionBefore = before;
605 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
607 /* similar check for last codepoint */
608 else if (i == cur->h.range.startPosition + length - 1) {
609 if (i == layout->len - 1)
610 layout->actual_breakpoints[i].breakConditionAfter = after;
611 else
612 layout->actual_breakpoints[i].breakConditionAfter = layout->actual_breakpoints[i+1].breakConditionBefore =
613 override_break_condition(layout->actual_breakpoints[i+1].breakConditionBefore, after);
614 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
616 /* for all positions within a range disable breaks */
617 else {
618 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
619 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
622 layout->actual_breakpoints[i].isWhitespace = 0;
623 layout->actual_breakpoints[i].isSoftHyphen = 0;
626 return S_OK;
629 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos);
631 static inline DWRITE_LINE_BREAKPOINT get_effective_breakpoint(const struct dwrite_textlayout *layout, UINT32 pos)
633 if (layout->actual_breakpoints)
634 return layout->actual_breakpoints[pos];
635 return layout->nominal_breakpoints[pos];
638 static inline void init_cluster_metrics(const struct dwrite_textlayout *layout, const struct regular_layout_run *run,
639 UINT16 start_glyph, UINT16 stop_glyph, UINT32 stop_position, UINT16 length, DWRITE_CLUSTER_METRICS *metrics)
641 UINT8 breakcondition;
642 UINT32 position;
643 UINT16 j;
645 /* For clusters made of control chars we report zero glyphs, and we need zero cluster
646 width as well; advances are already computed at this point and are not necessary zero. */
647 metrics->width = 0.0f;
648 if (run->run.glyphCount) {
649 for (j = start_glyph; j < stop_glyph; j++)
650 metrics->width += run->run.glyphAdvances[j];
652 metrics->length = length;
654 position = run->descr.textPosition + stop_position;
655 if (stop_glyph == run->glyphcount)
656 breakcondition = get_effective_breakpoint(layout, position).breakConditionAfter;
657 else {
658 breakcondition = get_effective_breakpoint(layout, position).breakConditionBefore;
659 if (stop_position) position -= 1;
662 metrics->canWrapLineAfter = breakcondition == DWRITE_BREAK_CONDITION_CAN_BREAK ||
663 breakcondition == DWRITE_BREAK_CONDITION_MUST_BREAK;
664 if (metrics->length == 1) {
665 DWRITE_LINE_BREAKPOINT bp = get_effective_breakpoint(layout, position);
666 metrics->isWhitespace = bp.isWhitespace;
667 metrics->isNewline = metrics->canWrapLineAfter && lb_is_newline_char(layout->str[position]);
668 metrics->isSoftHyphen = bp.isSoftHyphen;
670 else {
671 metrics->isWhitespace = 0;
672 metrics->isNewline = 0;
673 metrics->isSoftHyphen = 0;
675 metrics->isRightToLeft = run->run.bidiLevel & 1;
676 metrics->padding = 0;
681 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
682 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
683 Note that there's no need to reallocate anything at this point as we allocate one cluster per
684 codepoint initially.
687 static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 *cluster)
689 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[*cluster];
690 struct layout_cluster *c = &layout->clusters[*cluster];
691 const struct regular_layout_run *run = &r->u.regular;
692 UINT32 i, start = 0;
694 for (i = 0; i < run->descr.stringLength; i++) {
695 BOOL end = i == run->descr.stringLength - 1;
697 if (run->descr.clusterMap[start] != run->descr.clusterMap[i]) {
698 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->descr.clusterMap[i], i,
699 i - start, metrics);
700 c->position = start;
701 c->run = r;
703 *cluster += 1;
704 metrics++;
705 c++;
706 start = i;
709 if (end) {
710 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->glyphcount, i,
711 i - start + 1, metrics);
712 c->position = start;
713 c->run = r;
715 *cluster += 1;
716 return;
721 #define SCALE_FONT_METRIC(metric, emSize, metrics) ((FLOAT)(metric) * (emSize) / (FLOAT)(metrics)->designUnitsPerEm)
723 static void layout_get_font_metrics(struct dwrite_textlayout *layout, IDWriteFontFace *fontface, FLOAT emsize,
724 DWRITE_FONT_METRICS *fontmetrics)
726 if (is_layout_gdi_compatible(layout)) {
727 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(fontface, emsize, layout->ppdip, &layout->transform, fontmetrics);
728 if (FAILED(hr))
729 WARN("failed to get compat metrics, 0x%08x\n", hr);
731 else
732 IDWriteFontFace_GetMetrics(fontface, fontmetrics);
735 static void layout_get_font_height(FLOAT emsize, DWRITE_FONT_METRICS *fontmetrics, FLOAT *baseline, FLOAT *height)
737 *baseline = SCALE_FONT_METRIC(fontmetrics->ascent + fontmetrics->lineGap, emsize, fontmetrics);
738 *height = SCALE_FONT_METRIC(fontmetrics->ascent + fontmetrics->descent + fontmetrics->lineGap, emsize, fontmetrics);
741 static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
743 IDWriteFontFallback *fallback;
744 IDWriteTextAnalyzer *analyzer;
745 struct layout_range *range;
746 struct layout_run *r;
747 UINT32 cluster = 0;
748 HRESULT hr;
750 free_layout_eruns(layout);
751 free_layout_runs(layout);
753 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
754 if (!layout->clustermetrics && layout->len) {
755 layout->clustermetrics = heap_alloc(layout->len*sizeof(*layout->clustermetrics));
756 layout->clusters = heap_alloc(layout->len*sizeof(*layout->clusters));
757 if (!layout->clustermetrics || !layout->clusters) {
758 heap_free(layout->clustermetrics);
759 heap_free(layout->clusters);
760 return E_OUTOFMEMORY;
763 layout->cluster_count = 0;
765 hr = get_textanalyzer(&analyzer);
766 if (FAILED(hr))
767 return hr;
769 LIST_FOR_EACH_ENTRY(range, &layout->ranges, struct layout_range, h.entry) {
770 /* we don't care about ranges that don't contain any text */
771 if (range->h.range.startPosition >= layout->len)
772 break;
774 /* inline objects override actual text in a range */
775 if (range->object) {
776 hr = layout_update_breakpoints_range(layout, range);
777 if (FAILED(hr))
778 return hr;
780 r = alloc_layout_run(LAYOUT_RUN_INLINE);
781 if (!r)
782 return E_OUTOFMEMORY;
784 r->u.object.object = range->object;
785 r->u.object.length = get_clipped_range_length(layout, range);
786 list_add_tail(&layout->runs, &r->entry);
787 continue;
790 /* initial splitting by script */
791 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, (IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
792 range->h.range.startPosition, get_clipped_range_length(layout, range), (IDWriteTextAnalysisSink*)&layout->IDWriteTextAnalysisSink1_iface);
793 if (FAILED(hr))
794 break;
796 /* this splits it further */
797 hr = IDWriteTextAnalyzer_AnalyzeBidi(analyzer, (IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
798 range->h.range.startPosition, get_clipped_range_length(layout, range), (IDWriteTextAnalysisSink*)&layout->IDWriteTextAnalysisSink1_iface);
799 if (FAILED(hr))
800 break;
803 if (layout->format.fallback) {
804 fallback = layout->format.fallback;
805 IDWriteFontFallback_AddRef(fallback);
807 else {
808 hr = IDWriteFactory5_GetSystemFontFallback(layout->factory, &fallback);
809 if (FAILED(hr))
810 return hr;
813 /* resolve run fonts */
814 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
815 struct regular_layout_run *run = &r->u.regular;
816 IDWriteFont *font;
817 UINT32 length;
819 if (r->kind == LAYOUT_RUN_INLINE)
820 continue;
822 range = get_layout_range_by_pos(layout, run->descr.textPosition);
824 if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL) {
825 IDWriteFontCollection *collection;
827 if (range->collection) {
828 collection = range->collection;
829 IDWriteFontCollection_AddRef(collection);
831 else
832 IDWriteFactory5_GetSystemFontCollection(layout->factory, FALSE, (IDWriteFontCollection1 **)&collection, FALSE);
834 hr = create_matching_font(collection, range->fontfamily, range->weight,
835 range->style, range->stretch, &font);
837 IDWriteFontCollection_Release(collection);
839 if (FAILED(hr)) {
840 WARN("%s: failed to create a font for non visual run, %s, collection %p\n", debugstr_rundescr(&run->descr),
841 debugstr_w(range->fontfamily), range->collection);
842 return hr;
845 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
846 IDWriteFont_Release(font);
847 if (FAILED(hr))
848 return hr;
850 run->run.fontEmSize = range->fontsize;
851 continue;
854 length = run->descr.stringLength;
856 while (length) {
857 UINT32 mapped_length;
858 FLOAT scale;
860 run = &r->u.regular;
862 hr = IDWriteFontFallback_MapCharacters(fallback,
863 (IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
864 run->descr.textPosition,
865 run->descr.stringLength,
866 range->collection,
867 range->fontfamily,
868 range->weight,
869 range->style,
870 range->stretch,
871 &mapped_length,
872 &font,
873 &scale);
874 if (FAILED(hr)) {
875 WARN("%s: failed to map family %s, collection %p\n", debugstr_rundescr(&run->descr), debugstr_w(range->fontfamily), range->collection);
876 return hr;
879 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
880 IDWriteFont_Release(font);
881 if (FAILED(hr))
882 return hr;
883 run->run.fontEmSize = range->fontsize * scale;
885 if (mapped_length < length) {
886 struct regular_layout_run *nextrun;
887 struct layout_run *nextr;
889 /* keep mapped part for current run, add another run for the rest */
890 nextr = alloc_layout_run(LAYOUT_RUN_REGULAR);
891 if (!nextr)
892 return E_OUTOFMEMORY;
894 *nextr = *r;
895 nextrun = &nextr->u.regular;
896 nextrun->descr.textPosition = run->descr.textPosition + mapped_length;
897 nextrun->descr.stringLength = run->descr.stringLength - mapped_length;
898 nextrun->descr.string = &layout->str[nextrun->descr.textPosition];
899 run->descr.stringLength = mapped_length;
900 list_add_after(&r->entry, &nextr->entry);
901 r = nextr;
904 length -= mapped_length;
908 IDWriteFontFallback_Release(fallback);
910 /* fill run info */
911 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
912 DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props = NULL;
913 DWRITE_SHAPING_TEXT_PROPERTIES *text_props = NULL;
914 struct regular_layout_run *run = &r->u.regular;
915 DWRITE_FONT_METRICS fontmetrics = { 0 };
916 UINT32 max_count;
918 /* we need to do very little in case of inline objects */
919 if (r->kind == LAYOUT_RUN_INLINE) {
920 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[cluster];
921 struct layout_cluster *c = &layout->clusters[cluster];
922 DWRITE_INLINE_OBJECT_METRICS inlinemetrics;
924 metrics->width = 0.0f;
925 metrics->length = r->u.object.length;
926 metrics->canWrapLineAfter = 0;
927 metrics->isWhitespace = 0;
928 metrics->isNewline = 0;
929 metrics->isSoftHyphen = 0;
930 metrics->isRightToLeft = 0;
931 metrics->padding = 0;
932 c->run = r;
933 c->position = 0; /* there's always one cluster per inline object, so 0 is valid value */
934 cluster++;
936 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
937 hr = IDWriteInlineObject_GetMetrics(r->u.object.object, &inlinemetrics);
938 if (FAILED(hr)) {
939 memset(&inlinemetrics, 0, sizeof(inlinemetrics));
940 hr = S_OK;
942 metrics->width = inlinemetrics.width;
943 r->baseline = inlinemetrics.baseline;
944 r->height = inlinemetrics.height;
946 /* FIXME: use resolved breakpoints in this case too */
948 continue;
951 range = get_layout_range_by_pos(layout, run->descr.textPosition);
952 run->descr.localeName = range->locale;
953 run->clustermap = heap_alloc(run->descr.stringLength*sizeof(UINT16));
955 max_count = 3*run->descr.stringLength/2 + 16;
956 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
957 if (!run->clustermap || !run->glyphs)
958 goto memerr;
960 text_props = heap_alloc(run->descr.stringLength*sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
961 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
962 if (!text_props || !glyph_props)
963 goto memerr;
965 while (1) {
966 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, run->descr.string, run->descr.stringLength,
967 run->run.fontFace, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
968 NULL /* FIXME */, NULL, NULL, 0, max_count, run->clustermap, text_props, run->glyphs, glyph_props,
969 &run->glyphcount);
970 if (hr == E_NOT_SUFFICIENT_BUFFER) {
971 heap_free(run->glyphs);
972 heap_free(glyph_props);
974 max_count = run->glyphcount;
976 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
977 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
978 if (!run->glyphs || !glyph_props)
979 goto memerr;
981 continue;
984 break;
987 if (FAILED(hr)) {
988 heap_free(text_props);
989 heap_free(glyph_props);
990 WARN("%s: shaping failed 0x%08x\n", debugstr_rundescr(&run->descr), hr);
991 continue;
994 run->run.glyphIndices = run->glyphs;
995 run->descr.clusterMap = run->clustermap;
997 run->advances = heap_alloc(run->glyphcount*sizeof(FLOAT));
998 run->offsets = heap_alloc(run->glyphcount*sizeof(DWRITE_GLYPH_OFFSET));
999 if (!run->advances || !run->offsets)
1000 goto memerr;
1002 /* now set advances and offsets */
1003 if (is_layout_gdi_compatible(layout))
1004 hr = IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap,
1005 text_props, run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount,
1006 run->run.fontFace, run->run.fontEmSize, layout->ppdip, &layout->transform,
1007 layout->measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->run.isSideways,
1008 run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL, NULL, 0, run->advances, run->offsets);
1009 else
1010 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap, text_props,
1011 run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount, run->run.fontFace,
1012 run->run.fontEmSize, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
1013 NULL, NULL, 0, run->advances, run->offsets);
1015 heap_free(text_props);
1016 heap_free(glyph_props);
1017 if (FAILED(hr))
1018 WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_rundescr(&run->descr), hr);
1020 run->run.glyphAdvances = run->advances;
1021 run->run.glyphOffsets = run->offsets;
1023 /* Special treatment for runs that don't produce visual output, shaping code adds normal glyphs for them,
1024 with valid cluster map and potentially with non-zero advances; layout code exposes those as zero width clusters. */
1025 if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL)
1026 run->run.glyphCount = 0;
1027 else
1028 run->run.glyphCount = run->glyphcount;
1030 /* baseline derived from font metrics */
1031 layout_get_font_metrics(layout, run->run.fontFace, run->run.fontEmSize, &fontmetrics);
1032 layout_get_font_height(run->run.fontEmSize, &fontmetrics, &r->baseline, &r->height);
1034 layout_set_cluster_metrics(layout, r, &cluster);
1035 continue;
1037 memerr:
1038 heap_free(text_props);
1039 heap_free(glyph_props);
1040 heap_free(run->clustermap);
1041 heap_free(run->glyphs);
1042 heap_free(run->advances);
1043 heap_free(run->offsets);
1044 run->advances = NULL;
1045 run->offsets = NULL;
1046 run->clustermap = run->glyphs = NULL;
1047 hr = E_OUTOFMEMORY;
1048 break;
1051 if (hr == S_OK) {
1052 layout->cluster_count = cluster;
1053 if (cluster)
1054 layout->clustermetrics[cluster-1].canWrapLineAfter = 1;
1057 IDWriteTextAnalyzer_Release(analyzer);
1058 return hr;
1061 static HRESULT layout_compute(struct dwrite_textlayout *layout)
1063 HRESULT hr;
1065 if (!(layout->recompute & RECOMPUTE_CLUSTERS))
1066 return S_OK;
1068 /* nominal breakpoints are evaluated only once, because string never changes */
1069 if (!layout->nominal_breakpoints) {
1070 IDWriteTextAnalyzer *analyzer;
1071 HRESULT hr;
1073 layout->nominal_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
1074 if (!layout->nominal_breakpoints)
1075 return E_OUTOFMEMORY;
1077 hr = get_textanalyzer(&analyzer);
1078 if (FAILED(hr))
1079 return hr;
1081 hr = IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer, (IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
1082 0, layout->len, (IDWriteTextAnalysisSink*)&layout->IDWriteTextAnalysisSink1_iface);
1083 IDWriteTextAnalyzer_Release(analyzer);
1085 if (layout->actual_breakpoints) {
1086 heap_free(layout->actual_breakpoints);
1087 layout->actual_breakpoints = NULL;
1090 hr = layout_compute_runs(layout);
1092 if (TRACE_ON(dwrite)) {
1093 struct layout_run *cur;
1095 LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
1096 if (cur->kind == LAYOUT_RUN_INLINE)
1097 TRACE("run inline object %p, len %u\n", cur->u.object.object, cur->u.object.length);
1098 else
1099 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur->u.regular.descr.textPosition, cur->u.regular.descr.textPosition +
1100 cur->u.regular.descr.stringLength-1, cur->u.regular.descr.stringLength, cur->u.regular.run.bidiLevel);
1104 layout->recompute &= ~RECOMPUTE_CLUSTERS;
1105 return hr;
1108 static inline FLOAT get_cluster_range_width(struct dwrite_textlayout *layout, UINT32 start, UINT32 end)
1110 FLOAT width = 0.0f;
1111 for (; start < end; start++)
1112 width += layout->clustermetrics[start].width;
1113 return width;
1116 static struct layout_range_header *get_layout_range_header_by_pos(struct list *ranges, UINT32 pos)
1118 struct layout_range_header *cur;
1120 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
1121 DWRITE_TEXT_RANGE *r = &cur->range;
1122 if (r->startPosition <= pos && pos < r->startPosition + r->length)
1123 return cur;
1126 return NULL;
1129 static inline IUnknown *layout_get_effect_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1131 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->effects, pos);
1132 return ((struct layout_range_iface*)h)->iface;
1135 static inline BOOL layout_is_erun_rtl(const struct layout_effective_run *erun)
1137 return erun->run->u.regular.run.bidiLevel & 1;
1140 /* A set of parameters that additionally splits resulting runs. It happens after shaping and all text processing,
1141 no glyph changes are possible. It's understandable for drawing effects, because DrawGlyphRun() reports them as
1142 one of the arguments, but it also happens for decorations, so every effective run has uniform
1143 underline/strikethough/effect tuple. */
1144 struct layout_final_splitting_params {
1145 BOOL strikethrough;
1146 BOOL underline;
1147 IUnknown *effect;
1150 static inline BOOL layout_get_strikethrough_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1152 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->strike_ranges, pos);
1153 return ((struct layout_range_bool*)h)->value;
1156 static inline BOOL layout_get_underline_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1158 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->underline_ranges, pos);
1159 return ((struct layout_range_bool*)h)->value;
1162 static void layout_splitting_params_from_pos(struct dwrite_textlayout *layout, UINT32 pos,
1163 struct layout_final_splitting_params *params)
1165 params->strikethrough = layout_get_strikethrough_from_pos(layout, pos);
1166 params->underline = layout_get_underline_from_pos(layout, pos);
1167 params->effect = layout_get_effect_from_pos(layout, pos);
1170 static BOOL is_same_splitting_params(const struct layout_final_splitting_params *left,
1171 const struct layout_final_splitting_params *right)
1173 return left->strikethrough == right->strikethrough &&
1174 left->underline == right->underline &&
1175 left->effect == right->effect;
1178 static void layout_get_erun_font_metrics(struct dwrite_textlayout *layout, struct layout_effective_run *erun,
1179 DWRITE_FONT_METRICS *metrics)
1181 memset(metrics, 0, sizeof(*metrics));
1182 if (is_layout_gdi_compatible(layout)) {
1183 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(
1184 erun->run->u.regular.run.fontFace,
1185 erun->run->u.regular.run.fontEmSize,
1186 layout->ppdip,
1187 &layout->transform,
1188 metrics);
1189 if (FAILED(hr))
1190 WARN("failed to get font metrics, 0x%08x\n", hr);
1192 else
1193 IDWriteFontFace_GetMetrics(erun->run->u.regular.run.fontFace, metrics);
1196 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
1197 'cluster_count' indicates how many clusters to add, including first one. */
1198 static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 first_cluster,
1199 UINT32 cluster_count, UINT32 line, FLOAT origin_x, struct layout_final_splitting_params *params)
1201 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1202 UINT32 i, start, length, last_cluster;
1203 struct layout_effective_run *run;
1205 if (r->kind == LAYOUT_RUN_INLINE) {
1206 struct layout_effective_inline *inlineobject;
1208 inlineobject = heap_alloc(sizeof(*inlineobject));
1209 if (!inlineobject)
1210 return E_OUTOFMEMORY;
1212 inlineobject->object = r->u.object.object;
1213 inlineobject->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1214 inlineobject->origin.x = is_rtl ? origin_x - inlineobject->width : origin_x;
1215 inlineobject->origin.y = 0.0f; /* set after line is built */
1216 inlineobject->align_dx = 0.0f;
1217 inlineobject->baseline = r->baseline;
1219 /* It's not clear how these two are set, possibly directionality
1220 is derived from surrounding text (replaced text could have
1221 different ranges which differ in reading direction). */
1222 inlineobject->is_sideways = FALSE;
1223 inlineobject->is_rtl = FALSE;
1224 inlineobject->line = line;
1226 /* effect assigned from start position and on is used for inline objects */
1227 inlineobject->effect = layout_get_effect_from_pos(layout, layout->clusters[first_cluster].position);
1229 list_add_tail(&layout->inlineobjects, &inlineobject->entry);
1230 return S_OK;
1233 run = heap_alloc(sizeof(*run));
1234 if (!run)
1235 return E_OUTOFMEMORY;
1237 /* No need to iterate for that, use simple fact that:
1238 <last cluster position> = <first cluster position> + <sum of cluster lengths not including last one> */
1239 last_cluster = first_cluster + cluster_count - 1;
1240 length = layout->clusters[last_cluster].position - layout->clusters[first_cluster].position +
1241 layout->clustermetrics[last_cluster].length;
1243 run->clustermap = heap_alloc(sizeof(UINT16)*length);
1244 if (!run->clustermap) {
1245 heap_free(run);
1246 return E_OUTOFMEMORY;
1249 run->run = r;
1250 run->start = start = layout->clusters[first_cluster].position;
1251 run->length = length;
1252 run->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1253 memset(&run->bbox, 0, sizeof(run->bbox));
1255 /* Check if run direction matches paragraph direction, if it doesn't adjust by
1256 run width */
1257 if (layout_is_erun_rtl(run) ^ is_rtl)
1258 run->origin.x = is_rtl ? origin_x - run->width : origin_x + run->width;
1259 else
1260 run->origin.x = origin_x;
1262 run->origin.y = 0.0f; /* set after line is built */
1263 run->align_dx = 0.0f;
1264 run->line = line;
1266 if (r->u.regular.run.glyphCount) {
1267 /* Trim leading and trailing clusters. */
1268 run->glyphcount = r->u.regular.run.glyphCount - r->u.regular.clustermap[start];
1269 if (start + length < r->u.regular.descr.stringLength)
1270 run->glyphcount -= r->u.regular.run.glyphCount - r->u.regular.clustermap[start + length];
1272 else
1273 run->glyphcount = 0;
1275 /* cluster map needs to be shifted */
1276 for (i = 0; i < length; i++)
1277 run->clustermap[i] = r->u.regular.clustermap[start + i] - r->u.regular.clustermap[start];
1279 run->effect = params->effect;
1280 run->underlined = params->underline;
1281 list_add_tail(&layout->eruns, &run->entry);
1283 /* Strikethrough style is guaranteed to be consistent within effective run,
1284 its width equals to run width, thickness and offset are derived from
1285 font metrics, rest of the values are from layout or run itself */
1286 if (params->strikethrough) {
1287 struct layout_strikethrough *s;
1288 DWRITE_FONT_METRICS metrics;
1290 s = heap_alloc(sizeof(*s));
1291 if (!s)
1292 return E_OUTOFMEMORY;
1294 layout_get_erun_font_metrics(layout, run, &metrics);
1295 s->s.width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1296 s->s.thickness = SCALE_FONT_METRIC(metrics.strikethroughThickness, r->u.regular.run.fontEmSize, &metrics);
1297 /* Negative offset moves it above baseline as Y coordinate grows downward. */
1298 s->s.offset = -SCALE_FONT_METRIC(metrics.strikethroughPosition, r->u.regular.run.fontEmSize, &metrics);
1299 s->s.readingDirection = layout->format.readingdir;
1300 s->s.flowDirection = layout->format.flow;
1301 s->s.localeName = r->u.regular.descr.localeName;
1302 s->s.measuringMode = layout->measuringmode;
1303 s->run = run;
1305 list_add_tail(&layout->strikethrough, &s->entry);
1308 return S_OK;
1311 static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_LINE_METRICS1 *metrics)
1313 UINT32 i = layout->metrics.lineCount;
1315 if (!layout->line_alloc) {
1316 layout->line_alloc = 5;
1317 layout->linemetrics = heap_alloc(layout->line_alloc * sizeof(*layout->linemetrics));
1318 layout->lines = heap_alloc(layout->line_alloc * sizeof(*layout->lines));
1319 if (!layout->linemetrics || !layout->lines) {
1320 heap_free(layout->linemetrics);
1321 heap_free(layout->lines);
1322 layout->linemetrics = NULL;
1323 layout->lines = NULL;
1324 return E_OUTOFMEMORY;
1328 if (layout->metrics.lineCount == layout->line_alloc) {
1329 DWRITE_LINE_METRICS1 *metrics;
1330 struct layout_line *lines;
1332 if ((metrics = heap_realloc(layout->linemetrics, layout->line_alloc * 2 * sizeof(*layout->linemetrics))))
1333 layout->linemetrics = metrics;
1334 if ((lines = heap_realloc(layout->lines, layout->line_alloc * 2 * sizeof(*layout->lines))))
1335 layout->lines = lines;
1337 if (!metrics || !lines)
1338 return E_OUTOFMEMORY;
1340 layout->line_alloc *= 2;
1343 layout->linemetrics[i] = *metrics;
1345 switch (layout->format.spacing.method)
1347 case DWRITE_LINE_SPACING_METHOD_UNIFORM:
1348 if (layout->format.spacing.method == DWRITE_LINE_SPACING_METHOD_UNIFORM) {
1349 layout->linemetrics[i].height = layout->format.spacing.height;
1350 layout->linemetrics[i].baseline = layout->format.spacing.baseline;
1352 break;
1353 case DWRITE_LINE_SPACING_METHOD_PROPORTIONAL:
1354 if (layout->format.spacing.method == DWRITE_LINE_SPACING_METHOD_UNIFORM) {
1355 layout->linemetrics[i].height = layout->format.spacing.height * metrics->height;
1356 layout->linemetrics[i].baseline = layout->format.spacing.baseline * metrics->baseline;
1358 break;
1359 default:
1360 /* using content values */;
1363 layout->lines[i].height = metrics->height;
1364 layout->lines[i].baseline = metrics->baseline;
1366 layout->metrics.lineCount++;
1367 return S_OK;
1370 static inline struct layout_effective_run *layout_get_next_erun(struct dwrite_textlayout *layout,
1371 const struct layout_effective_run *cur)
1373 struct list *e;
1375 if (!cur)
1376 e = list_head(&layout->eruns);
1377 else
1378 e = list_next(&layout->eruns, &cur->entry);
1379 if (!e)
1380 return NULL;
1381 return LIST_ENTRY(e, struct layout_effective_run, entry);
1384 static inline struct layout_effective_run *layout_get_prev_erun(struct dwrite_textlayout *layout,
1385 const struct layout_effective_run *cur)
1387 struct list *e;
1389 if (!cur)
1390 e = list_tail(&layout->eruns);
1391 else
1392 e = list_prev(&layout->eruns, &cur->entry);
1393 if (!e)
1394 return NULL;
1395 return LIST_ENTRY(e, struct layout_effective_run, entry);
1398 static inline struct layout_effective_inline *layout_get_next_inline_run(struct dwrite_textlayout *layout,
1399 const struct layout_effective_inline *cur)
1401 struct list *e;
1403 if (!cur)
1404 e = list_head(&layout->inlineobjects);
1405 else
1406 e = list_next(&layout->inlineobjects, &cur->entry);
1407 if (!e)
1408 return NULL;
1409 return LIST_ENTRY(e, struct layout_effective_inline, entry);
1412 static FLOAT layout_get_line_width(struct dwrite_textlayout *layout,
1413 struct layout_effective_run *erun, struct layout_effective_inline *inrun, UINT32 line)
1415 FLOAT width = 0.0f;
1417 while (erun && erun->line == line) {
1418 width += erun->width;
1419 erun = layout_get_next_erun(layout, erun);
1420 if (!erun)
1421 break;
1424 while (inrun && inrun->line == line) {
1425 width += inrun->width;
1426 inrun = layout_get_next_inline_run(layout, inrun);
1427 if (!inrun)
1428 break;
1431 return width;
1434 static inline BOOL should_skip_transform(const DWRITE_MATRIX *m, FLOAT *det)
1436 *det = m->m11 * m->m22 - m->m12 * m->m21;
1437 /* on certain conditions we can skip transform */
1438 return (!memcmp(m, &identity, sizeof(*m)) || fabsf(*det) <= 1e-10f);
1441 static inline void layout_apply_snapping(D2D1_POINT_2F *vec, BOOL skiptransform, FLOAT ppdip,
1442 const DWRITE_MATRIX *m, FLOAT det)
1444 if (!skiptransform) {
1445 D2D1_POINT_2F vec2;
1447 /* apply transform */
1448 vec->x *= ppdip;
1449 vec->y *= ppdip;
1451 vec2.x = m->m11 * vec->x + m->m21 * vec->y + m->dx;
1452 vec2.y = m->m12 * vec->x + m->m22 * vec->y + m->dy;
1454 /* snap */
1455 vec2.x = floorf(vec2.x + 0.5f);
1456 vec2.y = floorf(vec2.y + 0.5f);
1458 /* apply inverted transform, we don't care about X component at this point */
1459 vec->x = (m->m22 * vec2.x - m->m21 * vec2.y + m->m21 * m->dy - m->m22 * m->dx) / det;
1460 vec->x /= ppdip;
1462 vec->y = (-m->m12 * vec2.x + m->m11 * vec2.y - (m->m11 * m->dy - m->m12 * m->dx)) / det;
1463 vec->y /= ppdip;
1465 else {
1466 vec->x = floorf(vec->x * ppdip + 0.5f) / ppdip;
1467 vec->y = floorf(vec->y * ppdip + 0.5f) / ppdip;
1471 static void layout_apply_leading_alignment(struct dwrite_textlayout *layout)
1473 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1474 struct layout_effective_inline *inrun;
1475 struct layout_effective_run *erun;
1477 erun = layout_get_next_erun(layout, NULL);
1478 inrun = layout_get_next_inline_run(layout, NULL);
1480 while (erun) {
1481 erun->align_dx = 0.0f;
1482 erun = layout_get_next_erun(layout, erun);
1485 while (inrun) {
1486 inrun->align_dx = 0.0f;
1487 inrun = layout_get_next_inline_run(layout, inrun);
1490 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
1493 static void layout_apply_trailing_alignment(struct dwrite_textlayout *layout)
1495 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1496 struct layout_effective_inline *inrun;
1497 struct layout_effective_run *erun;
1498 UINT32 line;
1500 erun = layout_get_next_erun(layout, NULL);
1501 inrun = layout_get_next_inline_run(layout, NULL);
1503 for (line = 0; line < layout->metrics.lineCount; line++) {
1504 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1505 FLOAT shift = layout->metrics.layoutWidth - width;
1507 if (is_rtl)
1508 shift *= -1.0f;
1510 while (erun && erun->line == line) {
1511 erun->align_dx = shift;
1512 erun = layout_get_next_erun(layout, erun);
1515 while (inrun && inrun->line == line) {
1516 inrun->align_dx = shift;
1517 inrun = layout_get_next_inline_run(layout, inrun);
1521 layout->metrics.left = is_rtl ? 0.0f : layout->metrics.layoutWidth - layout->metrics.width;
1524 static inline FLOAT layout_get_centered_shift(struct dwrite_textlayout *layout, BOOL skiptransform,
1525 FLOAT width, FLOAT det)
1527 if (is_layout_gdi_compatible(layout)) {
1528 D2D1_POINT_2F vec = { layout->metrics.layoutWidth - width, 0.0f};
1529 layout_apply_snapping(&vec, skiptransform, layout->ppdip, &layout->transform, det);
1530 return floorf(vec.x / 2.0f);
1532 else
1533 return (layout->metrics.layoutWidth - width) / 2.0f;
1536 static void layout_apply_centered_alignment(struct dwrite_textlayout *layout)
1538 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1539 struct layout_effective_inline *inrun;
1540 struct layout_effective_run *erun;
1541 BOOL skiptransform;
1542 UINT32 line;
1543 FLOAT det;
1545 erun = layout_get_next_erun(layout, NULL);
1546 inrun = layout_get_next_inline_run(layout, NULL);
1548 skiptransform = should_skip_transform(&layout->transform, &det);
1550 for (line = 0; line < layout->metrics.lineCount; line++) {
1551 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1552 FLOAT shift = layout_get_centered_shift(layout, skiptransform, width, det);
1554 if (is_rtl)
1555 shift *= -1.0f;
1557 while (erun && erun->line == line) {
1558 erun->align_dx = shift;
1559 erun = layout_get_next_erun(layout, erun);
1562 while (inrun && inrun->line == line) {
1563 inrun->align_dx = shift;
1564 inrun = layout_get_next_inline_run(layout, inrun);
1568 layout->metrics.left = (layout->metrics.layoutWidth - layout->metrics.width) / 2.0f;
1571 static void layout_apply_text_alignment(struct dwrite_textlayout *layout)
1573 switch (layout->format.textalignment)
1575 case DWRITE_TEXT_ALIGNMENT_LEADING:
1576 layout_apply_leading_alignment(layout);
1577 break;
1578 case DWRITE_TEXT_ALIGNMENT_TRAILING:
1579 layout_apply_trailing_alignment(layout);
1580 break;
1581 case DWRITE_TEXT_ALIGNMENT_CENTER:
1582 layout_apply_centered_alignment(layout);
1583 break;
1584 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED:
1585 FIXME("alignment %d not implemented\n", layout->format.textalignment);
1586 break;
1587 default:
1592 static void layout_apply_par_alignment(struct dwrite_textlayout *layout)
1594 struct layout_effective_inline *inrun;
1595 struct layout_effective_run *erun;
1596 FLOAT origin_y = 0.0f;
1597 UINT32 line;
1599 /* alignment mode defines origin, after that all run origins are updated
1600 the same way */
1602 switch (layout->format.paralign)
1604 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR:
1605 origin_y = 0.0f;
1606 break;
1607 case DWRITE_PARAGRAPH_ALIGNMENT_FAR:
1608 origin_y = layout->metrics.layoutHeight - layout->metrics.height;
1609 break;
1610 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER:
1611 origin_y = (layout->metrics.layoutHeight - layout->metrics.height) / 2.0f;
1612 break;
1613 default:
1617 layout->metrics.top = origin_y;
1619 erun = layout_get_next_erun(layout, NULL);
1620 inrun = layout_get_next_inline_run(layout, NULL);
1621 for (line = 0; line < layout->metrics.lineCount; line++) {
1622 FLOAT pos_y = origin_y + layout->linemetrics[line].baseline;
1624 while (erun && erun->line == line) {
1625 erun->origin.y = pos_y;
1626 erun = layout_get_next_erun(layout, erun);
1629 while (inrun && inrun->line == line) {
1630 inrun->origin.y = pos_y - inrun->baseline;
1631 inrun = layout_get_next_inline_run(layout, inrun);
1634 origin_y += layout->linemetrics[line].height;
1638 struct layout_underline_splitting_params {
1639 const WCHAR *locale; /* points to range data, no additional allocation */
1640 IUnknown *effect; /* does not hold another reference */
1643 static void init_u_splitting_params_from_erun(struct layout_effective_run *erun,
1644 struct layout_underline_splitting_params *params)
1646 params->locale = erun->run->u.regular.descr.localeName;
1647 params->effect = erun->effect;
1650 static BOOL is_same_u_splitting(struct layout_underline_splitting_params *left,
1651 struct layout_underline_splitting_params *right)
1653 return left->effect == right->effect && !strcmpiW(left->locale, right->locale);
1656 static HRESULT layout_add_underline(struct dwrite_textlayout *layout, struct layout_effective_run *first,
1657 struct layout_effective_run *last)
1659 FLOAT thickness, offset, runheight;
1660 struct layout_effective_run *cur;
1661 DWRITE_FONT_METRICS metrics;
1663 if (first == layout_get_prev_erun(layout, last)) {
1664 layout_get_erun_font_metrics(layout, first, &metrics);
1665 thickness = SCALE_FONT_METRIC(metrics.underlineThickness, first->run->u.regular.run.fontEmSize, &metrics);
1666 offset = SCALE_FONT_METRIC(metrics.underlinePosition, first->run->u.regular.run.fontEmSize, &metrics);
1667 runheight = SCALE_FONT_METRIC(metrics.capHeight, first->run->u.regular.run.fontEmSize, &metrics);
1669 else {
1670 FLOAT width = 0.0f;
1672 /* Single underline is added for consecutive underlined runs. In this case underline parameters are
1673 calculated as weighted average, where run width acts as a weight. */
1674 thickness = offset = runheight = 0.0f;
1675 cur = first;
1676 do {
1677 layout_get_erun_font_metrics(layout, cur, &metrics);
1679 thickness += SCALE_FONT_METRIC(metrics.underlineThickness, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
1680 offset += SCALE_FONT_METRIC(metrics.underlinePosition, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
1681 runheight = max(SCALE_FONT_METRIC(metrics.capHeight, cur->run->u.regular.run.fontEmSize, &metrics), runheight);
1682 width += cur->width;
1684 cur = layout_get_next_erun(layout, cur);
1685 } while (cur != last);
1687 thickness /= width;
1688 offset /= width;
1691 cur = first;
1692 do {
1693 struct layout_underline_splitting_params params, prev_params;
1694 struct layout_effective_run *next, *w;
1695 struct layout_underline *u;
1697 init_u_splitting_params_from_erun(cur, &prev_params);
1698 while ((next = layout_get_next_erun(layout, cur)) != last) {
1699 init_u_splitting_params_from_erun(next, &params);
1700 if (!is_same_u_splitting(&prev_params, &params))
1701 break;
1702 cur = next;
1705 u = heap_alloc(sizeof(*u));
1706 if (!u)
1707 return E_OUTOFMEMORY;
1709 w = cur;
1710 u->u.width = 0.0f;
1711 while (w != next) {
1712 u->u.width += w->width;
1713 w = layout_get_next_erun(layout, w);
1716 u->u.thickness = thickness;
1717 /* Font metrics convention is to have it negative when below baseline, for rendering
1718 however Y grows from baseline down for horizontal baseline. */
1719 u->u.offset = -offset;
1720 u->u.runHeight = runheight;
1721 u->u.readingDirection = is_run_rtl(cur) ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
1722 DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
1723 u->u.flowDirection = layout->format.flow;
1724 u->u.localeName = cur->run->u.regular.descr.localeName;
1725 u->u.measuringMode = layout->measuringmode;
1726 u->run = cur;
1727 list_add_tail(&layout->underlines, &u->entry);
1729 cur = next;
1730 } while (cur != last);
1732 return S_OK;
1735 /* Adds zero width line, metrics are derived from font at specified text position. */
1736 static HRESULT layout_set_dummy_line_metrics(struct dwrite_textlayout *layout, UINT32 pos)
1738 DWRITE_LINE_METRICS1 metrics = { 0 };
1739 DWRITE_FONT_METRICS fontmetrics;
1740 struct layout_range *range;
1741 IDWriteFontFace *fontface;
1742 IDWriteFont *font;
1743 HRESULT hr;
1745 range = get_layout_range_by_pos(layout, pos);
1746 hr = create_matching_font(range->collection,
1747 range->fontfamily,
1748 range->weight,
1749 range->style,
1750 range->stretch,
1751 &font);
1752 if (FAILED(hr))
1753 return hr;
1754 hr = IDWriteFont_CreateFontFace(font, &fontface);
1755 IDWriteFont_Release(font);
1756 if (FAILED(hr))
1757 return hr;
1759 layout_get_font_metrics(layout, fontface, range->fontsize, &fontmetrics);
1760 layout_get_font_height(range->fontsize, &fontmetrics, &metrics.baseline, &metrics.height);
1761 IDWriteFontFace_Release(fontface);
1763 return layout_set_line_metrics(layout, &metrics);
1766 static void layout_add_line(struct dwrite_textlayout *layout, UINT32 first_cluster, UINT32 last_cluster,
1767 UINT32 *textpos)
1769 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1770 struct layout_final_splitting_params params, prev_params;
1771 DWRITE_INLINE_OBJECT_METRICS sign_metrics = { 0 };
1772 UINT32 line = layout->metrics.lineCount, i;
1773 DWRITE_LINE_METRICS1 metrics = { 0 };
1774 UINT32 index, start, pos = *textpos;
1775 FLOAT descent, trailingspacewidth;
1776 BOOL append_trimming_run = FALSE;
1777 const struct layout_run *run;
1778 FLOAT width, origin_x;
1779 HRESULT hr;
1781 /* Take a look at clusters we got for this line in reverse order to set trailing properties for current line */
1782 for (index = last_cluster, trailingspacewidth = 0.0f; index >= first_cluster; index--) {
1783 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1784 struct layout_cluster *lc = &layout->clusters[index];
1785 WCHAR ch;
1787 /* This also filters out clusters added from inline objects, those are never
1788 treated as a white space. */
1789 if (!cluster->isWhitespace)
1790 break;
1792 /* Every isNewline cluster is also isWhitespace, but not every
1793 newline character cluster has isNewline set, so go back to original string. */
1794 ch = lc->run->u.regular.descr.string[lc->position];
1795 if (cluster->length == 1 && lb_is_newline_char(ch))
1796 metrics.newlineLength += cluster->length;
1798 metrics.trailingWhitespaceLength += cluster->length;
1799 trailingspacewidth += cluster->width;
1802 /* Line metrics length includes trailing whitespace length too */
1803 for (i = first_cluster; i <= last_cluster; i++)
1804 metrics.length += layout->clustermetrics[i].length;
1806 /* Ignore trailing whitespaces */
1807 while (last_cluster > first_cluster) {
1808 if (!layout->clustermetrics[last_cluster].isWhitespace)
1809 break;
1811 last_cluster--;
1814 /* Does not include trailing space width */
1815 width = get_cluster_range_width(layout, first_cluster, last_cluster + 1);
1817 /* Append trimming run if necessary */
1818 if (width > layout->metrics.layoutWidth && layout->format.trimmingsign != NULL &&
1819 layout->format.trimming.granularity != DWRITE_TRIMMING_GRANULARITY_NONE) {
1820 FLOAT trimmed_width = width;
1822 hr = IDWriteInlineObject_GetMetrics(layout->format.trimmingsign, &sign_metrics);
1823 if (SUCCEEDED(hr)) {
1824 while (last_cluster > first_cluster) {
1825 if (trimmed_width + sign_metrics.width <= layout->metrics.layoutWidth)
1826 break;
1827 trimmed_width -= layout->clustermetrics[last_cluster--].width;
1829 append_trimming_run = TRUE;
1831 else
1832 WARN("Failed to get trimming sign metrics, lines won't be trimmed, hr %#x.\n", hr);
1834 width = trimmed_width + sign_metrics.width;
1837 layout_splitting_params_from_pos(layout, pos, &params);
1838 prev_params = params;
1839 run = layout->clusters[first_cluster].run;
1841 /* Form runs from a range of clusters; this is what will be reported with DrawGlyphRun() */
1842 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0f;
1843 for (start = first_cluster, i = first_cluster; i <= last_cluster; i++) {
1844 layout_splitting_params_from_pos(layout, pos, &params);
1846 if (run != layout->clusters[i].run || !is_same_splitting_params(&prev_params, &params)) {
1847 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, &prev_params);
1848 if (FAILED(hr))
1849 return;
1851 origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) :
1852 get_cluster_range_width(layout, start, i);
1853 run = layout->clusters[i].run;
1854 start = i;
1857 prev_params = params;
1858 pos += layout->clustermetrics[i].length;
1861 /* Final run from what's left from cluster range */
1862 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, &prev_params);
1863 if (FAILED(hr))
1864 return;
1866 if (append_trimming_run) {
1867 struct layout_effective_inline *trimming_sign;
1869 trimming_sign = heap_alloc(sizeof(*trimming_sign));
1870 if (!trimming_sign)
1871 return;
1873 trimming_sign->object = layout->format.trimmingsign;
1874 trimming_sign->width = sign_metrics.width;
1875 origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) : get_cluster_range_width(layout, start, i);
1876 trimming_sign->origin.x = is_rtl ? origin_x - trimming_sign->width : origin_x;
1877 trimming_sign->origin.y = 0.0f; /* set after line is built */
1878 trimming_sign->align_dx = 0.0f;
1879 trimming_sign->baseline = sign_metrics.baseline;
1881 trimming_sign->is_sideways = FALSE;
1882 trimming_sign->is_rtl = FALSE;
1883 trimming_sign->line = line;
1885 trimming_sign->effect = NULL; /* FIXME */
1887 list_add_tail(&layout->inlineobjects, &trimming_sign->entry);
1890 /* Look for max baseline and descent for this line */
1891 for (index = first_cluster, metrics.baseline = 0.0f, descent = 0.0f; index <= last_cluster; index++) {
1892 const struct layout_run *cur = layout->clusters[index].run;
1893 FLOAT cur_descent = cur->height - cur->baseline;
1895 if (cur->baseline > metrics.baseline)
1896 metrics.baseline = cur->baseline;
1897 if (cur_descent > descent)
1898 descent = cur_descent;
1901 layout->metrics.width = max(width, layout->metrics.width);
1902 layout->metrics.widthIncludingTrailingWhitespace = max(width + trailingspacewidth,
1903 layout->metrics.widthIncludingTrailingWhitespace);
1905 metrics.height = descent + metrics.baseline;
1906 metrics.isTrimmed = append_trimming_run || width > layout->metrics.layoutWidth;
1907 layout_set_line_metrics(layout, &metrics);
1909 *textpos += metrics.length;
1912 static void layout_set_line_positions(struct dwrite_textlayout *layout)
1914 struct layout_effective_inline *inrun;
1915 struct layout_effective_run *erun;
1916 FLOAT origin_y;
1917 UINT32 line;
1919 /* Now all line info is here, update effective runs positions in flow direction */
1920 erun = layout_get_next_erun(layout, NULL);
1921 inrun = layout_get_next_inline_run(layout, NULL);
1923 for (line = 0, origin_y = 0.0f; line < layout->metrics.lineCount; line++) {
1924 FLOAT pos_y = origin_y + layout->linemetrics[line].baseline;
1926 /* For all runs on this line */
1927 while (erun && erun->line == line) {
1928 erun->origin.y = pos_y;
1929 erun = layout_get_next_erun(layout, erun);
1932 /* Same for inline runs */
1933 while (inrun && inrun->line == line) {
1934 inrun->origin.y = pos_y - inrun->baseline;
1935 inrun = layout_get_next_inline_run(layout, inrun);
1938 origin_y += layout->linemetrics[line].height;
1941 layout->metrics.height = origin_y;
1943 /* Initial paragraph alignment is always near */
1944 if (layout->format.paralign != DWRITE_PARAGRAPH_ALIGNMENT_NEAR)
1945 layout_apply_par_alignment(layout);
1948 static BOOL layout_can_wrap_after(const struct dwrite_textlayout *layout, UINT32 cluster)
1950 if (layout->format.wrapping == DWRITE_WORD_WRAPPING_CHARACTER)
1951 return TRUE;
1953 return layout->clustermetrics[cluster].canWrapLineAfter;
1956 static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
1958 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1959 struct layout_effective_run *erun, *first_underlined;
1960 UINT32 i, start, textpos, last_breaking_point;
1961 DWRITE_LINE_METRICS1 metrics;
1962 FLOAT width;
1963 UINT32 line;
1964 HRESULT hr;
1966 if (!(layout->recompute & RECOMPUTE_LINES))
1967 return S_OK;
1969 free_layout_eruns(layout);
1971 hr = layout_compute(layout);
1972 if (FAILED(hr))
1973 return hr;
1975 layout->metrics.lineCount = 0;
1976 memset(&metrics, 0, sizeof(metrics));
1978 layout->metrics.height = 0.0f;
1979 layout->metrics.width = 0.0f;
1980 layout->metrics.widthIncludingTrailingWhitespace = 0.0f;
1982 last_breaking_point = ~0u;
1984 for (i = 0, start = 0, width = 0.0f, textpos = 0; i < layout->cluster_count; i++) {
1985 BOOL overflow = FALSE;
1987 while (i < layout->cluster_count && !layout->clustermetrics[i].isNewline) {
1988 /* Check for overflow */
1989 overflow = ((width + layout->clustermetrics[i].width > layout->metrics.layoutWidth) &&
1990 (layout->format.wrapping != DWRITE_WORD_WRAPPING_NO_WRAP));
1991 if (overflow)
1992 break;
1994 if (layout_can_wrap_after(layout, i))
1995 last_breaking_point = i;
1996 width += layout->clustermetrics[i].width;
1997 i++;
1999 i = min(i, layout->cluster_count - 1);
2001 /* Ignore if overflown on whitespace */
2002 if (overflow && !(layout->clustermetrics[i].isWhitespace && layout_can_wrap_after(layout, i))) {
2003 /* Use most recently found breaking point */
2004 if (last_breaking_point != ~0u) {
2005 i = last_breaking_point;
2006 last_breaking_point = ~0u;
2008 else {
2009 /* Otherwise proceed forward to next newline or breaking point */
2010 for (; i < layout->cluster_count; i++)
2011 if (layout_can_wrap_after(layout, i) || layout->clustermetrics[i].isNewline)
2012 break;
2015 i = min(i, layout->cluster_count - 1);
2017 layout_add_line(layout, start, i, &textpos);
2018 start = i + 1;
2019 width = 0.0f;
2022 /* Add dummy line if:
2023 - there's no text, metrics come from first range in this case;
2024 - last ended with a mandatory break, metrics come from last text position.
2026 if (layout->len == 0)
2027 hr = layout_set_dummy_line_metrics(layout, 0);
2028 else if (layout->clustermetrics[layout->cluster_count - 1].isNewline)
2029 hr = layout_set_dummy_line_metrics(layout, layout->len - 1);
2030 if (FAILED(hr))
2031 return hr;
2033 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
2034 layout->metrics.top = 0.0f;
2035 layout->metrics.maxBidiReorderingDepth = 1; /* FIXME */
2037 /* Add explicit underlined runs */
2038 erun = layout_get_next_erun(layout, NULL);
2039 first_underlined = erun && erun->underlined ? erun : NULL;
2040 for (line = 0; line < layout->metrics.lineCount; line++) {
2041 while (erun && erun->line == line) {
2042 erun = layout_get_next_erun(layout, erun);
2044 if (first_underlined && (!erun || !erun->underlined)) {
2045 layout_add_underline(layout, first_underlined, erun);
2046 first_underlined = NULL;
2048 else if (!first_underlined && erun && erun->underlined)
2049 first_underlined = erun;
2053 /* Position runs in flow direction */
2054 layout_set_line_positions(layout);
2056 /* Initial alignment is always leading */
2057 if (layout->format.textalignment != DWRITE_TEXT_ALIGNMENT_LEADING)
2058 layout_apply_text_alignment(layout);
2060 layout->recompute &= ~RECOMPUTE_LINES;
2061 return hr;
2064 static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum layout_range_attr_kind attr,
2065 struct layout_range_attr_value *value)
2067 struct layout_range_spacing const *range_spacing = (struct layout_range_spacing*)h;
2068 struct layout_range_iface const *range_iface = (struct layout_range_iface*)h;
2069 struct layout_range_bool const *range_bool = (struct layout_range_bool*)h;
2070 struct layout_range const *range = (struct layout_range*)h;
2072 switch (attr) {
2073 case LAYOUT_RANGE_ATTR_WEIGHT:
2074 return range->weight == value->u.weight;
2075 case LAYOUT_RANGE_ATTR_STYLE:
2076 return range->style == value->u.style;
2077 case LAYOUT_RANGE_ATTR_STRETCH:
2078 return range->stretch == value->u.stretch;
2079 case LAYOUT_RANGE_ATTR_FONTSIZE:
2080 return range->fontsize == value->u.fontsize;
2081 case LAYOUT_RANGE_ATTR_INLINE:
2082 return range->object == value->u.object;
2083 case LAYOUT_RANGE_ATTR_EFFECT:
2084 return range_iface->iface == value->u.effect;
2085 case LAYOUT_RANGE_ATTR_UNDERLINE:
2086 return range_bool->value == value->u.underline;
2087 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2088 return range_bool->value == value->u.strikethrough;
2089 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2090 return range->pair_kerning == value->u.pair_kerning;
2091 case LAYOUT_RANGE_ATTR_FONTCOLL:
2092 return range->collection == value->u.collection;
2093 case LAYOUT_RANGE_ATTR_LOCALE:
2094 return strcmpiW(range->locale, value->u.locale) == 0;
2095 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2096 return strcmpW(range->fontfamily, value->u.fontfamily) == 0;
2097 case LAYOUT_RANGE_ATTR_SPACING:
2098 return range_spacing->leading == value->u.spacing[0] &&
2099 range_spacing->trailing == value->u.spacing[1] &&
2100 range_spacing->min_advance == value->u.spacing[2];
2101 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2102 return range_iface->iface == (IUnknown*)value->u.typography;
2103 default:
2107 return FALSE;
2110 static inline BOOL is_same_layout_attributes(struct layout_range_header const *hleft, struct layout_range_header const *hright)
2112 switch (hleft->kind)
2114 case LAYOUT_RANGE_REGULAR:
2116 struct layout_range const *left = (struct layout_range const*)hleft;
2117 struct layout_range const *right = (struct layout_range const*)hright;
2118 return left->weight == right->weight &&
2119 left->style == right->style &&
2120 left->stretch == right->stretch &&
2121 left->fontsize == right->fontsize &&
2122 left->object == right->object &&
2123 left->pair_kerning == right->pair_kerning &&
2124 left->collection == right->collection &&
2125 !strcmpiW(left->locale, right->locale) &&
2126 !strcmpW(left->fontfamily, right->fontfamily);
2128 case LAYOUT_RANGE_UNDERLINE:
2129 case LAYOUT_RANGE_STRIKETHROUGH:
2131 struct layout_range_bool const *left = (struct layout_range_bool const*)hleft;
2132 struct layout_range_bool const *right = (struct layout_range_bool const*)hright;
2133 return left->value == right->value;
2135 case LAYOUT_RANGE_EFFECT:
2136 case LAYOUT_RANGE_TYPOGRAPHY:
2138 struct layout_range_iface const *left = (struct layout_range_iface const*)hleft;
2139 struct layout_range_iface const *right = (struct layout_range_iface const*)hright;
2140 return left->iface == right->iface;
2142 case LAYOUT_RANGE_SPACING:
2144 struct layout_range_spacing const *left = (struct layout_range_spacing const*)hleft;
2145 struct layout_range_spacing const *right = (struct layout_range_spacing const*)hright;
2146 return left->leading == right->leading &&
2147 left->trailing == right->trailing &&
2148 left->min_advance == right->min_advance;
2150 default:
2151 FIXME("unknown range kind %d\n", hleft->kind);
2152 return FALSE;
2156 static inline BOOL is_same_text_range(const DWRITE_TEXT_RANGE *left, const DWRITE_TEXT_RANGE *right)
2158 return left->startPosition == right->startPosition && left->length == right->length;
2161 /* Allocates range and inits it with default values from text format. */
2162 static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout *layout, const DWRITE_TEXT_RANGE *r,
2163 enum layout_range_kind kind)
2165 struct layout_range_header *h;
2167 switch (kind)
2169 case LAYOUT_RANGE_REGULAR:
2171 struct layout_range *range;
2173 range = heap_alloc(sizeof(*range));
2174 if (!range) return NULL;
2176 range->weight = layout->format.weight;
2177 range->style = layout->format.style;
2178 range->stretch = layout->format.stretch;
2179 range->fontsize = layout->format.fontsize;
2180 range->object = NULL;
2181 range->pair_kerning = FALSE;
2183 range->fontfamily = heap_strdupW(layout->format.family_name);
2184 if (!range->fontfamily) {
2185 heap_free(range);
2186 return NULL;
2189 range->collection = layout->format.collection;
2190 if (range->collection)
2191 IDWriteFontCollection_AddRef(range->collection);
2192 strcpyW(range->locale, layout->format.locale);
2194 h = &range->h;
2195 break;
2197 case LAYOUT_RANGE_UNDERLINE:
2198 case LAYOUT_RANGE_STRIKETHROUGH:
2200 struct layout_range_bool *range;
2202 range = heap_alloc(sizeof(*range));
2203 if (!range) return NULL;
2205 range->value = FALSE;
2206 h = &range->h;
2207 break;
2209 case LAYOUT_RANGE_EFFECT:
2210 case LAYOUT_RANGE_TYPOGRAPHY:
2212 struct layout_range_iface *range;
2214 range = heap_alloc(sizeof(*range));
2215 if (!range) return NULL;
2217 range->iface = NULL;
2218 h = &range->h;
2219 break;
2221 case LAYOUT_RANGE_SPACING:
2223 struct layout_range_spacing *range;
2225 range = heap_alloc(sizeof(*range));
2226 if (!range) return NULL;
2228 range->leading = 0.0f;
2229 range->trailing = 0.0f;
2230 range->min_advance = 0.0f;
2231 h = &range->h;
2232 break;
2234 default:
2235 FIXME("unknown range kind %d\n", kind);
2236 return NULL;
2239 h->kind = kind;
2240 h->range = *r;
2241 return h;
2244 static struct layout_range_header *alloc_layout_range_from(struct layout_range_header *h, const DWRITE_TEXT_RANGE *r)
2246 struct layout_range_header *ret;
2248 switch (h->kind)
2250 case LAYOUT_RANGE_REGULAR:
2252 struct layout_range *from = (struct layout_range*)h;
2254 struct layout_range *range = heap_alloc(sizeof(*range));
2255 if (!range) return NULL;
2257 *range = *from;
2258 range->fontfamily = heap_strdupW(from->fontfamily);
2259 if (!range->fontfamily) {
2260 heap_free(range);
2261 return NULL;
2264 /* update refcounts */
2265 if (range->object)
2266 IDWriteInlineObject_AddRef(range->object);
2267 if (range->collection)
2268 IDWriteFontCollection_AddRef(range->collection);
2269 ret = &range->h;
2270 break;
2272 case LAYOUT_RANGE_UNDERLINE:
2273 case LAYOUT_RANGE_STRIKETHROUGH:
2275 struct layout_range_bool *strike = heap_alloc(sizeof(*strike));
2276 if (!strike) return NULL;
2278 *strike = *(struct layout_range_bool*)h;
2279 ret = &strike->h;
2280 break;
2282 case LAYOUT_RANGE_EFFECT:
2283 case LAYOUT_RANGE_TYPOGRAPHY:
2285 struct layout_range_iface *effect = heap_alloc(sizeof(*effect));
2286 if (!effect) return NULL;
2288 *effect = *(struct layout_range_iface*)h;
2289 if (effect->iface)
2290 IUnknown_AddRef(effect->iface);
2291 ret = &effect->h;
2292 break;
2294 case LAYOUT_RANGE_SPACING:
2296 struct layout_range_spacing *spacing = heap_alloc(sizeof(*spacing));
2297 if (!spacing) return NULL;
2299 *spacing = *(struct layout_range_spacing*)h;
2300 ret = &spacing->h;
2301 break;
2303 default:
2304 FIXME("unknown range kind %d\n", h->kind);
2305 return NULL;
2308 ret->range = *r;
2309 return ret;
2312 static void free_layout_range(struct layout_range_header *h)
2314 if (!h)
2315 return;
2317 switch (h->kind)
2319 case LAYOUT_RANGE_REGULAR:
2321 struct layout_range *range = (struct layout_range*)h;
2323 if (range->object)
2324 IDWriteInlineObject_Release(range->object);
2325 if (range->collection)
2326 IDWriteFontCollection_Release(range->collection);
2327 heap_free(range->fontfamily);
2328 break;
2330 case LAYOUT_RANGE_EFFECT:
2331 case LAYOUT_RANGE_TYPOGRAPHY:
2333 struct layout_range_iface *range = (struct layout_range_iface*)h;
2334 if (range->iface)
2335 IUnknown_Release(range->iface);
2336 break;
2338 default:
2342 heap_free(h);
2345 static void free_layout_ranges_list(struct dwrite_textlayout *layout)
2347 struct layout_range_header *cur, *cur2;
2349 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->ranges, struct layout_range_header, entry) {
2350 list_remove(&cur->entry);
2351 free_layout_range(cur);
2354 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->underline_ranges, struct layout_range_header, entry) {
2355 list_remove(&cur->entry);
2356 free_layout_range(cur);
2359 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->strike_ranges, struct layout_range_header, entry) {
2360 list_remove(&cur->entry);
2361 free_layout_range(cur);
2364 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->effects, struct layout_range_header, entry) {
2365 list_remove(&cur->entry);
2366 free_layout_range(cur);
2369 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->spacing, struct layout_range_header, entry) {
2370 list_remove(&cur->entry);
2371 free_layout_range(cur);
2374 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->typographies, struct layout_range_header, entry) {
2375 list_remove(&cur->entry);
2376 free_layout_range(cur);
2380 static struct layout_range_header *find_outer_range(struct list *ranges, const DWRITE_TEXT_RANGE *range)
2382 struct layout_range_header *cur;
2384 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
2386 if (cur->range.startPosition > range->startPosition)
2387 return NULL;
2389 if ((cur->range.startPosition + cur->range.length < range->startPosition + range->length) &&
2390 (range->startPosition < cur->range.startPosition + cur->range.length))
2391 return NULL;
2392 if (cur->range.startPosition + cur->range.length >= range->startPosition + range->length)
2393 return cur;
2396 return NULL;
2399 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos)
2401 struct layout_range *cur;
2403 LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, h.entry) {
2404 DWRITE_TEXT_RANGE *r = &cur->h.range;
2405 if (r->startPosition <= pos && pos < r->startPosition + r->length)
2406 return cur;
2409 return NULL;
2412 static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
2414 if (*dest == value) return FALSE;
2416 if (*dest)
2417 IUnknown_Release(*dest);
2418 *dest = value;
2419 if (*dest)
2420 IUnknown_AddRef(*dest);
2422 return TRUE;
2425 static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2427 struct layout_range_spacing *dest_spacing = (struct layout_range_spacing*)h;
2428 struct layout_range_iface *dest_iface = (struct layout_range_iface*)h;
2429 struct layout_range_bool *dest_bool = (struct layout_range_bool*)h;
2430 struct layout_range *dest = (struct layout_range*)h;
2432 BOOL changed = FALSE;
2434 switch (attr) {
2435 case LAYOUT_RANGE_ATTR_WEIGHT:
2436 changed = dest->weight != value->u.weight;
2437 dest->weight = value->u.weight;
2438 break;
2439 case LAYOUT_RANGE_ATTR_STYLE:
2440 changed = dest->style != value->u.style;
2441 dest->style = value->u.style;
2442 break;
2443 case LAYOUT_RANGE_ATTR_STRETCH:
2444 changed = dest->stretch != value->u.stretch;
2445 dest->stretch = value->u.stretch;
2446 break;
2447 case LAYOUT_RANGE_ATTR_FONTSIZE:
2448 changed = dest->fontsize != value->u.fontsize;
2449 dest->fontsize = value->u.fontsize;
2450 break;
2451 case LAYOUT_RANGE_ATTR_INLINE:
2452 changed = set_layout_range_iface_attr((IUnknown**)&dest->object, (IUnknown*)value->u.object);
2453 break;
2454 case LAYOUT_RANGE_ATTR_EFFECT:
2455 changed = set_layout_range_iface_attr((IUnknown**)&dest_iface->iface, (IUnknown*)value->u.effect);
2456 break;
2457 case LAYOUT_RANGE_ATTR_UNDERLINE:
2458 changed = dest_bool->value != value->u.underline;
2459 dest_bool->value = value->u.underline;
2460 break;
2461 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2462 changed = dest_bool->value != value->u.strikethrough;
2463 dest_bool->value = value->u.strikethrough;
2464 break;
2465 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2466 changed = dest->pair_kerning != value->u.pair_kerning;
2467 dest->pair_kerning = value->u.pair_kerning;
2468 break;
2469 case LAYOUT_RANGE_ATTR_FONTCOLL:
2470 changed = set_layout_range_iface_attr((IUnknown**)&dest->collection, (IUnknown*)value->u.collection);
2471 break;
2472 case LAYOUT_RANGE_ATTR_LOCALE:
2473 changed = strcmpiW(dest->locale, value->u.locale) != 0;
2474 if (changed) {
2475 strcpyW(dest->locale, value->u.locale);
2476 strlwrW(dest->locale);
2478 break;
2479 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2480 changed = strcmpW(dest->fontfamily, value->u.fontfamily) != 0;
2481 if (changed) {
2482 heap_free(dest->fontfamily);
2483 dest->fontfamily = heap_strdupW(value->u.fontfamily);
2485 break;
2486 case LAYOUT_RANGE_ATTR_SPACING:
2487 changed = dest_spacing->leading != value->u.spacing[0] ||
2488 dest_spacing->trailing != value->u.spacing[1] ||
2489 dest_spacing->min_advance != value->u.spacing[2];
2490 dest_spacing->leading = value->u.spacing[0];
2491 dest_spacing->trailing = value->u.spacing[1];
2492 dest_spacing->min_advance = value->u.spacing[2];
2493 break;
2494 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2495 changed = set_layout_range_iface_attr((IUnknown**)&dest_iface->iface, (IUnknown*)value->u.typography);
2496 break;
2497 default:
2501 return changed;
2504 static inline BOOL is_in_layout_range(const DWRITE_TEXT_RANGE *outer, const DWRITE_TEXT_RANGE *inner)
2506 return (inner->startPosition >= outer->startPosition) &&
2507 (inner->startPosition + inner->length <= outer->startPosition + outer->length);
2510 static inline HRESULT return_range(const struct layout_range_header *h, DWRITE_TEXT_RANGE *r)
2512 if (r) *r = h->range;
2513 return S_OK;
2516 /* Sets attribute value for given range, does all needed splitting/merging of existing ranges. */
2517 static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2519 struct layout_range_header *cur, *right, *left, *outer;
2520 BOOL changed = FALSE;
2521 struct list *ranges;
2522 DWRITE_TEXT_RANGE r;
2524 /* ignore zero length ranges */
2525 if (value->range.length == 0)
2526 return S_OK;
2528 /* select from ranges lists */
2529 switch (attr)
2531 case LAYOUT_RANGE_ATTR_WEIGHT:
2532 case LAYOUT_RANGE_ATTR_STYLE:
2533 case LAYOUT_RANGE_ATTR_STRETCH:
2534 case LAYOUT_RANGE_ATTR_FONTSIZE:
2535 case LAYOUT_RANGE_ATTR_INLINE:
2536 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2537 case LAYOUT_RANGE_ATTR_FONTCOLL:
2538 case LAYOUT_RANGE_ATTR_LOCALE:
2539 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2540 ranges = &layout->ranges;
2541 break;
2542 case LAYOUT_RANGE_ATTR_UNDERLINE:
2543 ranges = &layout->underline_ranges;
2544 break;
2545 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2546 ranges = &layout->strike_ranges;
2547 break;
2548 case LAYOUT_RANGE_ATTR_EFFECT:
2549 ranges = &layout->effects;
2550 break;
2551 case LAYOUT_RANGE_ATTR_SPACING:
2552 ranges = &layout->spacing;
2553 break;
2554 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2555 ranges = &layout->typographies;
2556 break;
2557 default:
2558 FIXME("unknown attr kind %d\n", attr);
2559 return E_FAIL;
2562 /* If new range is completely within existing range, split existing range in two */
2563 if ((outer = find_outer_range(ranges, &value->range))) {
2565 /* no need to add same range */
2566 if (is_same_layout_attrvalue(outer, attr, value))
2567 return S_OK;
2569 /* for matching range bounds just replace data */
2570 if (is_same_text_range(&outer->range, &value->range)) {
2571 changed = set_layout_range_attrval(outer, attr, value);
2572 goto done;
2575 /* add new range to the left */
2576 if (value->range.startPosition == outer->range.startPosition) {
2577 left = alloc_layout_range_from(outer, &value->range);
2578 if (!left) return E_OUTOFMEMORY;
2580 changed = set_layout_range_attrval(left, attr, value);
2581 list_add_before(&outer->entry, &left->entry);
2582 outer->range.startPosition += value->range.length;
2583 outer->range.length -= value->range.length;
2584 goto done;
2587 /* add new range to the right */
2588 if (value->range.startPosition + value->range.length == outer->range.startPosition + outer->range.length) {
2589 right = alloc_layout_range_from(outer, &value->range);
2590 if (!right) return E_OUTOFMEMORY;
2592 changed = set_layout_range_attrval(right, attr, value);
2593 list_add_after(&outer->entry, &right->entry);
2594 outer->range.length -= value->range.length;
2595 goto done;
2598 r.startPosition = value->range.startPosition + value->range.length;
2599 r.length = outer->range.length + outer->range.startPosition - r.startPosition;
2601 /* right part */
2602 right = alloc_layout_range_from(outer, &r);
2603 /* new range in the middle */
2604 cur = alloc_layout_range_from(outer, &value->range);
2605 if (!right || !cur) {
2606 free_layout_range(right);
2607 free_layout_range(cur);
2608 return E_OUTOFMEMORY;
2611 /* reuse container range as a left part */
2612 outer->range.length = value->range.startPosition - outer->range.startPosition;
2614 /* new part */
2615 set_layout_range_attrval(cur, attr, value);
2617 list_add_after(&outer->entry, &cur->entry);
2618 list_add_after(&cur->entry, &right->entry);
2620 layout->recompute = RECOMPUTE_EVERYTHING;
2621 return S_OK;
2624 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2625 Update all of them. */
2626 left = get_layout_range_header_by_pos(ranges, value->range.startPosition);
2627 if (left->range.startPosition == value->range.startPosition)
2628 changed = set_layout_range_attrval(left, attr, value);
2629 else /* need to split */ {
2630 r.startPosition = value->range.startPosition;
2631 r.length = left->range.length - value->range.startPosition + left->range.startPosition;
2632 left->range.length -= r.length;
2633 cur = alloc_layout_range_from(left, &r);
2634 changed = set_layout_range_attrval(cur, attr, value);
2635 list_add_after(&left->entry, &cur->entry);
2637 cur = LIST_ENTRY(list_next(ranges, &left->entry), struct layout_range_header, entry);
2639 /* for all existing ranges covered by new one update value */
2640 while (cur && is_in_layout_range(&value->range, &cur->range)) {
2641 changed |= set_layout_range_attrval(cur, attr, value);
2642 cur = LIST_ENTRY(list_next(ranges, &cur->entry), struct layout_range_header, entry);
2645 /* it's possible rightmost range intersects */
2646 if (cur && (cur->range.startPosition < value->range.startPosition + value->range.length)) {
2647 r.startPosition = cur->range.startPosition;
2648 r.length = value->range.startPosition + value->range.length - cur->range.startPosition;
2649 left = alloc_layout_range_from(cur, &r);
2650 changed |= set_layout_range_attrval(left, attr, value);
2651 cur->range.startPosition += left->range.length;
2652 cur->range.length -= left->range.length;
2653 list_add_before(&cur->entry, &left->entry);
2656 done:
2657 if (changed) {
2658 struct list *next, *i;
2660 layout->recompute = RECOMPUTE_EVERYTHING;
2661 i = list_head(ranges);
2662 while ((next = list_next(ranges, i))) {
2663 struct layout_range_header *next_range = LIST_ENTRY(next, struct layout_range_header, entry);
2665 cur = LIST_ENTRY(i, struct layout_range_header, entry);
2666 if (is_same_layout_attributes(cur, next_range)) {
2667 /* remove similar range */
2668 cur->range.length += next_range->range.length;
2669 list_remove(next);
2670 free_layout_range(next_range);
2672 else
2673 i = list_next(ranges, i);
2677 return S_OK;
2680 static inline const WCHAR *get_string_attribute_ptr(struct layout_range *range, enum layout_range_attr_kind kind)
2682 const WCHAR *str;
2684 switch (kind) {
2685 case LAYOUT_RANGE_ATTR_LOCALE:
2686 str = range->locale;
2687 break;
2688 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2689 str = range->fontfamily;
2690 break;
2691 default:
2692 str = NULL;
2695 return str;
2698 static HRESULT get_string_attribute_length(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2699 UINT32 *length, DWRITE_TEXT_RANGE *r)
2701 struct layout_range *range;
2702 const WCHAR *str;
2704 range = get_layout_range_by_pos(layout, position);
2705 if (!range) {
2706 *length = 0;
2707 return S_OK;
2710 str = get_string_attribute_ptr(range, kind);
2711 *length = strlenW(str);
2712 return return_range(&range->h, r);
2715 static HRESULT get_string_attribute_value(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2716 WCHAR *ret, UINT32 length, DWRITE_TEXT_RANGE *r)
2718 struct layout_range *range;
2719 const WCHAR *str;
2721 if (length == 0)
2722 return E_INVALIDARG;
2724 ret[0] = 0;
2725 range = get_layout_range_by_pos(layout, position);
2726 if (!range)
2727 return E_INVALIDARG;
2729 str = get_string_attribute_ptr(range, kind);
2730 if (length < strlenW(str) + 1)
2731 return E_NOT_SUFFICIENT_BUFFER;
2733 strcpyW(ret, str);
2734 return return_range(&range->h, r);
2737 static HRESULT WINAPI dwritetextlayout_QueryInterface(IDWriteTextLayout3 *iface, REFIID riid, void **obj)
2739 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2741 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2743 *obj = NULL;
2745 if (IsEqualIID(riid, &IID_IDWriteTextLayout3) ||
2746 IsEqualIID(riid, &IID_IDWriteTextLayout2) ||
2747 IsEqualIID(riid, &IID_IDWriteTextLayout1) ||
2748 IsEqualIID(riid, &IID_IDWriteTextLayout) ||
2749 IsEqualIID(riid, &IID_IUnknown))
2751 *obj = iface;
2753 else if (IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
2754 IsEqualIID(riid, &IID_IDWriteTextFormat))
2755 *obj = &This->IDWriteTextFormat1_iface;
2757 if (*obj) {
2758 IDWriteTextLayout3_AddRef(iface);
2759 return S_OK;
2762 return E_NOINTERFACE;
2765 static ULONG WINAPI dwritetextlayout_AddRef(IDWriteTextLayout3 *iface)
2767 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2768 ULONG ref = InterlockedIncrement(&This->ref);
2769 TRACE("(%p)->(%d)\n", This, ref);
2770 return ref;
2773 static ULONG WINAPI dwritetextlayout_Release(IDWriteTextLayout3 *iface)
2775 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2776 ULONG ref = InterlockedDecrement(&This->ref);
2778 TRACE("(%p)->(%d)\n", This, ref);
2780 if (!ref) {
2781 IDWriteFactory5_Release(This->factory);
2782 free_layout_ranges_list(This);
2783 free_layout_eruns(This);
2784 free_layout_runs(This);
2785 release_format_data(&This->format);
2786 heap_free(This->nominal_breakpoints);
2787 heap_free(This->actual_breakpoints);
2788 heap_free(This->clustermetrics);
2789 heap_free(This->clusters);
2790 heap_free(This->linemetrics);
2791 heap_free(This->lines);
2792 heap_free(This->str);
2793 heap_free(This);
2796 return ref;
2799 static HRESULT WINAPI dwritetextlayout_SetTextAlignment(IDWriteTextLayout3 *iface, DWRITE_TEXT_ALIGNMENT alignment)
2801 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2802 return IDWriteTextFormat1_SetTextAlignment(&This->IDWriteTextFormat1_iface, alignment);
2805 static HRESULT WINAPI dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout3 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
2807 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2808 return IDWriteTextFormat1_SetParagraphAlignment(&This->IDWriteTextFormat1_iface, alignment);
2811 static HRESULT WINAPI dwritetextlayout_SetWordWrapping(IDWriteTextLayout3 *iface, DWRITE_WORD_WRAPPING wrapping)
2813 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2814 return IDWriteTextFormat1_SetWordWrapping(&This->IDWriteTextFormat1_iface, wrapping);
2817 static HRESULT WINAPI dwritetextlayout_SetReadingDirection(IDWriteTextLayout3 *iface, DWRITE_READING_DIRECTION direction)
2819 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2820 return IDWriteTextFormat1_SetReadingDirection(&This->IDWriteTextFormat1_iface, direction);
2823 static HRESULT WINAPI dwritetextlayout_SetFlowDirection(IDWriteTextLayout3 *iface, DWRITE_FLOW_DIRECTION direction)
2825 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2826 TRACE("(%p)->(%d)\n", This, direction);
2827 return IDWriteTextFormat1_SetFlowDirection(&This->IDWriteTextFormat1_iface, direction);
2830 static HRESULT WINAPI dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout3 *iface, FLOAT tabstop)
2832 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2833 TRACE("(%p)->(%.2f)\n", This, tabstop);
2834 return IDWriteTextFormat1_SetIncrementalTabStop(&This->IDWriteTextFormat1_iface, tabstop);
2837 static HRESULT WINAPI dwritetextlayout_SetTrimming(IDWriteTextLayout3 *iface, DWRITE_TRIMMING const *trimming,
2838 IDWriteInlineObject *trimming_sign)
2840 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2841 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
2842 return IDWriteTextFormat1_SetTrimming(&This->IDWriteTextFormat1_iface, trimming, trimming_sign);
2845 static HRESULT WINAPI dwritetextlayout_SetLineSpacing(IDWriteTextLayout3 *iface, DWRITE_LINE_SPACING_METHOD spacing,
2846 FLOAT line_spacing, FLOAT baseline)
2848 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2849 TRACE("(%p)->(%d %.2f %.2f)\n", This, spacing, line_spacing, baseline);
2850 return IDWriteTextFormat1_SetLineSpacing(&This->IDWriteTextFormat1_iface, spacing, line_spacing, baseline);
2853 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextlayout_GetTextAlignment(IDWriteTextLayout3 *iface)
2855 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2856 return IDWriteTextFormat1_GetTextAlignment(&This->IDWriteTextFormat1_iface);
2859 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout3 *iface)
2861 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2862 return IDWriteTextFormat1_GetParagraphAlignment(&This->IDWriteTextFormat1_iface);
2865 static DWRITE_WORD_WRAPPING WINAPI dwritetextlayout_GetWordWrapping(IDWriteTextLayout3 *iface)
2867 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2868 return IDWriteTextFormat1_GetWordWrapping(&This->IDWriteTextFormat1_iface);
2871 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_GetReadingDirection(IDWriteTextLayout3 *iface)
2873 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2874 return IDWriteTextFormat1_GetReadingDirection(&This->IDWriteTextFormat1_iface);
2877 static DWRITE_FLOW_DIRECTION WINAPI dwritetextlayout_GetFlowDirection(IDWriteTextLayout3 *iface)
2879 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2880 return IDWriteTextFormat1_GetFlowDirection(&This->IDWriteTextFormat1_iface);
2883 static FLOAT WINAPI dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout3 *iface)
2885 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2886 return IDWriteTextFormat1_GetIncrementalTabStop(&This->IDWriteTextFormat1_iface);
2889 static HRESULT WINAPI dwritetextlayout_GetTrimming(IDWriteTextLayout3 *iface, DWRITE_TRIMMING *options,
2890 IDWriteInlineObject **trimming_sign)
2892 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2893 return IDWriteTextFormat1_GetTrimming(&This->IDWriteTextFormat1_iface, options, trimming_sign);
2896 static HRESULT WINAPI dwritetextlayout_GetLineSpacing(IDWriteTextLayout3 *iface, DWRITE_LINE_SPACING_METHOD *method,
2897 FLOAT *spacing, FLOAT *baseline)
2899 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2900 return IDWriteTextFormat_GetLineSpacing((IDWriteTextFormat*)&This->IDWriteTextFormat1_iface, method, spacing, baseline);
2903 static HRESULT WINAPI dwritetextlayout_GetFontCollection(IDWriteTextLayout3 *iface, IDWriteFontCollection **collection)
2905 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2906 return IDWriteTextFormat1_GetFontCollection(&This->IDWriteTextFormat1_iface, collection);
2909 static UINT32 WINAPI dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout3 *iface)
2911 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2912 return IDWriteTextFormat1_GetFontFamilyNameLength(&This->IDWriteTextFormat1_iface);
2915 static HRESULT WINAPI dwritetextlayout_GetFontFamilyName(IDWriteTextLayout3 *iface, WCHAR *name, UINT32 size)
2917 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2918 return IDWriteTextFormat1_GetFontFamilyName(&This->IDWriteTextFormat1_iface, name, size);
2921 static DWRITE_FONT_WEIGHT WINAPI dwritetextlayout_GetFontWeight(IDWriteTextLayout3 *iface)
2923 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2924 return IDWriteTextFormat1_GetFontWeight(&This->IDWriteTextFormat1_iface);
2927 static DWRITE_FONT_STYLE WINAPI dwritetextlayout_GetFontStyle(IDWriteTextLayout3 *iface)
2929 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2930 return IDWriteTextFormat1_GetFontStyle(&This->IDWriteTextFormat1_iface);
2933 static DWRITE_FONT_STRETCH WINAPI dwritetextlayout_GetFontStretch(IDWriteTextLayout3 *iface)
2935 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2936 return IDWriteTextFormat1_GetFontStretch(&This->IDWriteTextFormat1_iface);
2939 static FLOAT WINAPI dwritetextlayout_GetFontSize(IDWriteTextLayout3 *iface)
2941 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2942 return IDWriteTextFormat1_GetFontSize(&This->IDWriteTextFormat1_iface);
2945 static UINT32 WINAPI dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout3 *iface)
2947 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2948 return IDWriteTextFormat1_GetLocaleNameLength(&This->IDWriteTextFormat1_iface);
2951 static HRESULT WINAPI dwritetextlayout_GetLocaleName(IDWriteTextLayout3 *iface, WCHAR *name, UINT32 size)
2953 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2954 return IDWriteTextFormat1_GetLocaleName(&This->IDWriteTextFormat1_iface, name, size);
2957 static HRESULT WINAPI dwritetextlayout_SetMaxWidth(IDWriteTextLayout3 *iface, FLOAT maxWidth)
2959 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2960 BOOL changed;
2962 TRACE("(%p)->(%.2f)\n", This, maxWidth);
2964 if (maxWidth < 0.0f)
2965 return E_INVALIDARG;
2967 changed = This->metrics.layoutWidth != maxWidth;
2968 This->metrics.layoutWidth = maxWidth;
2970 if (changed)
2971 This->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
2972 return S_OK;
2975 static HRESULT WINAPI dwritetextlayout_SetMaxHeight(IDWriteTextLayout3 *iface, FLOAT maxHeight)
2977 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2978 BOOL changed;
2980 TRACE("(%p)->(%.2f)\n", This, maxHeight);
2982 if (maxHeight < 0.0f)
2983 return E_INVALIDARG;
2985 changed = This->metrics.layoutHeight != maxHeight;
2986 This->metrics.layoutHeight = maxHeight;
2988 if (changed)
2989 This->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
2990 return S_OK;
2993 static HRESULT WINAPI dwritetextlayout_SetFontCollection(IDWriteTextLayout3 *iface, IDWriteFontCollection* collection, DWRITE_TEXT_RANGE range)
2995 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2996 struct layout_range_attr_value value;
2998 TRACE("(%p)->(%p %s)\n", This, collection, debugstr_range(&range));
3000 value.range = range;
3001 value.u.collection = collection;
3002 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTCOLL, &value);
3005 static HRESULT WINAPI dwritetextlayout_SetFontFamilyName(IDWriteTextLayout3 *iface, WCHAR const *name, DWRITE_TEXT_RANGE range)
3007 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3008 struct layout_range_attr_value value;
3010 TRACE("(%p)->(%s %s)\n", This, debugstr_w(name), debugstr_range(&range));
3012 if (!name)
3013 return E_INVALIDARG;
3015 value.range = range;
3016 value.u.fontfamily = name;
3017 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTFAMILY, &value);
3020 static HRESULT WINAPI dwritetextlayout_SetFontWeight(IDWriteTextLayout3 *iface, DWRITE_FONT_WEIGHT weight, DWRITE_TEXT_RANGE range)
3022 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3023 struct layout_range_attr_value value;
3025 TRACE("(%p)->(%d %s)\n", This, weight, debugstr_range(&range));
3027 if ((UINT32)weight > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
3028 return E_INVALIDARG;
3030 value.range = range;
3031 value.u.weight = weight;
3032 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_WEIGHT, &value);
3035 static HRESULT WINAPI dwritetextlayout_SetFontStyle(IDWriteTextLayout3 *iface, DWRITE_FONT_STYLE style, DWRITE_TEXT_RANGE range)
3037 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3038 struct layout_range_attr_value value;
3040 TRACE("(%p)->(%d %s)\n", This, style, debugstr_range(&range));
3042 if ((UINT32)style > DWRITE_FONT_STYLE_ITALIC)
3043 return E_INVALIDARG;
3045 value.range = range;
3046 value.u.style = style;
3047 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STYLE, &value);
3050 static HRESULT WINAPI dwritetextlayout_SetFontStretch(IDWriteTextLayout3 *iface, DWRITE_FONT_STRETCH stretch, DWRITE_TEXT_RANGE range)
3052 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3053 struct layout_range_attr_value value;
3055 TRACE("(%p)->(%d %s)\n", This, stretch, debugstr_range(&range));
3057 if (stretch == DWRITE_FONT_STRETCH_UNDEFINED || (UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
3058 return E_INVALIDARG;
3060 value.range = range;
3061 value.u.stretch = stretch;
3062 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRETCH, &value);
3065 static HRESULT WINAPI dwritetextlayout_SetFontSize(IDWriteTextLayout3 *iface, FLOAT size, DWRITE_TEXT_RANGE range)
3067 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3068 struct layout_range_attr_value value;
3070 TRACE("(%p)->(%.2f %s)\n", This, size, debugstr_range(&range));
3072 if (size <= 0.0f)
3073 return E_INVALIDARG;
3075 value.range = range;
3076 value.u.fontsize = size;
3077 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTSIZE, &value);
3080 static HRESULT WINAPI dwritetextlayout_SetUnderline(IDWriteTextLayout3 *iface, BOOL underline, DWRITE_TEXT_RANGE range)
3082 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3083 struct layout_range_attr_value value;
3085 TRACE("(%p)->(%d %s)\n", This, underline, debugstr_range(&range));
3087 value.range = range;
3088 value.u.underline = underline;
3089 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_UNDERLINE, &value);
3092 static HRESULT WINAPI dwritetextlayout_SetStrikethrough(IDWriteTextLayout3 *iface, BOOL strikethrough, DWRITE_TEXT_RANGE range)
3094 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3095 struct layout_range_attr_value value;
3097 TRACE("(%p)->(%d %s)\n", This, strikethrough, debugstr_range(&range));
3099 value.range = range;
3100 value.u.strikethrough = strikethrough;
3101 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRIKETHROUGH, &value);
3104 static HRESULT WINAPI dwritetextlayout_SetDrawingEffect(IDWriteTextLayout3 *iface, IUnknown* effect, DWRITE_TEXT_RANGE range)
3106 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3107 struct layout_range_attr_value value;
3109 TRACE("(%p)->(%p %s)\n", This, effect, debugstr_range(&range));
3111 value.range = range;
3112 value.u.effect = effect;
3113 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_EFFECT, &value);
3116 static HRESULT WINAPI dwritetextlayout_SetInlineObject(IDWriteTextLayout3 *iface, IDWriteInlineObject *object, DWRITE_TEXT_RANGE range)
3118 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3119 struct layout_range_attr_value value;
3121 TRACE("(%p)->(%p %s)\n", This, object, debugstr_range(&range));
3123 value.range = range;
3124 value.u.object = object;
3125 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_INLINE, &value);
3128 static HRESULT WINAPI dwritetextlayout_SetTypography(IDWriteTextLayout3 *iface, IDWriteTypography* typography, DWRITE_TEXT_RANGE range)
3130 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3131 struct layout_range_attr_value value;
3133 TRACE("(%p)->(%p %s)\n", This, typography, debugstr_range(&range));
3135 value.range = range;
3136 value.u.typography = typography;
3137 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_TYPOGRAPHY, &value);
3140 static HRESULT WINAPI dwritetextlayout_SetLocaleName(IDWriteTextLayout3 *iface, WCHAR const* locale, DWRITE_TEXT_RANGE range)
3142 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3143 struct layout_range_attr_value value;
3145 TRACE("(%p)->(%s %s)\n", This, debugstr_w(locale), debugstr_range(&range));
3147 if (!locale || strlenW(locale) > LOCALE_NAME_MAX_LENGTH-1)
3148 return E_INVALIDARG;
3150 value.range = range;
3151 value.u.locale = locale;
3152 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_LOCALE, &value);
3155 static FLOAT WINAPI dwritetextlayout_GetMaxWidth(IDWriteTextLayout3 *iface)
3157 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3158 TRACE("(%p)\n", This);
3159 return This->metrics.layoutWidth;
3162 static FLOAT WINAPI dwritetextlayout_GetMaxHeight(IDWriteTextLayout3 *iface)
3164 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3165 TRACE("(%p)\n", This);
3166 return This->metrics.layoutHeight;
3169 static HRESULT WINAPI dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout3 *iface, UINT32 position,
3170 IDWriteFontCollection** collection, DWRITE_TEXT_RANGE *r)
3172 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3173 struct layout_range *range;
3175 TRACE("(%p)->(%u %p %p)\n", This, position, collection, r);
3177 if (position >= This->len)
3178 return S_OK;
3180 range = get_layout_range_by_pos(This, position);
3181 *collection = range->collection;
3182 if (*collection)
3183 IDWriteFontCollection_AddRef(*collection);
3185 return return_range(&range->h, r);
3188 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout3 *iface,
3189 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
3191 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3192 TRACE("(%p)->(%d %p %p)\n", This, position, length, r);
3193 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, length, r);
3196 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout3 *iface,
3197 UINT32 position, WCHAR *name, UINT32 length, DWRITE_TEXT_RANGE *r)
3199 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3200 TRACE("(%p)->(%u %p %u %p)\n", This, position, name, length, r);
3201 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, name, length, r);
3204 static HRESULT WINAPI dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout3 *iface,
3205 UINT32 position, DWRITE_FONT_WEIGHT *weight, DWRITE_TEXT_RANGE *r)
3207 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3208 struct layout_range *range;
3210 TRACE("(%p)->(%u %p %p)\n", This, position, weight, r);
3212 if (position >= This->len)
3213 return S_OK;
3215 range = get_layout_range_by_pos(This, position);
3216 *weight = range->weight;
3218 return return_range(&range->h, r);
3221 static HRESULT WINAPI dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout3 *iface,
3222 UINT32 position, DWRITE_FONT_STYLE *style, DWRITE_TEXT_RANGE *r)
3224 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3225 struct layout_range *range;
3227 TRACE("(%p)->(%u %p %p)\n", This, position, style, r);
3229 range = get_layout_range_by_pos(This, position);
3230 *style = range->style;
3231 return return_range(&range->h, r);
3234 static HRESULT WINAPI dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout3 *iface,
3235 UINT32 position, DWRITE_FONT_STRETCH *stretch, DWRITE_TEXT_RANGE *r)
3237 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3238 struct layout_range *range;
3240 TRACE("(%p)->(%u %p %p)\n", This, position, stretch, r);
3242 range = get_layout_range_by_pos(This, position);
3243 *stretch = range->stretch;
3244 return return_range(&range->h, r);
3247 static HRESULT WINAPI dwritetextlayout_layout_GetFontSize(IDWriteTextLayout3 *iface,
3248 UINT32 position, FLOAT *size, DWRITE_TEXT_RANGE *r)
3250 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3251 struct layout_range *range;
3253 TRACE("(%p)->(%u %p %p)\n", This, position, size, r);
3255 range = get_layout_range_by_pos(This, position);
3256 *size = range->fontsize;
3257 return return_range(&range->h, r);
3260 static HRESULT WINAPI dwritetextlayout_GetUnderline(IDWriteTextLayout3 *iface,
3261 UINT32 position, BOOL *underline, DWRITE_TEXT_RANGE *r)
3263 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3264 struct layout_range_bool *range;
3266 TRACE("(%p)->(%u %p %p)\n", This, position, underline, r);
3268 range = (struct layout_range_bool*)get_layout_range_header_by_pos(&This->underline_ranges, position);
3269 *underline = range->value;
3271 return return_range(&range->h, r);
3274 static HRESULT WINAPI dwritetextlayout_GetStrikethrough(IDWriteTextLayout3 *iface,
3275 UINT32 position, BOOL *strikethrough, DWRITE_TEXT_RANGE *r)
3277 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3278 struct layout_range_bool *range;
3280 TRACE("(%p)->(%u %p %p)\n", This, position, strikethrough, r);
3282 range = (struct layout_range_bool*)get_layout_range_header_by_pos(&This->strike_ranges, position);
3283 *strikethrough = range->value;
3285 return return_range(&range->h, r);
3288 static HRESULT WINAPI dwritetextlayout_GetDrawingEffect(IDWriteTextLayout3 *iface,
3289 UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r)
3291 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3292 struct layout_range_iface *range;
3294 TRACE("(%p)->(%u %p %p)\n", This, position, effect, r);
3296 range = (struct layout_range_iface*)get_layout_range_header_by_pos(&This->effects, position);
3297 *effect = range->iface;
3298 if (*effect)
3299 IUnknown_AddRef(*effect);
3301 return return_range(&range->h, r);
3304 static HRESULT WINAPI dwritetextlayout_GetInlineObject(IDWriteTextLayout3 *iface,
3305 UINT32 position, IDWriteInlineObject **object, DWRITE_TEXT_RANGE *r)
3307 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3308 struct layout_range *range;
3310 TRACE("(%p)->(%u %p %p)\n", This, position, object, r);
3312 if (position >= This->len)
3313 return S_OK;
3315 range = get_layout_range_by_pos(This, position);
3316 *object = range->object;
3317 if (*object)
3318 IDWriteInlineObject_AddRef(*object);
3320 return return_range(&range->h, r);
3323 static HRESULT WINAPI dwritetextlayout_GetTypography(IDWriteTextLayout3 *iface,
3324 UINT32 position, IDWriteTypography** typography, DWRITE_TEXT_RANGE *r)
3326 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3327 struct layout_range_iface *range;
3329 TRACE("(%p)->(%u %p %p)\n", This, position, typography, r);
3331 range = (struct layout_range_iface*)get_layout_range_header_by_pos(&This->typographies, position);
3332 *typography = (IDWriteTypography*)range->iface;
3333 if (*typography)
3334 IDWriteTypography_AddRef(*typography);
3336 return return_range(&range->h, r);
3339 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout3 *iface,
3340 UINT32 position, UINT32* length, DWRITE_TEXT_RANGE *r)
3342 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3343 TRACE("(%p)->(%u %p %p)\n", This, position, length, r);
3344 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_LOCALE, position, length, r);
3347 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout3 *iface,
3348 UINT32 position, WCHAR* locale, UINT32 length, DWRITE_TEXT_RANGE *r)
3350 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3351 TRACE("(%p)->(%u %p %u %p)\n", This, position, locale, length, r);
3352 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_LOCALE, position, locale, length, r);
3355 static inline FLOAT renderer_apply_snapping(FLOAT coord, BOOL skiptransform, FLOAT ppdip, FLOAT det,
3356 const DWRITE_MATRIX *m)
3358 D2D1_POINT_2F vec, vec2;
3360 if (!skiptransform) {
3361 /* apply transform */
3362 vec.x = 0.0f;
3363 vec.y = coord * ppdip;
3365 vec2.x = m->m11 * vec.x + m->m21 * vec.y + m->dx;
3366 vec2.y = m->m12 * vec.x + m->m22 * vec.y + m->dy;
3368 /* snap */
3369 vec2.x = floorf(vec2.x + 0.5f);
3370 vec2.y = floorf(vec2.y + 0.5f);
3372 /* apply inverted transform, we don't care about X component at this point */
3373 vec.y = (-m->m12 * vec2.x + m->m11 * vec2.y - (m->m11 * m->dy - m->m12 * m->dx)) / det;
3374 vec.y /= ppdip;
3376 else
3377 vec.y = floorf(coord * ppdip + 0.5f) / ppdip;
3379 return vec.y;
3382 static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout3 *iface,
3383 void *context, IDWriteTextRenderer* renderer, FLOAT origin_x, FLOAT origin_y)
3385 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3386 BOOL disabled = FALSE, skiptransform = FALSE;
3387 struct layout_effective_inline *inlineobject;
3388 struct layout_effective_run *run;
3389 struct layout_strikethrough *s;
3390 struct layout_underline *u;
3391 FLOAT det = 0.0f, ppdip = 0.0f;
3392 DWRITE_MATRIX m = { 0 };
3393 HRESULT hr;
3395 TRACE("(%p)->(%p %p %.2f %.2f)\n", This, context, renderer, origin_x, origin_y);
3397 hr = layout_compute_effective_runs(This);
3398 if (FAILED(hr))
3399 return hr;
3401 hr = IDWriteTextRenderer_IsPixelSnappingDisabled(renderer, context, &disabled);
3402 if (FAILED(hr))
3403 return hr;
3405 if (!disabled) {
3406 hr = IDWriteTextRenderer_GetPixelsPerDip(renderer, context, &ppdip);
3407 if (FAILED(hr))
3408 return hr;
3410 hr = IDWriteTextRenderer_GetCurrentTransform(renderer, context, &m);
3411 if (FAILED(hr))
3412 return hr;
3414 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
3415 if (ppdip <= 0.0f ||
3416 (m.m11 * m.m22 != 0.0f && (m.m12 != 0.0f || m.m21 != 0.0f)) ||
3417 (m.m12 * m.m21 != 0.0f && (m.m11 != 0.0f || m.m22 != 0.0f)))
3418 disabled = TRUE;
3419 else
3420 skiptransform = should_skip_transform(&m, &det);
3423 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
3424 /* 1. Regular runs */
3425 LIST_FOR_EACH_ENTRY(run, &This->eruns, struct layout_effective_run, entry) {
3426 const struct regular_layout_run *regular = &run->run->u.regular;
3427 UINT32 start_glyph = regular->clustermap[run->start];
3428 DWRITE_GLYPH_RUN_DESCRIPTION descr;
3429 DWRITE_GLYPH_RUN glyph_run;
3431 /* Everything but cluster map will be reused from nominal run, as we only need
3432 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
3433 it can't be reused because it has to start with 0 index for each reported run. */
3434 glyph_run = regular->run;
3435 glyph_run.glyphCount = run->glyphcount;
3437 /* fixup glyph data arrays */
3438 glyph_run.glyphIndices += start_glyph;
3439 glyph_run.glyphAdvances += start_glyph;
3440 glyph_run.glyphOffsets += start_glyph;
3442 /* description */
3443 descr = regular->descr;
3444 descr.stringLength = run->length;
3445 descr.string += run->start;
3446 descr.clusterMap = run->clustermap;
3447 descr.textPosition += run->start;
3449 /* return value is ignored */
3450 IDWriteTextRenderer_DrawGlyphRun(renderer,
3451 context,
3452 run->origin.x + run->align_dx + origin_x,
3453 SNAP_COORD(run->origin.y + origin_y),
3454 This->measuringmode,
3455 &glyph_run,
3456 &descr,
3457 run->effect);
3460 /* 2. Inline objects */
3461 LIST_FOR_EACH_ENTRY(inlineobject, &This->inlineobjects, struct layout_effective_inline, entry) {
3462 IDWriteTextRenderer_DrawInlineObject(renderer,
3463 context,
3464 inlineobject->origin.x + inlineobject->align_dx + origin_x,
3465 SNAP_COORD(inlineobject->origin.y + origin_y),
3466 inlineobject->object,
3467 inlineobject->is_sideways,
3468 inlineobject->is_rtl,
3469 inlineobject->effect);
3472 /* 3. Underlines */
3473 LIST_FOR_EACH_ENTRY(u, &This->underlines, struct layout_underline, entry) {
3474 IDWriteTextRenderer_DrawUnderline(renderer,
3475 context,
3476 /* horizontal underline always grows from left to right, width is always added to origin regardless of run direction */
3477 (is_run_rtl(u->run) ? u->run->origin.x - u->run->width : u->run->origin.x) + u->run->align_dx + origin_x,
3478 SNAP_COORD(u->run->origin.y + origin_y),
3479 &u->u,
3480 u->run->effect);
3483 /* 4. Strikethrough */
3484 LIST_FOR_EACH_ENTRY(s, &This->strikethrough, struct layout_strikethrough, entry) {
3485 IDWriteTextRenderer_DrawStrikethrough(renderer,
3486 context,
3487 s->run->origin.x + s->run->align_dx + origin_x,
3488 SNAP_COORD(s->run->origin.y + origin_y),
3489 &s->s,
3490 s->run->effect);
3492 #undef SNAP_COORD
3494 return S_OK;
3497 static HRESULT WINAPI dwritetextlayout_GetLineMetrics(IDWriteTextLayout3 *iface,
3498 DWRITE_LINE_METRICS *metrics, UINT32 max_count, UINT32 *count)
3500 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3501 HRESULT hr;
3503 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
3505 hr = layout_compute_effective_runs(This);
3506 if (FAILED(hr))
3507 return hr;
3509 if (metrics) {
3510 UINT32 i, c = min(max_count, This->metrics.lineCount);
3511 for (i = 0; i < c; i++)
3512 memcpy(metrics + i, This->linemetrics + i, sizeof(*metrics));
3515 *count = This->metrics.lineCount;
3516 return max_count >= This->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3519 static HRESULT WINAPI dwritetextlayout_GetMetrics(IDWriteTextLayout3 *iface, DWRITE_TEXT_METRICS *metrics)
3521 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3522 DWRITE_TEXT_METRICS1 metrics1;
3523 HRESULT hr;
3525 TRACE("(%p)->(%p)\n", This, metrics);
3527 hr = IDWriteTextLayout3_GetMetrics(iface, &metrics1);
3528 if (hr == S_OK)
3529 memcpy(metrics, &metrics1, sizeof(*metrics));
3531 return hr;
3534 static void scale_glyph_bbox(RECT *bbox, FLOAT emSize, UINT16 units_per_em, D2D1_RECT_F *ret)
3536 #define SCALE(x) ((FLOAT)x * emSize / (FLOAT)units_per_em)
3537 ret->left = SCALE(bbox->left);
3538 ret->right = SCALE(bbox->right);
3539 ret->top = SCALE(bbox->top);
3540 ret->bottom = SCALE(bbox->bottom);
3541 #undef SCALE
3544 static void d2d_rect_offset(D2D1_RECT_F *rect, FLOAT x, FLOAT y)
3546 rect->left += x;
3547 rect->right += x;
3548 rect->top += y;
3549 rect->bottom += y;
3552 static BOOL d2d_rect_is_empty(const D2D1_RECT_F *rect)
3554 return ((rect->left >= rect->right) || (rect->top >= rect->bottom));
3557 static void d2d_rect_union(D2D1_RECT_F *dst, const D2D1_RECT_F *src)
3559 if (d2d_rect_is_empty(dst)) {
3560 if (d2d_rect_is_empty(src)) {
3561 dst->left = dst->right = dst->top = dst->bottom = 0.0f;
3562 return;
3564 else
3565 *dst = *src;
3567 else {
3568 if (!d2d_rect_is_empty(src)) {
3569 dst->left = min(dst->left, src->left);
3570 dst->right = max(dst->right, src->right);
3571 dst->top = min(dst->top, src->top);
3572 dst->bottom = max(dst->bottom, src->bottom);
3577 static void layout_get_erun_bbox(struct dwrite_textlayout *layout, struct layout_effective_run *run, D2D1_RECT_F *bbox)
3579 const struct regular_layout_run *regular = &run->run->u.regular;
3580 UINT32 start_glyph = regular->clustermap[run->start];
3581 const DWRITE_GLYPH_RUN *glyph_run = &regular->run;
3582 DWRITE_FONT_METRICS font_metrics;
3583 D2D1_POINT_2F origin = { 0 };
3584 UINT32 i;
3586 if (run->bbox.top == run->bbox.bottom) {
3587 IDWriteFontFace_GetMetrics(glyph_run->fontFace, &font_metrics);
3589 for (i = 0; i < run->glyphcount; i++) {
3590 D2D1_RECT_F glyph_bbox;
3591 RECT design_bbox;
3593 freetype_get_design_glyph_bbox((IDWriteFontFace4 *)glyph_run->fontFace, font_metrics.designUnitsPerEm,
3594 glyph_run->glyphIndices[i + start_glyph], &design_bbox);
3596 scale_glyph_bbox(&design_bbox, glyph_run->fontEmSize, font_metrics.designUnitsPerEm, &glyph_bbox);
3597 d2d_rect_offset(&glyph_bbox, origin.x + glyph_run->glyphOffsets[i + start_glyph].advanceOffset,
3598 origin.y + glyph_run->glyphOffsets[i + start_glyph].ascenderOffset);
3599 d2d_rect_union(&run->bbox, &glyph_bbox);
3601 /* FIXME: take care of vertical/rtl */
3602 origin.x += glyph_run->glyphAdvances[i + start_glyph];
3606 *bbox = run->bbox;
3607 d2d_rect_offset(bbox, run->origin.x + run->align_dx, run->origin.y);
3610 static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout3 *iface,
3611 DWRITE_OVERHANG_METRICS *overhangs)
3613 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3614 struct layout_effective_run *run;
3615 D2D1_RECT_F bbox = { 0 };
3616 HRESULT hr;
3618 TRACE("(%p)->(%p)\n", This, overhangs);
3620 memset(overhangs, 0, sizeof(*overhangs));
3622 if (!(This->recompute & RECOMPUTE_OVERHANGS)) {
3623 *overhangs = This->overhangs;
3624 return S_OK;
3627 hr = layout_compute_effective_runs(This);
3628 if (FAILED(hr))
3629 return hr;
3631 LIST_FOR_EACH_ENTRY(run, &This->eruns, struct layout_effective_run, entry) {
3632 D2D1_RECT_F run_bbox;
3634 layout_get_erun_bbox(This, run, &run_bbox);
3635 d2d_rect_union(&bbox, &run_bbox);
3638 /* FIXME: iterate over inline objects too */
3640 /* deltas from text content metrics */
3641 This->overhangs.left = -bbox.left;
3642 This->overhangs.top = -bbox.top;
3643 This->overhangs.right = bbox.right - This->metrics.layoutWidth;
3644 This->overhangs.bottom = bbox.bottom - This->metrics.layoutHeight;
3645 This->recompute &= ~RECOMPUTE_OVERHANGS;
3647 *overhangs = This->overhangs;
3649 return S_OK;
3652 static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout3 *iface,
3653 DWRITE_CLUSTER_METRICS *metrics, UINT32 max_count, UINT32 *count)
3655 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3656 HRESULT hr;
3658 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
3660 hr = layout_compute(This);
3661 if (FAILED(hr))
3662 return hr;
3664 if (metrics)
3665 memcpy(metrics, This->clustermetrics, sizeof(DWRITE_CLUSTER_METRICS)*min(max_count, This->cluster_count));
3667 *count = This->cluster_count;
3668 return max_count >= This->cluster_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3671 static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout3 *iface, FLOAT* min_width)
3673 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3674 UINT32 start;
3675 FLOAT width;
3676 HRESULT hr;
3678 TRACE("(%p)->(%p)\n", This, min_width);
3680 if (!min_width)
3681 return E_INVALIDARG;
3683 if (!(This->recompute & RECOMPUTE_MINIMAL_WIDTH))
3684 goto width_done;
3686 *min_width = 0.0f;
3687 hr = layout_compute(This);
3688 if (FAILED(hr))
3689 return hr;
3691 /* Find widest word without emergency breaking between clusters, trailing whitespaces
3692 preceding breaking point do not contribute to word width. */
3693 for (start = 0; start < This->cluster_count;) {
3694 UINT32 end = start, j, next;
3696 /* Last cluster always could be wrapped after. */
3697 while (!This->clustermetrics[end].canWrapLineAfter)
3698 end++;
3699 /* make is so current cluster range that we can wrap after is [start,end) */
3700 end++;
3702 next = end;
3704 /* Ignore trailing whitespace clusters, in case of single space range will
3705 be reduced to empty range, or [start,start+1). */
3706 while (end > start && This->clustermetrics[end-1].isWhitespace)
3707 end--;
3709 /* check if cluster range exceeds last minimal width */
3710 width = 0.0f;
3711 for (j = start; j < end; j++)
3712 width += This->clustermetrics[j].width;
3714 start = next;
3716 if (width > This->minwidth)
3717 This->minwidth = width;
3719 This->recompute &= ~RECOMPUTE_MINIMAL_WIDTH;
3721 width_done:
3722 *min_width = This->minwidth;
3723 return S_OK;
3726 static HRESULT WINAPI dwritetextlayout_HitTestPoint(IDWriteTextLayout3 *iface,
3727 FLOAT pointX, FLOAT pointY, BOOL* is_trailinghit, BOOL* is_inside, DWRITE_HIT_TEST_METRICS *metrics)
3729 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3730 FIXME("(%p)->(%f %f %p %p %p): stub\n", This, pointX, pointY, is_trailinghit, is_inside, metrics);
3731 return E_NOTIMPL;
3734 static HRESULT WINAPI dwritetextlayout_HitTestTextPosition(IDWriteTextLayout3 *iface,
3735 UINT32 textPosition, BOOL is_trailinghit, FLOAT* pointX, FLOAT* pointY, DWRITE_HIT_TEST_METRICS *metrics)
3737 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3738 FIXME("(%p)->(%u %d %p %p %p): stub\n", This, textPosition, is_trailinghit, pointX, pointY, metrics);
3739 return E_NOTIMPL;
3742 static HRESULT WINAPI dwritetextlayout_HitTestTextRange(IDWriteTextLayout3 *iface,
3743 UINT32 textPosition, UINT32 textLength, FLOAT originX, FLOAT originY,
3744 DWRITE_HIT_TEST_METRICS *metrics, UINT32 max_metricscount, UINT32* actual_metricscount)
3746 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3747 FIXME("(%p)->(%u %u %f %f %p %u %p): stub\n", This, textPosition, textLength, originX, originY, metrics,
3748 max_metricscount, actual_metricscount);
3749 return E_NOTIMPL;
3752 static HRESULT WINAPI dwritetextlayout1_SetPairKerning(IDWriteTextLayout3 *iface, BOOL is_pairkerning_enabled,
3753 DWRITE_TEXT_RANGE range)
3755 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3756 struct layout_range_attr_value value;
3758 TRACE("(%p)->(%d %s)\n", This, is_pairkerning_enabled, debugstr_range(&range));
3760 value.range = range;
3761 value.u.pair_kerning = !!is_pairkerning_enabled;
3762 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_PAIR_KERNING, &value);
3765 static HRESULT WINAPI dwritetextlayout1_GetPairKerning(IDWriteTextLayout3 *iface, UINT32 position, BOOL *is_pairkerning_enabled,
3766 DWRITE_TEXT_RANGE *r)
3768 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3769 struct layout_range *range;
3771 TRACE("(%p)->(%u %p %p)\n", This, position, is_pairkerning_enabled, r);
3773 if (position >= This->len)
3774 return S_OK;
3776 range = get_layout_range_by_pos(This, position);
3777 *is_pairkerning_enabled = range->pair_kerning;
3779 return return_range(&range->h, r);
3782 static HRESULT WINAPI dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout3 *iface, FLOAT leading, FLOAT trailing,
3783 FLOAT min_advance, DWRITE_TEXT_RANGE range)
3785 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3786 struct layout_range_attr_value value;
3788 TRACE("(%p)->(%.2f %.2f %.2f %s)\n", This, leading, trailing, min_advance, debugstr_range(&range));
3790 if (min_advance < 0.0f)
3791 return E_INVALIDARG;
3793 value.range = range;
3794 value.u.spacing[0] = leading;
3795 value.u.spacing[1] = trailing;
3796 value.u.spacing[2] = min_advance;
3797 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_SPACING, &value);
3800 static HRESULT WINAPI dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout3 *iface, UINT32 position, FLOAT *leading,
3801 FLOAT *trailing, FLOAT *min_advance, DWRITE_TEXT_RANGE *r)
3803 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3804 struct layout_range_spacing *range;
3806 TRACE("(%p)->(%u %p %p %p %p)\n", This, position, leading, trailing, min_advance, r);
3808 range = (struct layout_range_spacing*)get_layout_range_header_by_pos(&This->spacing, position);
3809 *leading = range->leading;
3810 *trailing = range->trailing;
3811 *min_advance = range->min_advance;
3813 return return_range(&range->h, r);
3816 static HRESULT WINAPI dwritetextlayout2_GetMetrics(IDWriteTextLayout3 *iface, DWRITE_TEXT_METRICS1 *metrics)
3818 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3819 HRESULT hr;
3821 TRACE("(%p)->(%p)\n", This, metrics);
3823 hr = layout_compute_effective_runs(This);
3824 if (FAILED(hr))
3825 return hr;
3827 *metrics = This->metrics;
3828 return S_OK;
3831 static HRESULT WINAPI dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout3 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
3833 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3835 TRACE("(%p)->(%d)\n", This, orientation);
3837 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
3838 return E_INVALIDARG;
3840 This->format.vertical_orientation = orientation;
3841 return S_OK;
3844 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout3 *iface)
3846 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3847 TRACE("(%p)\n", This);
3848 return This->format.vertical_orientation;
3851 static HRESULT WINAPI dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout3 *iface, BOOL lastline_wrapping_enabled)
3853 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3854 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
3855 return IDWriteTextFormat1_SetLastLineWrapping(&This->IDWriteTextFormat1_iface, lastline_wrapping_enabled);
3858 static BOOL WINAPI dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout3 *iface)
3860 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3861 TRACE("(%p)\n", This);
3862 return IDWriteTextFormat1_GetLastLineWrapping(&This->IDWriteTextFormat1_iface);
3865 static HRESULT WINAPI dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout3 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
3867 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3868 TRACE("(%p)->(%d)\n", This, alignment);
3869 return IDWriteTextFormat1_SetOpticalAlignment(&This->IDWriteTextFormat1_iface, alignment);
3872 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout3 *iface)
3874 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3875 TRACE("(%p)\n", This);
3876 return IDWriteTextFormat1_GetOpticalAlignment(&This->IDWriteTextFormat1_iface);
3879 static HRESULT WINAPI dwritetextlayout2_SetFontFallback(IDWriteTextLayout3 *iface, IDWriteFontFallback *fallback)
3881 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3882 TRACE("(%p)->(%p)\n", This, fallback);
3883 return set_fontfallback_for_format(&This->format, fallback);
3886 static HRESULT WINAPI dwritetextlayout2_GetFontFallback(IDWriteTextLayout3 *iface, IDWriteFontFallback **fallback)
3888 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3889 TRACE("(%p)->(%p)\n", This, fallback);
3890 return get_fontfallback_from_format(&This->format, fallback);
3893 static HRESULT WINAPI dwritetextlayout3_InvalidateLayout(IDWriteTextLayout3 *iface)
3895 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3897 TRACE("(%p)\n", This);
3899 This->recompute = RECOMPUTE_EVERYTHING;
3900 return S_OK;
3903 static HRESULT WINAPI dwritetextlayout3_SetLineSpacing(IDWriteTextLayout3 *iface, DWRITE_LINE_SPACING const *spacing)
3905 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3906 BOOL changed;
3907 HRESULT hr;
3909 TRACE("(%p)->(%p)\n", This, spacing);
3911 hr = format_set_linespacing(&This->format, spacing, &changed);
3912 if (FAILED(hr))
3913 return hr;
3915 if (changed) {
3916 if (!(This->recompute & RECOMPUTE_LINES)) {
3917 UINT32 line;
3919 switch (This->format.spacing.method)
3921 case DWRITE_LINE_SPACING_METHOD_DEFAULT:
3922 for (line = 0; line < This->metrics.lineCount; line++) {
3923 This->linemetrics[line].height = This->lines[line].height;
3924 This->linemetrics[line].baseline = This->lines[line].baseline;
3926 break;
3927 case DWRITE_LINE_SPACING_METHOD_UNIFORM:
3928 for (line = 0; line < This->metrics.lineCount; line++) {
3929 This->linemetrics[line].height = This->format.spacing.height;
3930 This->linemetrics[line].baseline = This->format.spacing.baseline;
3932 break;
3933 case DWRITE_LINE_SPACING_METHOD_PROPORTIONAL:
3934 for (line = 0; line < This->metrics.lineCount; line++) {
3935 This->linemetrics[line].height = This->format.spacing.height * This->lines[line].height;
3936 This->linemetrics[line].baseline = This->format.spacing.baseline * This->lines[line].baseline;
3938 break;
3939 default:
3943 layout_set_line_positions(This);
3946 This->recompute |= RECOMPUTE_OVERHANGS;
3949 return S_OK;
3952 static HRESULT WINAPI dwritetextlayout3_GetLineSpacing(IDWriteTextLayout3 *iface, DWRITE_LINE_SPACING *spacing)
3954 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3956 TRACE("(%p)->(%p)\n", This, spacing);
3958 *spacing = This->format.spacing;
3959 return S_OK;
3962 static HRESULT WINAPI dwritetextlayout3_GetLineMetrics(IDWriteTextLayout3 *iface, DWRITE_LINE_METRICS1 *metrics,
3963 UINT32 max_count, UINT32 *count)
3965 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3966 HRESULT hr;
3968 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
3970 hr = layout_compute_effective_runs(This);
3971 if (FAILED(hr))
3972 return hr;
3974 if (metrics)
3975 memcpy(metrics, This->linemetrics, sizeof(*metrics) * min(max_count, This->metrics.lineCount));
3977 *count = This->metrics.lineCount;
3978 return max_count >= This->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3981 static const IDWriteTextLayout3Vtbl dwritetextlayoutvtbl = {
3982 dwritetextlayout_QueryInterface,
3983 dwritetextlayout_AddRef,
3984 dwritetextlayout_Release,
3985 dwritetextlayout_SetTextAlignment,
3986 dwritetextlayout_SetParagraphAlignment,
3987 dwritetextlayout_SetWordWrapping,
3988 dwritetextlayout_SetReadingDirection,
3989 dwritetextlayout_SetFlowDirection,
3990 dwritetextlayout_SetIncrementalTabStop,
3991 dwritetextlayout_SetTrimming,
3992 dwritetextlayout_SetLineSpacing,
3993 dwritetextlayout_GetTextAlignment,
3994 dwritetextlayout_GetParagraphAlignment,
3995 dwritetextlayout_GetWordWrapping,
3996 dwritetextlayout_GetReadingDirection,
3997 dwritetextlayout_GetFlowDirection,
3998 dwritetextlayout_GetIncrementalTabStop,
3999 dwritetextlayout_GetTrimming,
4000 dwritetextlayout_GetLineSpacing,
4001 dwritetextlayout_GetFontCollection,
4002 dwritetextlayout_GetFontFamilyNameLength,
4003 dwritetextlayout_GetFontFamilyName,
4004 dwritetextlayout_GetFontWeight,
4005 dwritetextlayout_GetFontStyle,
4006 dwritetextlayout_GetFontStretch,
4007 dwritetextlayout_GetFontSize,
4008 dwritetextlayout_GetLocaleNameLength,
4009 dwritetextlayout_GetLocaleName,
4010 dwritetextlayout_SetMaxWidth,
4011 dwritetextlayout_SetMaxHeight,
4012 dwritetextlayout_SetFontCollection,
4013 dwritetextlayout_SetFontFamilyName,
4014 dwritetextlayout_SetFontWeight,
4015 dwritetextlayout_SetFontStyle,
4016 dwritetextlayout_SetFontStretch,
4017 dwritetextlayout_SetFontSize,
4018 dwritetextlayout_SetUnderline,
4019 dwritetextlayout_SetStrikethrough,
4020 dwritetextlayout_SetDrawingEffect,
4021 dwritetextlayout_SetInlineObject,
4022 dwritetextlayout_SetTypography,
4023 dwritetextlayout_SetLocaleName,
4024 dwritetextlayout_GetMaxWidth,
4025 dwritetextlayout_GetMaxHeight,
4026 dwritetextlayout_layout_GetFontCollection,
4027 dwritetextlayout_layout_GetFontFamilyNameLength,
4028 dwritetextlayout_layout_GetFontFamilyName,
4029 dwritetextlayout_layout_GetFontWeight,
4030 dwritetextlayout_layout_GetFontStyle,
4031 dwritetextlayout_layout_GetFontStretch,
4032 dwritetextlayout_layout_GetFontSize,
4033 dwritetextlayout_GetUnderline,
4034 dwritetextlayout_GetStrikethrough,
4035 dwritetextlayout_GetDrawingEffect,
4036 dwritetextlayout_GetInlineObject,
4037 dwritetextlayout_GetTypography,
4038 dwritetextlayout_layout_GetLocaleNameLength,
4039 dwritetextlayout_layout_GetLocaleName,
4040 dwritetextlayout_Draw,
4041 dwritetextlayout_GetLineMetrics,
4042 dwritetextlayout_GetMetrics,
4043 dwritetextlayout_GetOverhangMetrics,
4044 dwritetextlayout_GetClusterMetrics,
4045 dwritetextlayout_DetermineMinWidth,
4046 dwritetextlayout_HitTestPoint,
4047 dwritetextlayout_HitTestTextPosition,
4048 dwritetextlayout_HitTestTextRange,
4049 dwritetextlayout1_SetPairKerning,
4050 dwritetextlayout1_GetPairKerning,
4051 dwritetextlayout1_SetCharacterSpacing,
4052 dwritetextlayout1_GetCharacterSpacing,
4053 dwritetextlayout2_GetMetrics,
4054 dwritetextlayout2_SetVerticalGlyphOrientation,
4055 dwritetextlayout2_GetVerticalGlyphOrientation,
4056 dwritetextlayout2_SetLastLineWrapping,
4057 dwritetextlayout2_GetLastLineWrapping,
4058 dwritetextlayout2_SetOpticalAlignment,
4059 dwritetextlayout2_GetOpticalAlignment,
4060 dwritetextlayout2_SetFontFallback,
4061 dwritetextlayout2_GetFontFallback,
4062 dwritetextlayout3_InvalidateLayout,
4063 dwritetextlayout3_SetLineSpacing,
4064 dwritetextlayout3_GetLineSpacing,
4065 dwritetextlayout3_GetLineMetrics
4068 static HRESULT WINAPI dwritetextformat_layout_QueryInterface(IDWriteTextFormat1 *iface, REFIID riid, void **obj)
4070 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4071 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4072 return IDWriteTextLayout3_QueryInterface(&This->IDWriteTextLayout3_iface, riid, obj);
4075 static ULONG WINAPI dwritetextformat_layout_AddRef(IDWriteTextFormat1 *iface)
4077 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4078 return IDWriteTextLayout3_AddRef(&This->IDWriteTextLayout3_iface);
4081 static ULONG WINAPI dwritetextformat_layout_Release(IDWriteTextFormat1 *iface)
4083 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4084 return IDWriteTextLayout3_Release(&This->IDWriteTextLayout3_iface);
4087 static HRESULT WINAPI dwritetextformat_layout_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
4089 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4090 BOOL changed;
4091 HRESULT hr;
4093 TRACE("(%p)->(%d)\n", This, alignment);
4095 hr = format_set_textalignment(&This->format, alignment, &changed);
4096 if (FAILED(hr))
4097 return hr;
4099 if (changed) {
4100 /* if layout is not ready there's nothing to align */
4101 if (!(This->recompute & RECOMPUTE_LINES))
4102 layout_apply_text_alignment(This);
4103 This->recompute |= RECOMPUTE_OVERHANGS;
4106 return S_OK;
4109 static HRESULT WINAPI dwritetextformat_layout_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
4111 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4112 BOOL changed;
4113 HRESULT hr;
4115 TRACE("(%p)->(%d)\n", This, alignment);
4117 hr = format_set_paralignment(&This->format, alignment, &changed);
4118 if (FAILED(hr))
4119 return hr;
4121 if (changed) {
4122 /* if layout is not ready there's nothing to align */
4123 if (!(This->recompute & RECOMPUTE_LINES))
4124 layout_apply_par_alignment(This);
4125 This->recompute |= RECOMPUTE_OVERHANGS;
4128 return S_OK;
4131 static HRESULT WINAPI dwritetextformat_layout_SetWordWrapping(IDWriteTextFormat1 *iface, DWRITE_WORD_WRAPPING wrapping)
4133 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4134 BOOL changed;
4135 HRESULT hr;
4137 TRACE("(%p)->(%d)\n", This, wrapping);
4139 hr = format_set_wordwrapping(&This->format, wrapping, &changed);
4140 if (FAILED(hr))
4141 return hr;
4143 if (changed)
4144 This->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
4146 return S_OK;
4149 static HRESULT WINAPI dwritetextformat_layout_SetReadingDirection(IDWriteTextFormat1 *iface, DWRITE_READING_DIRECTION direction)
4151 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4152 BOOL changed;
4153 HRESULT hr;
4155 TRACE("(%p)->(%d)\n", This, direction);
4157 hr = format_set_readingdirection(&This->format, direction, &changed);
4158 if (FAILED(hr))
4159 return hr;
4161 if (changed)
4162 This->recompute = RECOMPUTE_EVERYTHING;
4164 return S_OK;
4167 static HRESULT WINAPI dwritetextformat_layout_SetFlowDirection(IDWriteTextFormat1 *iface, DWRITE_FLOW_DIRECTION direction)
4169 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4170 BOOL changed;
4171 HRESULT hr;
4173 TRACE("(%p)->(%d)\n", This, direction);
4175 hr = format_set_flowdirection(&This->format, direction, &changed);
4176 if (FAILED(hr))
4177 return hr;
4179 if (changed)
4180 This->recompute = RECOMPUTE_EVERYTHING;
4182 return S_OK;
4185 static HRESULT WINAPI dwritetextformat_layout_SetIncrementalTabStop(IDWriteTextFormat1 *iface, FLOAT tabstop)
4187 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4188 FIXME("(%p)->(%f): stub\n", This, tabstop);
4189 return E_NOTIMPL;
4192 static HRESULT WINAPI dwritetextformat_layout_SetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING const *trimming,
4193 IDWriteInlineObject *trimming_sign)
4195 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4196 BOOL changed;
4197 HRESULT hr;
4199 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
4201 hr = format_set_trimming(&This->format, trimming, trimming_sign, &changed);
4203 if (changed)
4204 This->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
4206 return hr;
4209 static HRESULT WINAPI dwritetextformat_layout_SetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD method,
4210 FLOAT height, FLOAT baseline)
4212 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4213 DWRITE_LINE_SPACING spacing;
4215 TRACE("(%p)->(%d %f %f)\n", This, method, height, baseline);
4217 spacing = This->format.spacing;
4218 spacing.method = method;
4219 spacing.height = height;
4220 spacing.baseline = baseline;
4221 return IDWriteTextLayout3_SetLineSpacing(&This->IDWriteTextLayout3_iface, &spacing);
4224 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_layout_GetTextAlignment(IDWriteTextFormat1 *iface)
4226 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4227 TRACE("(%p)\n", This);
4228 return This->format.textalignment;
4231 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_layout_GetParagraphAlignment(IDWriteTextFormat1 *iface)
4233 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4234 TRACE("(%p)\n", This);
4235 return This->format.paralign;
4238 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_layout_GetWordWrapping(IDWriteTextFormat1 *iface)
4240 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4241 TRACE("(%p)\n", This);
4242 return This->format.wrapping;
4245 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_layout_GetReadingDirection(IDWriteTextFormat1 *iface)
4247 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4248 TRACE("(%p)\n", This);
4249 return This->format.readingdir;
4252 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_layout_GetFlowDirection(IDWriteTextFormat1 *iface)
4254 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4255 TRACE("(%p)\n", This);
4256 return This->format.flow;
4259 static FLOAT WINAPI dwritetextformat_layout_GetIncrementalTabStop(IDWriteTextFormat1 *iface)
4261 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4262 FIXME("(%p): stub\n", This);
4263 return 0.0f;
4266 static HRESULT WINAPI dwritetextformat_layout_GetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING *options,
4267 IDWriteInlineObject **trimming_sign)
4269 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4271 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
4273 *options = This->format.trimming;
4274 *trimming_sign = This->format.trimmingsign;
4275 if (*trimming_sign)
4276 IDWriteInlineObject_AddRef(*trimming_sign);
4277 return S_OK;
4280 static HRESULT WINAPI dwritetextformat_layout_GetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD *method,
4281 FLOAT *spacing, FLOAT *baseline)
4283 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4285 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
4287 *method = This->format.spacing.method;
4288 *spacing = This->format.spacing.height;
4289 *baseline = This->format.spacing.baseline;
4290 return S_OK;
4293 static HRESULT WINAPI dwritetextformat_layout_GetFontCollection(IDWriteTextFormat1 *iface, IDWriteFontCollection **collection)
4295 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4297 TRACE("(%p)->(%p)\n", This, collection);
4299 *collection = This->format.collection;
4300 if (*collection)
4301 IDWriteFontCollection_AddRef(*collection);
4302 return S_OK;
4305 static UINT32 WINAPI dwritetextformat_layout_GetFontFamilyNameLength(IDWriteTextFormat1 *iface)
4307 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4308 TRACE("(%p)\n", This);
4309 return This->format.family_len;
4312 static HRESULT WINAPI dwritetextformat_layout_GetFontFamilyName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
4314 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4316 TRACE("(%p)->(%p %u)\n", This, name, size);
4318 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
4319 strcpyW(name, This->format.family_name);
4320 return S_OK;
4323 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_layout_GetFontWeight(IDWriteTextFormat1 *iface)
4325 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4326 TRACE("(%p)\n", This);
4327 return This->format.weight;
4330 static DWRITE_FONT_STYLE WINAPI dwritetextformat_layout_GetFontStyle(IDWriteTextFormat1 *iface)
4332 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4333 TRACE("(%p)\n", This);
4334 return This->format.style;
4337 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_layout_GetFontStretch(IDWriteTextFormat1 *iface)
4339 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4340 TRACE("(%p)\n", This);
4341 return This->format.stretch;
4344 static FLOAT WINAPI dwritetextformat_layout_GetFontSize(IDWriteTextFormat1 *iface)
4346 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4347 TRACE("(%p)\n", This);
4348 return This->format.fontsize;
4351 static UINT32 WINAPI dwritetextformat_layout_GetLocaleNameLength(IDWriteTextFormat1 *iface)
4353 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4354 TRACE("(%p)\n", This);
4355 return This->format.locale_len;
4358 static HRESULT WINAPI dwritetextformat_layout_GetLocaleName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
4360 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4362 TRACE("(%p)->(%p %u)\n", This, name, size);
4364 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
4365 strcpyW(name, This->format.locale);
4366 return S_OK;
4369 static HRESULT WINAPI dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat1 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4371 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4372 FIXME("(%p)->(%d): stub\n", This, orientation);
4373 return E_NOTIMPL;
4376 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat1 *iface)
4378 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4379 FIXME("(%p): stub\n", This);
4380 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
4383 static HRESULT WINAPI dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat1 *iface, BOOL lastline_wrapping_enabled)
4385 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4387 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
4389 This->format.last_line_wrapping = !!lastline_wrapping_enabled;
4390 return S_OK;
4393 static BOOL WINAPI dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat1 *iface)
4395 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4396 TRACE("(%p)\n", This);
4397 return This->format.last_line_wrapping;
4400 static HRESULT WINAPI dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat1 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
4402 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4403 TRACE("(%p)->(%d)\n", This, alignment);
4404 return format_set_optical_alignment(&This->format, alignment);
4407 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat1 *iface)
4409 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4410 TRACE("(%p)\n", This);
4411 return This->format.optical_alignment;
4414 static HRESULT WINAPI dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback *fallback)
4416 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4417 TRACE("(%p)->(%p)\n", This, fallback);
4418 return IDWriteTextLayout3_SetFontFallback(&This->IDWriteTextLayout3_iface, fallback);
4421 static HRESULT WINAPI dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback **fallback)
4423 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4424 TRACE("(%p)->(%p)\n", This, fallback);
4425 return IDWriteTextLayout3_GetFontFallback(&This->IDWriteTextLayout3_iface, fallback);
4428 static const IDWriteTextFormat1Vtbl dwritetextformat1_layout_vtbl = {
4429 dwritetextformat_layout_QueryInterface,
4430 dwritetextformat_layout_AddRef,
4431 dwritetextformat_layout_Release,
4432 dwritetextformat_layout_SetTextAlignment,
4433 dwritetextformat_layout_SetParagraphAlignment,
4434 dwritetextformat_layout_SetWordWrapping,
4435 dwritetextformat_layout_SetReadingDirection,
4436 dwritetextformat_layout_SetFlowDirection,
4437 dwritetextformat_layout_SetIncrementalTabStop,
4438 dwritetextformat_layout_SetTrimming,
4439 dwritetextformat_layout_SetLineSpacing,
4440 dwritetextformat_layout_GetTextAlignment,
4441 dwritetextformat_layout_GetParagraphAlignment,
4442 dwritetextformat_layout_GetWordWrapping,
4443 dwritetextformat_layout_GetReadingDirection,
4444 dwritetextformat_layout_GetFlowDirection,
4445 dwritetextformat_layout_GetIncrementalTabStop,
4446 dwritetextformat_layout_GetTrimming,
4447 dwritetextformat_layout_GetLineSpacing,
4448 dwritetextformat_layout_GetFontCollection,
4449 dwritetextformat_layout_GetFontFamilyNameLength,
4450 dwritetextformat_layout_GetFontFamilyName,
4451 dwritetextformat_layout_GetFontWeight,
4452 dwritetextformat_layout_GetFontStyle,
4453 dwritetextformat_layout_GetFontStretch,
4454 dwritetextformat_layout_GetFontSize,
4455 dwritetextformat_layout_GetLocaleNameLength,
4456 dwritetextformat_layout_GetLocaleName,
4457 dwritetextformat1_layout_SetVerticalGlyphOrientation,
4458 dwritetextformat1_layout_GetVerticalGlyphOrientation,
4459 dwritetextformat1_layout_SetLastLineWrapping,
4460 dwritetextformat1_layout_GetLastLineWrapping,
4461 dwritetextformat1_layout_SetOpticalAlignment,
4462 dwritetextformat1_layout_GetOpticalAlignment,
4463 dwritetextformat1_layout_SetFontFallback,
4464 dwritetextformat1_layout_GetFontFallback,
4467 static HRESULT WINAPI dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink1 *iface,
4468 REFIID riid, void **obj)
4470 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink1) ||
4471 IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) ||
4472 IsEqualIID(riid, &IID_IUnknown))
4474 *obj = iface;
4475 IDWriteTextAnalysisSink1_AddRef(iface);
4476 return S_OK;
4479 *obj = NULL;
4480 return E_NOINTERFACE;
4483 static ULONG WINAPI dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink1 *iface)
4485 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4486 return IDWriteTextLayout3_AddRef(&layout->IDWriteTextLayout3_iface);
4489 static ULONG WINAPI dwritetextlayout_sink_Release(IDWriteTextAnalysisSink1 *iface)
4491 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4492 return IDWriteTextLayout3_Release(&layout->IDWriteTextLayout3_iface);
4495 static HRESULT WINAPI dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink1 *iface,
4496 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
4498 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4499 struct layout_run *run;
4501 TRACE("[%u,%u) script=%u:%s\n", position, position + length, sa->script, debugstr_sa_script(sa->script));
4503 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
4504 if (!run)
4505 return E_OUTOFMEMORY;
4507 run->u.regular.descr.string = &layout->str[position];
4508 run->u.regular.descr.stringLength = length;
4509 run->u.regular.descr.textPosition = position;
4510 run->u.regular.sa = *sa;
4511 list_add_tail(&layout->runs, &run->entry);
4512 return S_OK;
4515 static HRESULT WINAPI dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink1 *iface,
4516 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
4518 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4520 if (position + length > layout->len)
4521 return E_FAIL;
4523 memcpy(&layout->nominal_breakpoints[position], breakpoints, length*sizeof(DWRITE_LINE_BREAKPOINT));
4524 return S_OK;
4527 static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink1 *iface, UINT32 position,
4528 UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
4530 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4531 struct layout_run *cur_run;
4533 TRACE("[%u,%u) %u %u\n", position, position + length, explicitLevel, resolvedLevel);
4535 LIST_FOR_EACH_ENTRY(cur_run, &layout->runs, struct layout_run, entry) {
4536 struct regular_layout_run *cur = &cur_run->u.regular;
4537 struct layout_run *run;
4539 if (cur_run->kind == LAYOUT_RUN_INLINE)
4540 continue;
4542 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
4543 if (position < cur->descr.textPosition || position >= cur->descr.textPosition + cur->descr.stringLength)
4544 continue;
4546 /* full hit - just set run level */
4547 if (cur->descr.textPosition == position && cur->descr.stringLength == length) {
4548 cur->run.bidiLevel = resolvedLevel;
4549 break;
4552 /* current run is fully covered, move to next one */
4553 if (cur->descr.textPosition == position && cur->descr.stringLength < length) {
4554 cur->run.bidiLevel = resolvedLevel;
4555 position += cur->descr.stringLength;
4556 length -= cur->descr.stringLength;
4557 continue;
4560 /* all fully covered runs are processed at this point, reuse existing run for remaining
4561 reported bidi range and add another run for the rest of original one */
4563 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
4564 if (!run)
4565 return E_OUTOFMEMORY;
4567 *run = *cur_run;
4568 run->u.regular.descr.textPosition = position + length;
4569 run->u.regular.descr.stringLength = cur->descr.stringLength - length;
4570 run->u.regular.descr.string = &layout->str[position + length];
4572 /* reduce existing run */
4573 cur->run.bidiLevel = resolvedLevel;
4574 cur->descr.stringLength = length;
4576 list_add_after(&cur_run->entry, &run->entry);
4577 break;
4580 return S_OK;
4583 static HRESULT WINAPI dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink1 *iface,
4584 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
4586 return E_NOTIMPL;
4589 static HRESULT WINAPI dwritetextlayout_sink_SetGlyphOrientation(IDWriteTextAnalysisSink1 *iface,
4590 UINT32 position, UINT32 length, DWRITE_GLYPH_ORIENTATION_ANGLE angle, UINT8 adjusted_bidi_level,
4591 BOOL is_sideways, BOOL is_rtl)
4593 return E_NOTIMPL;
4596 static const IDWriteTextAnalysisSink1Vtbl dwritetextlayoutsinkvtbl = {
4597 dwritetextlayout_sink_QueryInterface,
4598 dwritetextlayout_sink_AddRef,
4599 dwritetextlayout_sink_Release,
4600 dwritetextlayout_sink_SetScriptAnalysis,
4601 dwritetextlayout_sink_SetLineBreakpoints,
4602 dwritetextlayout_sink_SetBidiLevel,
4603 dwritetextlayout_sink_SetNumberSubstitution,
4604 dwritetextlayout_sink_SetGlyphOrientation
4607 static HRESULT WINAPI dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource1 *iface,
4608 REFIID riid, void **obj)
4610 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource1) ||
4611 IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) ||
4612 IsEqualIID(riid, &IID_IUnknown))
4614 *obj = iface;
4615 IDWriteTextAnalysisSource1_AddRef(iface);
4616 return S_OK;
4619 *obj = NULL;
4620 return E_NOINTERFACE;
4623 static ULONG WINAPI dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource1 *iface)
4625 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4626 return IDWriteTextLayout3_AddRef(&layout->IDWriteTextLayout3_iface);
4629 static ULONG WINAPI dwritetextlayout_source_Release(IDWriteTextAnalysisSource1 *iface)
4631 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4632 return IDWriteTextLayout3_Release(&layout->IDWriteTextLayout3_iface);
4635 static HRESULT WINAPI dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource1 *iface,
4636 UINT32 position, WCHAR const** text, UINT32* text_len)
4638 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4640 TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
4642 if (position < layout->len) {
4643 *text = &layout->str[position];
4644 *text_len = layout->len - position;
4646 else {
4647 *text = NULL;
4648 *text_len = 0;
4651 return S_OK;
4654 static HRESULT WINAPI dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource1 *iface,
4655 UINT32 position, WCHAR const** text, UINT32* text_len)
4657 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4659 TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
4661 if (position > 0 && position < layout->len) {
4662 *text = layout->str;
4663 *text_len = position;
4665 else {
4666 *text = NULL;
4667 *text_len = 0;
4670 return S_OK;
4673 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource1 *iface)
4675 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4676 return IDWriteTextLayout3_GetReadingDirection(&layout->IDWriteTextLayout3_iface);
4679 static HRESULT WINAPI dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource1 *iface,
4680 UINT32 position, UINT32* text_len, WCHAR const** locale)
4682 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4683 struct layout_range *range = get_layout_range_by_pos(layout, position);
4685 if (position < layout->len) {
4686 struct layout_range *next;
4688 *locale = range->locale;
4689 *text_len = range->h.range.length - position;
4691 next = LIST_ENTRY(list_next(&layout->ranges, &range->h.entry), struct layout_range, h.entry);
4692 while (next && next->h.range.startPosition < layout->len && !strcmpW(range->locale, next->locale)) {
4693 *text_len += next->h.range.length;
4694 next = LIST_ENTRY(list_next(&layout->ranges, &next->h.entry), struct layout_range, h.entry);
4697 *text_len = min(*text_len, layout->len - position);
4699 else {
4700 *locale = NULL;
4701 *text_len = 0;
4704 return S_OK;
4707 static HRESULT WINAPI dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource1 *iface,
4708 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
4710 FIXME("%u %p %p: stub\n", position, text_len, substitution);
4711 return E_NOTIMPL;
4714 static HRESULT WINAPI dwritetextlayout_source_GetVerticalGlyphOrientation(IDWriteTextAnalysisSource1 *iface,
4715 UINT32 position, UINT32 *length, DWRITE_VERTICAL_GLYPH_ORIENTATION *orientation, UINT8 *bidi_level)
4717 FIXME("%u %p %p %p: stub\n", position, length, orientation, bidi_level);
4718 return E_NOTIMPL;
4721 static const IDWriteTextAnalysisSource1Vtbl dwritetextlayoutsourcevtbl = {
4722 dwritetextlayout_source_QueryInterface,
4723 dwritetextlayout_source_AddRef,
4724 dwritetextlayout_source_Release,
4725 dwritetextlayout_source_GetTextAtPosition,
4726 dwritetextlayout_source_GetTextBeforePosition,
4727 dwritetextlayout_source_GetParagraphReadingDirection,
4728 dwritetextlayout_source_GetLocaleName,
4729 dwritetextlayout_source_GetNumberSubstitution,
4730 dwritetextlayout_source_GetVerticalGlyphOrientation
4733 static HRESULT layout_format_from_textformat(struct dwrite_textlayout *layout, IDWriteTextFormat *format)
4735 struct dwrite_textformat *textformat;
4736 IDWriteTextFormat1 *format1;
4737 UINT32 len;
4738 HRESULT hr;
4740 if ((textformat = unsafe_impl_from_IDWriteTextFormat(format))) {
4741 layout->format = textformat->format;
4743 layout->format.locale = heap_strdupW(textformat->format.locale);
4744 layout->format.family_name = heap_strdupW(textformat->format.family_name);
4745 if (!layout->format.locale || !layout->format.family_name)
4747 heap_free(layout->format.locale);
4748 heap_free(layout->format.family_name);
4749 return E_OUTOFMEMORY;
4752 if (layout->format.trimmingsign)
4753 IDWriteInlineObject_AddRef(layout->format.trimmingsign);
4754 if (layout->format.collection)
4755 IDWriteFontCollection_AddRef(layout->format.collection);
4756 if (layout->format.fallback)
4757 IDWriteFontFallback_AddRef(layout->format.fallback);
4759 return S_OK;
4762 layout->format.weight = IDWriteTextFormat_GetFontWeight(format);
4763 layout->format.style = IDWriteTextFormat_GetFontStyle(format);
4764 layout->format.stretch = IDWriteTextFormat_GetFontStretch(format);
4765 layout->format.fontsize= IDWriteTextFormat_GetFontSize(format);
4766 layout->format.textalignment = IDWriteTextFormat_GetTextAlignment(format);
4767 layout->format.paralign = IDWriteTextFormat_GetParagraphAlignment(format);
4768 layout->format.wrapping = IDWriteTextFormat_GetWordWrapping(format);
4769 layout->format.readingdir = IDWriteTextFormat_GetReadingDirection(format);
4770 layout->format.flow = IDWriteTextFormat_GetFlowDirection(format);
4771 layout->format.fallback = NULL;
4772 layout->format.spacing.leadingBefore = 0.0f;
4773 layout->format.spacing.fontLineGapUsage = DWRITE_FONT_LINE_GAP_USAGE_DEFAULT;
4774 hr = IDWriteTextFormat_GetLineSpacing(format, &layout->format.spacing.method,
4775 &layout->format.spacing.height, &layout->format.spacing.baseline);
4776 if (FAILED(hr))
4777 return hr;
4779 hr = IDWriteTextFormat_GetTrimming(format, &layout->format.trimming, &layout->format.trimmingsign);
4780 if (FAILED(hr))
4781 return hr;
4783 /* locale name and length */
4784 len = IDWriteTextFormat_GetLocaleNameLength(format);
4785 layout->format.locale = heap_alloc((len+1)*sizeof(WCHAR));
4786 if (!layout->format.locale)
4787 return E_OUTOFMEMORY;
4789 hr = IDWriteTextFormat_GetLocaleName(format, layout->format.locale, len+1);
4790 if (FAILED(hr))
4791 return hr;
4792 layout->format.locale_len = len;
4794 /* font family name and length */
4795 len = IDWriteTextFormat_GetFontFamilyNameLength(format);
4796 layout->format.family_name = heap_alloc((len+1)*sizeof(WCHAR));
4797 if (!layout->format.family_name)
4798 return E_OUTOFMEMORY;
4800 hr = IDWriteTextFormat_GetFontFamilyName(format, layout->format.family_name, len+1);
4801 if (FAILED(hr))
4802 return hr;
4803 layout->format.family_len = len;
4805 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
4806 if (hr == S_OK) {
4807 IDWriteTextFormat2 *format2;
4809 layout->format.vertical_orientation = IDWriteTextFormat1_GetVerticalGlyphOrientation(format1);
4810 layout->format.optical_alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
4811 IDWriteTextFormat1_GetFontFallback(format1, &layout->format.fallback);
4813 if (IDWriteTextFormat1_QueryInterface(format1, &IID_IDWriteTextFormat2, (void**)&format2) == S_OK) {
4814 IDWriteTextFormat2_GetLineSpacing(format2, &layout->format.spacing);
4815 IDWriteTextFormat2_Release(format2);
4818 IDWriteTextFormat1_Release(format1);
4820 else {
4821 layout->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
4822 layout->format.optical_alignment = DWRITE_OPTICAL_ALIGNMENT_NONE;
4825 return IDWriteTextFormat_GetFontCollection(format, &layout->format.collection);
4828 static HRESULT init_textlayout(const struct textlayout_desc *desc, struct dwrite_textlayout *layout)
4830 struct layout_range_header *range, *strike, *underline, *effect, *spacing, *typography;
4831 static const DWRITE_TEXT_RANGE r = { 0, ~0u };
4832 HRESULT hr;
4834 layout->IDWriteTextLayout3_iface.lpVtbl = &dwritetextlayoutvtbl;
4835 layout->IDWriteTextFormat1_iface.lpVtbl = &dwritetextformat1_layout_vtbl;
4836 layout->IDWriteTextAnalysisSink1_iface.lpVtbl = &dwritetextlayoutsinkvtbl;
4837 layout->IDWriteTextAnalysisSource1_iface.lpVtbl = &dwritetextlayoutsourcevtbl;
4838 layout->ref = 1;
4839 layout->len = desc->length;
4840 layout->recompute = RECOMPUTE_EVERYTHING;
4841 layout->nominal_breakpoints = NULL;
4842 layout->actual_breakpoints = NULL;
4843 layout->cluster_count = 0;
4844 layout->clustermetrics = NULL;
4845 layout->clusters = NULL;
4846 layout->linemetrics = NULL;
4847 layout->lines = NULL;
4848 layout->line_alloc = 0;
4849 layout->minwidth = 0.0f;
4850 list_init(&layout->eruns);
4851 list_init(&layout->inlineobjects);
4852 list_init(&layout->underlines);
4853 list_init(&layout->strikethrough);
4854 list_init(&layout->runs);
4855 list_init(&layout->ranges);
4856 list_init(&layout->strike_ranges);
4857 list_init(&layout->underline_ranges);
4858 list_init(&layout->effects);
4859 list_init(&layout->spacing);
4860 list_init(&layout->typographies);
4861 memset(&layout->format, 0, sizeof(layout->format));
4862 memset(&layout->metrics, 0, sizeof(layout->metrics));
4863 layout->metrics.layoutWidth = desc->max_width;
4864 layout->metrics.layoutHeight = desc->max_height;
4865 layout->measuringmode = DWRITE_MEASURING_MODE_NATURAL;
4867 layout->ppdip = 0.0f;
4868 memset(&layout->transform, 0, sizeof(layout->transform));
4870 layout->str = heap_strdupnW(desc->string, desc->length);
4871 if (desc->length && !layout->str) {
4872 hr = E_OUTOFMEMORY;
4873 goto fail;
4876 hr = layout_format_from_textformat(layout, desc->format);
4877 if (FAILED(hr))
4878 goto fail;
4880 range = alloc_layout_range(layout, &r, LAYOUT_RANGE_REGULAR);
4881 strike = alloc_layout_range(layout, &r, LAYOUT_RANGE_STRIKETHROUGH);
4882 underline = alloc_layout_range(layout, &r, LAYOUT_RANGE_UNDERLINE);
4883 effect = alloc_layout_range(layout, &r, LAYOUT_RANGE_EFFECT);
4884 spacing = alloc_layout_range(layout, &r, LAYOUT_RANGE_SPACING);
4885 typography = alloc_layout_range(layout, &r, LAYOUT_RANGE_TYPOGRAPHY);
4886 if (!range || !strike || !effect || !spacing || !typography || !underline) {
4887 free_layout_range(range);
4888 free_layout_range(strike);
4889 free_layout_range(underline);
4890 free_layout_range(effect);
4891 free_layout_range(spacing);
4892 free_layout_range(typography);
4893 hr = E_OUTOFMEMORY;
4894 goto fail;
4897 if (desc->is_gdi_compatible)
4898 layout->measuringmode = desc->use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
4899 else
4900 layout->measuringmode = DWRITE_MEASURING_MODE_NATURAL;
4901 layout->ppdip = desc->ppdip;
4902 layout->transform = desc->transform ? *desc->transform : identity;
4904 layout->factory = desc->factory;
4905 IDWriteFactory5_AddRef(layout->factory);
4906 list_add_head(&layout->ranges, &range->entry);
4907 list_add_head(&layout->strike_ranges, &strike->entry);
4908 list_add_head(&layout->underline_ranges, &underline->entry);
4909 list_add_head(&layout->effects, &effect->entry);
4910 list_add_head(&layout->spacing, &spacing->entry);
4911 list_add_head(&layout->typographies, &typography->entry);
4912 return S_OK;
4914 fail:
4915 IDWriteTextLayout3_Release(&layout->IDWriteTextLayout3_iface);
4916 return hr;
4919 HRESULT create_textlayout(const struct textlayout_desc *desc, IDWriteTextLayout **ret)
4921 struct dwrite_textlayout *layout;
4922 HRESULT hr;
4924 *ret = NULL;
4926 if (!desc->format || !desc->string)
4927 return E_INVALIDARG;
4929 layout = heap_alloc(sizeof(struct dwrite_textlayout));
4930 if (!layout) return E_OUTOFMEMORY;
4932 hr = init_textlayout(desc, layout);
4933 if (hr == S_OK)
4934 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout3_iface;
4936 return hr;
4939 static HRESULT WINAPI dwritetrimmingsign_QueryInterface(IDWriteInlineObject *iface, REFIID riid, void **obj)
4941 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4943 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4945 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteInlineObject)) {
4946 *obj = iface;
4947 IDWriteInlineObject_AddRef(iface);
4948 return S_OK;
4951 *obj = NULL;
4952 return E_NOINTERFACE;
4955 static ULONG WINAPI dwritetrimmingsign_AddRef(IDWriteInlineObject *iface)
4957 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4958 ULONG ref = InterlockedIncrement(&This->ref);
4959 TRACE("(%p)->(%d)\n", This, ref);
4960 return ref;
4963 static ULONG WINAPI dwritetrimmingsign_Release(IDWriteInlineObject *iface)
4965 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4966 ULONG ref = InterlockedDecrement(&This->ref);
4968 TRACE("(%p)->(%d)\n", This, ref);
4970 if (!ref) {
4971 IDWriteTextLayout_Release(This->layout);
4972 heap_free(This);
4975 return ref;
4978 static HRESULT WINAPI dwritetrimmingsign_Draw(IDWriteInlineObject *iface, void *context, IDWriteTextRenderer *renderer,
4979 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *effect)
4981 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4982 DWRITE_TEXT_RANGE range = { 0, ~0u };
4983 DWRITE_TEXT_METRICS metrics;
4984 DWRITE_LINE_METRICS line;
4985 UINT32 line_count;
4986 HRESULT hr;
4988 TRACE("(%p)->(%p %p %.2f %.2f %d %d %p)\n", This, context, renderer, originX, originY, is_sideways, is_rtl, effect);
4990 IDWriteTextLayout_SetDrawingEffect(This->layout, effect, range);
4991 IDWriteTextLayout_GetLineMetrics(This->layout, &line, 1, &line_count);
4992 IDWriteTextLayout_GetMetrics(This->layout, &metrics);
4993 hr = IDWriteTextLayout_Draw(This->layout, context, renderer, originX, originY - line.baseline);
4994 IDWriteTextLayout_SetDrawingEffect(This->layout, NULL, range);
4995 return hr;
4998 static HRESULT WINAPI dwritetrimmingsign_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *ret)
5000 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
5001 DWRITE_TEXT_METRICS metrics;
5002 HRESULT hr;
5004 TRACE("(%p)->(%p)\n", This, ret);
5006 hr = IDWriteTextLayout_GetMetrics(This->layout, &metrics);
5007 if (FAILED(hr)) {
5008 memset(ret, 0, sizeof(*ret));
5009 return hr;
5012 ret->width = metrics.width;
5013 ret->height = 0.0f;
5014 ret->baseline = 0.0f;
5015 ret->supportsSideways = FALSE;
5016 return S_OK;
5019 static HRESULT WINAPI dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
5021 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
5022 TRACE("(%p)->(%p)\n", This, overhangs);
5023 return IDWriteTextLayout_GetOverhangMetrics(This->layout, overhangs);
5026 static HRESULT WINAPI dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
5027 DWRITE_BREAK_CONDITION *after)
5029 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
5031 TRACE("(%p)->(%p %p)\n", This, before, after);
5033 *before = *after = DWRITE_BREAK_CONDITION_NEUTRAL;
5034 return S_OK;
5037 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl = {
5038 dwritetrimmingsign_QueryInterface,
5039 dwritetrimmingsign_AddRef,
5040 dwritetrimmingsign_Release,
5041 dwritetrimmingsign_Draw,
5042 dwritetrimmingsign_GetMetrics,
5043 dwritetrimmingsign_GetOverhangMetrics,
5044 dwritetrimmingsign_GetBreakConditions
5047 static inline BOOL is_reading_direction_horz(DWRITE_READING_DIRECTION direction)
5049 return (direction == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT) ||
5050 (direction == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
5053 static inline BOOL is_reading_direction_vert(DWRITE_READING_DIRECTION direction)
5055 return (direction == DWRITE_READING_DIRECTION_TOP_TO_BOTTOM) ||
5056 (direction == DWRITE_READING_DIRECTION_BOTTOM_TO_TOP);
5059 static inline BOOL is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction)
5061 return (direction == DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT) ||
5062 (direction == DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT);
5065 static inline BOOL is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction)
5067 return (direction == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM) ||
5068 (direction == DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP);
5071 HRESULT create_trimmingsign(IDWriteFactory5 *factory, IDWriteTextFormat *format, IDWriteInlineObject **sign)
5073 static const WCHAR ellipsisW = 0x2026;
5074 struct dwrite_trimmingsign *This;
5075 DWRITE_READING_DIRECTION reading;
5076 DWRITE_FLOW_DIRECTION flow;
5077 HRESULT hr;
5079 *sign = NULL;
5081 /* Validate reading/flow direction here, layout creation won't complain about
5082 invalid combinations. */
5083 reading = IDWriteTextFormat_GetReadingDirection(format);
5084 flow = IDWriteTextFormat_GetFlowDirection(format);
5086 if ((is_reading_direction_horz(reading) && is_flow_direction_horz(flow)) ||
5087 (is_reading_direction_vert(reading) && is_flow_direction_vert(flow)))
5088 return DWRITE_E_FLOWDIRECTIONCONFLICTS;
5090 This = heap_alloc(sizeof(*This));
5091 if (!This)
5092 return E_OUTOFMEMORY;
5094 This->IDWriteInlineObject_iface.lpVtbl = &dwritetrimmingsignvtbl;
5095 This->ref = 1;
5097 hr = IDWriteFactory5_CreateTextLayout(factory, &ellipsisW, 1, format, 0.0f, 0.0f, &This->layout);
5098 if (FAILED(hr)) {
5099 heap_free(This);
5100 return hr;
5103 IDWriteTextLayout_SetWordWrapping(This->layout, DWRITE_WORD_WRAPPING_NO_WRAP);
5104 IDWriteTextLayout_SetParagraphAlignment(This->layout, DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
5105 *sign = &This->IDWriteInlineObject_iface;
5107 return S_OK;
5110 static HRESULT WINAPI dwritetextformat_QueryInterface(IDWriteTextFormat2 *iface, REFIID riid, void **obj)
5112 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5114 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
5116 if (IsEqualIID(riid, &IID_IDWriteTextFormat2) ||
5117 IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
5118 IsEqualIID(riid, &IID_IDWriteTextFormat) ||
5119 IsEqualIID(riid, &IID_IUnknown))
5121 *obj = iface;
5122 IDWriteTextFormat2_AddRef(iface);
5123 return S_OK;
5126 *obj = NULL;
5128 return E_NOINTERFACE;
5131 static ULONG WINAPI dwritetextformat_AddRef(IDWriteTextFormat2 *iface)
5133 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5134 ULONG ref = InterlockedIncrement(&This->ref);
5135 TRACE("(%p)->(%d)\n", This, ref);
5136 return ref;
5139 static ULONG WINAPI dwritetextformat_Release(IDWriteTextFormat2 *iface)
5141 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5142 ULONG ref = InterlockedDecrement(&This->ref);
5144 TRACE("(%p)->(%d)\n", This, ref);
5146 if (!ref)
5148 release_format_data(&This->format);
5149 heap_free(This);
5152 return ref;
5155 static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat2 *iface, DWRITE_TEXT_ALIGNMENT alignment)
5157 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5158 TRACE("(%p)->(%d)\n", This, alignment);
5159 return format_set_textalignment(&This->format, alignment, NULL);
5162 static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat2 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
5164 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5165 TRACE("(%p)->(%d)\n", This, alignment);
5166 return format_set_paralignment(&This->format, alignment, NULL);
5169 static HRESULT WINAPI dwritetextformat_SetWordWrapping(IDWriteTextFormat2 *iface, DWRITE_WORD_WRAPPING wrapping)
5171 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5172 TRACE("(%p)->(%d)\n", This, wrapping);
5173 return format_set_wordwrapping(&This->format, wrapping, NULL);
5176 static HRESULT WINAPI dwritetextformat_SetReadingDirection(IDWriteTextFormat2 *iface, DWRITE_READING_DIRECTION direction)
5178 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5179 TRACE("(%p)->(%d)\n", This, direction);
5180 return format_set_readingdirection(&This->format, direction, NULL);
5183 static HRESULT WINAPI dwritetextformat_SetFlowDirection(IDWriteTextFormat2 *iface, DWRITE_FLOW_DIRECTION direction)
5185 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5186 TRACE("(%p)->(%d)\n", This, direction);
5187 return format_set_flowdirection(&This->format, direction, NULL);
5190 static HRESULT WINAPI dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat2 *iface, FLOAT tabstop)
5192 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5193 FIXME("(%p)->(%f): stub\n", This, tabstop);
5194 return E_NOTIMPL;
5197 static HRESULT WINAPI dwritetextformat_SetTrimming(IDWriteTextFormat2 *iface, DWRITE_TRIMMING const *trimming,
5198 IDWriteInlineObject *trimming_sign)
5200 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5201 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
5202 return format_set_trimming(&This->format, trimming, trimming_sign, NULL);
5205 static HRESULT WINAPI dwritetextformat_SetLineSpacing(IDWriteTextFormat2 *iface, DWRITE_LINE_SPACING_METHOD method,
5206 FLOAT height, FLOAT baseline)
5208 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5209 DWRITE_LINE_SPACING spacing;
5211 TRACE("(%p)->(%d %f %f)\n", This, method, height, baseline);
5213 spacing = This->format.spacing;
5214 spacing.method = method;
5215 spacing.height = height;
5216 spacing.baseline = baseline;
5218 return format_set_linespacing(&This->format, &spacing, NULL);
5221 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_GetTextAlignment(IDWriteTextFormat2 *iface)
5223 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5224 TRACE("(%p)\n", This);
5225 return This->format.textalignment;
5228 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_GetParagraphAlignment(IDWriteTextFormat2 *iface)
5230 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5231 TRACE("(%p)\n", This);
5232 return This->format.paralign;
5235 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_GetWordWrapping(IDWriteTextFormat2 *iface)
5237 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5238 TRACE("(%p)\n", This);
5239 return This->format.wrapping;
5242 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_GetReadingDirection(IDWriteTextFormat2 *iface)
5244 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5245 TRACE("(%p)\n", This);
5246 return This->format.readingdir;
5249 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_GetFlowDirection(IDWriteTextFormat2 *iface)
5251 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5252 TRACE("(%p)\n", This);
5253 return This->format.flow;
5256 static FLOAT WINAPI dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat2 *iface)
5258 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5259 FIXME("(%p): stub\n", This);
5260 return 0.0f;
5263 static HRESULT WINAPI dwritetextformat_GetTrimming(IDWriteTextFormat2 *iface, DWRITE_TRIMMING *options,
5264 IDWriteInlineObject **trimming_sign)
5266 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5267 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
5269 *options = This->format.trimming;
5270 if ((*trimming_sign = This->format.trimmingsign))
5271 IDWriteInlineObject_AddRef(*trimming_sign);
5273 return S_OK;
5276 static HRESULT WINAPI dwritetextformat_GetLineSpacing(IDWriteTextFormat2 *iface, DWRITE_LINE_SPACING_METHOD *method,
5277 FLOAT *spacing, FLOAT *baseline)
5279 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5280 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
5282 *method = This->format.spacing.method;
5283 *spacing = This->format.spacing.height;
5284 *baseline = This->format.spacing.baseline;
5285 return S_OK;
5288 static HRESULT WINAPI dwritetextformat_GetFontCollection(IDWriteTextFormat2 *iface, IDWriteFontCollection **collection)
5290 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5292 TRACE("(%p)->(%p)\n", This, collection);
5294 *collection = This->format.collection;
5295 IDWriteFontCollection_AddRef(*collection);
5297 return S_OK;
5300 static UINT32 WINAPI dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat2 *iface)
5302 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5303 TRACE("(%p)\n", This);
5304 return This->format.family_len;
5307 static HRESULT WINAPI dwritetextformat_GetFontFamilyName(IDWriteTextFormat2 *iface, WCHAR *name, UINT32 size)
5309 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5311 TRACE("(%p)->(%p %u)\n", This, name, size);
5313 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
5314 strcpyW(name, This->format.family_name);
5315 return S_OK;
5318 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_GetFontWeight(IDWriteTextFormat2 *iface)
5320 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5321 TRACE("(%p)\n", This);
5322 return This->format.weight;
5325 static DWRITE_FONT_STYLE WINAPI dwritetextformat_GetFontStyle(IDWriteTextFormat2 *iface)
5327 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5328 TRACE("(%p)\n", This);
5329 return This->format.style;
5332 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_GetFontStretch(IDWriteTextFormat2 *iface)
5334 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5335 TRACE("(%p)\n", This);
5336 return This->format.stretch;
5339 static FLOAT WINAPI dwritetextformat_GetFontSize(IDWriteTextFormat2 *iface)
5341 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5342 TRACE("(%p)\n", This);
5343 return This->format.fontsize;
5346 static UINT32 WINAPI dwritetextformat_GetLocaleNameLength(IDWriteTextFormat2 *iface)
5348 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5349 TRACE("(%p)\n", This);
5350 return This->format.locale_len;
5353 static HRESULT WINAPI dwritetextformat_GetLocaleName(IDWriteTextFormat2 *iface, WCHAR *name, UINT32 size)
5355 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5357 TRACE("(%p)->(%p %u)\n", This, name, size);
5359 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
5360 strcpyW(name, This->format.locale);
5361 return S_OK;
5364 static HRESULT WINAPI dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat2 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
5366 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5368 TRACE("(%p)->(%d)\n", This, orientation);
5370 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
5371 return E_INVALIDARG;
5373 This->format.vertical_orientation = orientation;
5374 return S_OK;
5377 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat2 *iface)
5379 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5380 TRACE("(%p)\n", This);
5381 return This->format.vertical_orientation;
5384 static HRESULT WINAPI dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat2 *iface, BOOL lastline_wrapping_enabled)
5386 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5388 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
5390 This->format.last_line_wrapping = !!lastline_wrapping_enabled;
5391 return S_OK;
5394 static BOOL WINAPI dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat2 *iface)
5396 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5397 TRACE("(%p)\n", This);
5398 return This->format.last_line_wrapping;
5401 static HRESULT WINAPI dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat2 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
5403 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5404 TRACE("(%p)->(%d)\n", This, alignment);
5405 return format_set_optical_alignment(&This->format, alignment);
5408 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat2 *iface)
5410 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5411 TRACE("(%p)\n", This);
5412 return This->format.optical_alignment;
5415 static HRESULT WINAPI dwritetextformat1_SetFontFallback(IDWriteTextFormat2 *iface, IDWriteFontFallback *fallback)
5417 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5418 TRACE("(%p)->(%p)\n", This, fallback);
5419 return set_fontfallback_for_format(&This->format, fallback);
5422 static HRESULT WINAPI dwritetextformat1_GetFontFallback(IDWriteTextFormat2 *iface, IDWriteFontFallback **fallback)
5424 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5425 TRACE("(%p)->(%p)\n", This, fallback);
5426 return get_fontfallback_from_format(&This->format, fallback);
5429 static HRESULT WINAPI dwritetextformat2_SetLineSpacing(IDWriteTextFormat2 *iface, DWRITE_LINE_SPACING const *spacing)
5431 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5432 TRACE("(%p)->(%p)\n", This, spacing);
5433 return format_set_linespacing(&This->format, spacing, NULL);
5436 static HRESULT WINAPI dwritetextformat2_GetLineSpacing(IDWriteTextFormat2 *iface, DWRITE_LINE_SPACING *spacing)
5438 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5440 TRACE("(%p)->(%p)\n", This, spacing);
5442 *spacing = This->format.spacing;
5443 return S_OK;
5446 static const IDWriteTextFormat2Vtbl dwritetextformatvtbl = {
5447 dwritetextformat_QueryInterface,
5448 dwritetextformat_AddRef,
5449 dwritetextformat_Release,
5450 dwritetextformat_SetTextAlignment,
5451 dwritetextformat_SetParagraphAlignment,
5452 dwritetextformat_SetWordWrapping,
5453 dwritetextformat_SetReadingDirection,
5454 dwritetextformat_SetFlowDirection,
5455 dwritetextformat_SetIncrementalTabStop,
5456 dwritetextformat_SetTrimming,
5457 dwritetextformat_SetLineSpacing,
5458 dwritetextformat_GetTextAlignment,
5459 dwritetextformat_GetParagraphAlignment,
5460 dwritetextformat_GetWordWrapping,
5461 dwritetextformat_GetReadingDirection,
5462 dwritetextformat_GetFlowDirection,
5463 dwritetextformat_GetIncrementalTabStop,
5464 dwritetextformat_GetTrimming,
5465 dwritetextformat_GetLineSpacing,
5466 dwritetextformat_GetFontCollection,
5467 dwritetextformat_GetFontFamilyNameLength,
5468 dwritetextformat_GetFontFamilyName,
5469 dwritetextformat_GetFontWeight,
5470 dwritetextformat_GetFontStyle,
5471 dwritetextformat_GetFontStretch,
5472 dwritetextformat_GetFontSize,
5473 dwritetextformat_GetLocaleNameLength,
5474 dwritetextformat_GetLocaleName,
5475 dwritetextformat1_SetVerticalGlyphOrientation,
5476 dwritetextformat1_GetVerticalGlyphOrientation,
5477 dwritetextformat1_SetLastLineWrapping,
5478 dwritetextformat1_GetLastLineWrapping,
5479 dwritetextformat1_SetOpticalAlignment,
5480 dwritetextformat1_GetOpticalAlignment,
5481 dwritetextformat1_SetFontFallback,
5482 dwritetextformat1_GetFontFallback,
5483 dwritetextformat2_SetLineSpacing,
5484 dwritetextformat2_GetLineSpacing
5487 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat *iface)
5489 return (iface->lpVtbl == (IDWriteTextFormatVtbl*)&dwritetextformatvtbl) ?
5490 CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat2_iface) : NULL;
5493 HRESULT create_textformat(const WCHAR *family_name, IDWriteFontCollection *collection, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style,
5494 DWRITE_FONT_STRETCH stretch, FLOAT size, const WCHAR *locale, IDWriteTextFormat **format)
5496 struct dwrite_textformat *This;
5498 *format = NULL;
5500 if (size <= 0.0f)
5501 return E_INVALIDARG;
5503 if (((UINT32)weight > DWRITE_FONT_WEIGHT_ULTRA_BLACK) ||
5504 ((UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED) ||
5505 ((UINT32)style > DWRITE_FONT_STYLE_ITALIC))
5506 return E_INVALIDARG;
5508 This = heap_alloc(sizeof(struct dwrite_textformat));
5509 if (!This) return E_OUTOFMEMORY;
5511 This->IDWriteTextFormat2_iface.lpVtbl = &dwritetextformatvtbl;
5512 This->ref = 1;
5513 This->format.family_name = heap_strdupW(family_name);
5514 This->format.family_len = strlenW(family_name);
5515 This->format.locale = heap_strdupW(locale);
5516 This->format.locale_len = strlenW(locale);
5517 /* force locale name to lower case, layout will inherit this modified value */
5518 strlwrW(This->format.locale);
5519 This->format.weight = weight;
5520 This->format.style = style;
5521 This->format.fontsize = size;
5522 This->format.stretch = stretch;
5523 This->format.textalignment = DWRITE_TEXT_ALIGNMENT_LEADING;
5524 This->format.optical_alignment = DWRITE_OPTICAL_ALIGNMENT_NONE;
5525 This->format.paralign = DWRITE_PARAGRAPH_ALIGNMENT_NEAR;
5526 This->format.wrapping = DWRITE_WORD_WRAPPING_WRAP;
5527 This->format.last_line_wrapping = TRUE;
5528 This->format.readingdir = DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
5529 This->format.flow = DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM;
5530 This->format.spacing.method = DWRITE_LINE_SPACING_METHOD_DEFAULT;
5531 This->format.spacing.height = 0.0f;
5532 This->format.spacing.baseline = 0.0f;
5533 This->format.spacing.leadingBefore = 0.0f;
5534 This->format.spacing.fontLineGapUsage = DWRITE_FONT_LINE_GAP_USAGE_DEFAULT;
5535 This->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
5536 This->format.trimming.granularity = DWRITE_TRIMMING_GRANULARITY_NONE;
5537 This->format.trimming.delimiter = 0;
5538 This->format.trimming.delimiterCount = 0;
5539 This->format.trimmingsign = NULL;
5540 This->format.collection = collection;
5541 This->format.fallback = NULL;
5542 IDWriteFontCollection_AddRef(collection);
5544 *format = (IDWriteTextFormat*)&This->IDWriteTextFormat2_iface;
5546 return S_OK;
5549 static HRESULT WINAPI dwritetypography_QueryInterface(IDWriteTypography *iface, REFIID riid, void **obj)
5551 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5553 TRACE("(%p)->(%s %p)\n", typography, debugstr_guid(riid), obj);
5555 if (IsEqualIID(riid, &IID_IDWriteTypography) || IsEqualIID(riid, &IID_IUnknown)) {
5556 *obj = iface;
5557 IDWriteTypography_AddRef(iface);
5558 return S_OK;
5561 *obj = NULL;
5563 return E_NOINTERFACE;
5566 static ULONG WINAPI dwritetypography_AddRef(IDWriteTypography *iface)
5568 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5569 ULONG ref = InterlockedIncrement(&typography->ref);
5570 TRACE("(%p)->(%d)\n", typography, ref);
5571 return ref;
5574 static ULONG WINAPI dwritetypography_Release(IDWriteTypography *iface)
5576 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5577 ULONG ref = InterlockedDecrement(&typography->ref);
5579 TRACE("(%p)->(%d)\n", typography, ref);
5581 if (!ref) {
5582 heap_free(typography->features);
5583 heap_free(typography);
5586 return ref;
5589 static HRESULT WINAPI dwritetypography_AddFontFeature(IDWriteTypography *iface, DWRITE_FONT_FEATURE feature)
5591 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5593 TRACE("(%p)->(%x %u)\n", typography, feature.nameTag, feature.parameter);
5595 if (typography->count == typography->allocated) {
5596 DWRITE_FONT_FEATURE *ptr = heap_realloc(typography->features, 2*typography->allocated*sizeof(DWRITE_FONT_FEATURE));
5597 if (!ptr)
5598 return E_OUTOFMEMORY;
5600 typography->features = ptr;
5601 typography->allocated *= 2;
5604 typography->features[typography->count++] = feature;
5605 return S_OK;
5608 static UINT32 WINAPI dwritetypography_GetFontFeatureCount(IDWriteTypography *iface)
5610 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5611 TRACE("(%p)\n", typography);
5612 return typography->count;
5615 static HRESULT WINAPI dwritetypography_GetFontFeature(IDWriteTypography *iface, UINT32 index, DWRITE_FONT_FEATURE *feature)
5617 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5619 TRACE("(%p)->(%u %p)\n", typography, index, feature);
5621 if (index >= typography->count)
5622 return E_INVALIDARG;
5624 *feature = typography->features[index];
5625 return S_OK;
5628 static const IDWriteTypographyVtbl dwritetypographyvtbl = {
5629 dwritetypography_QueryInterface,
5630 dwritetypography_AddRef,
5631 dwritetypography_Release,
5632 dwritetypography_AddFontFeature,
5633 dwritetypography_GetFontFeatureCount,
5634 dwritetypography_GetFontFeature
5637 HRESULT create_typography(IDWriteTypography **ret)
5639 struct dwrite_typography *typography;
5641 *ret = NULL;
5643 typography = heap_alloc(sizeof(*typography));
5644 if (!typography)
5645 return E_OUTOFMEMORY;
5647 typography->IDWriteTypography_iface.lpVtbl = &dwritetypographyvtbl;
5648 typography->ref = 1;
5649 typography->allocated = 2;
5650 typography->count = 0;
5652 typography->features = heap_alloc(typography->allocated*sizeof(DWRITE_FONT_FEATURE));
5653 if (!typography->features) {
5654 heap_free(typography);
5655 return E_OUTOFMEMORY;
5658 *ret = &typography->IDWriteTypography_iface;
5659 return S_OK;