dwrite: Implement DetermineMinWidth() using line breaking info.
[wine.git] / dlls / dwrite / layout.c
blob03001666118287cc94efb14a16c860fc86e25f1b
1 /*
2 * Text format and layout
4 * Copyright 2012, 2014-2016 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"
31 #include "wine/list.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
35 struct dwrite_textformat_data {
36 WCHAR *family_name;
37 UINT32 family_len;
38 WCHAR *locale;
39 UINT32 locale_len;
41 DWRITE_FONT_WEIGHT weight;
42 DWRITE_FONT_STYLE style;
43 DWRITE_FONT_STRETCH stretch;
45 DWRITE_PARAGRAPH_ALIGNMENT paralign;
46 DWRITE_READING_DIRECTION readingdir;
47 DWRITE_WORD_WRAPPING wrapping;
48 BOOL last_line_wrapping;
49 DWRITE_TEXT_ALIGNMENT textalignment;
50 DWRITE_FLOW_DIRECTION flow;
51 DWRITE_LINE_SPACING_METHOD spacingmethod;
52 DWRITE_VERTICAL_GLYPH_ORIENTATION vertical_orientation;
53 DWRITE_OPTICAL_ALIGNMENT optical_alignment;
55 FLOAT spacing;
56 FLOAT baseline;
57 FLOAT fontsize;
59 DWRITE_TRIMMING trimming;
60 IDWriteInlineObject *trimmingsign;
62 IDWriteFontCollection *collection;
63 IDWriteFontFallback *fallback;
66 enum layout_range_attr_kind {
67 LAYOUT_RANGE_ATTR_WEIGHT,
68 LAYOUT_RANGE_ATTR_STYLE,
69 LAYOUT_RANGE_ATTR_STRETCH,
70 LAYOUT_RANGE_ATTR_FONTSIZE,
71 LAYOUT_RANGE_ATTR_EFFECT,
72 LAYOUT_RANGE_ATTR_INLINE,
73 LAYOUT_RANGE_ATTR_UNDERLINE,
74 LAYOUT_RANGE_ATTR_STRIKETHROUGH,
75 LAYOUT_RANGE_ATTR_PAIR_KERNING,
76 LAYOUT_RANGE_ATTR_FONTCOLL,
77 LAYOUT_RANGE_ATTR_LOCALE,
78 LAYOUT_RANGE_ATTR_FONTFAMILY,
79 LAYOUT_RANGE_ATTR_SPACING,
80 LAYOUT_RANGE_ATTR_TYPOGRAPHY
83 struct layout_range_attr_value {
84 DWRITE_TEXT_RANGE range;
85 union {
86 DWRITE_FONT_WEIGHT weight;
87 DWRITE_FONT_STYLE style;
88 DWRITE_FONT_STRETCH stretch;
89 FLOAT fontsize;
90 IDWriteInlineObject *object;
91 IUnknown *effect;
92 BOOL underline;
93 BOOL strikethrough;
94 BOOL pair_kerning;
95 IDWriteFontCollection *collection;
96 const WCHAR *locale;
97 const WCHAR *fontfamily;
98 FLOAT spacing[3]; /* in arguments order - leading, trailing, advance */
99 IDWriteTypography *typography;
100 } u;
103 enum layout_range_kind {
104 LAYOUT_RANGE_REGULAR,
105 LAYOUT_RANGE_UNDERLINE,
106 LAYOUT_RANGE_STRIKETHROUGH,
107 LAYOUT_RANGE_EFFECT,
108 LAYOUT_RANGE_SPACING,
109 LAYOUT_RANGE_TYPOGRAPHY
112 struct layout_range_header {
113 struct list entry;
114 enum layout_range_kind kind;
115 DWRITE_TEXT_RANGE range;
118 struct layout_range {
119 struct layout_range_header h;
120 DWRITE_FONT_WEIGHT weight;
121 DWRITE_FONT_STYLE style;
122 FLOAT fontsize;
123 DWRITE_FONT_STRETCH stretch;
124 IDWriteInlineObject *object;
125 BOOL pair_kerning;
126 IDWriteFontCollection *collection;
127 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
128 WCHAR *fontfamily;
131 struct layout_range_bool {
132 struct layout_range_header h;
133 BOOL value;
136 struct layout_range_iface {
137 struct layout_range_header h;
138 IUnknown *iface;
141 struct layout_range_spacing {
142 struct layout_range_header h;
143 FLOAT leading;
144 FLOAT trailing;
145 FLOAT min_advance;
148 enum layout_run_kind {
149 LAYOUT_RUN_REGULAR,
150 LAYOUT_RUN_INLINE
153 struct inline_object_run {
154 IDWriteInlineObject *object;
155 UINT16 length;
158 struct regular_layout_run {
159 DWRITE_GLYPH_RUN_DESCRIPTION descr;
160 DWRITE_GLYPH_RUN run;
161 DWRITE_SCRIPT_ANALYSIS sa;
162 UINT16 *glyphs;
163 UINT16 *clustermap;
164 FLOAT *advances;
165 DWRITE_GLYPH_OFFSET *offsets;
166 /* this is actual glyph count after shaping, it's not necessary the same as reported to Draw() */
167 UINT32 glyphcount;
170 struct layout_run {
171 struct list entry;
172 enum layout_run_kind kind;
173 union {
174 struct inline_object_run object;
175 struct regular_layout_run regular;
176 } u;
177 FLOAT baseline;
178 FLOAT height;
181 struct layout_effective_run {
182 struct list entry;
183 const struct layout_run *run; /* nominal run this one is based on */
184 UINT32 start; /* relative text position, 0 means first text position of a nominal run */
185 UINT32 length; /* length in codepoints that this run covers */
186 UINT32 glyphcount; /* total glyph count in this run */
187 IUnknown *effect; /* original reference is kept only at range level */
188 FLOAT origin_x; /* baseline X position */
189 FLOAT origin_y; /* baseline Y position */
190 FLOAT align_dx; /* adjustment from text alignment */
191 FLOAT width; /* run width */
192 UINT16 *clustermap; /* effective clustermap, allocated separately, is not reused from nominal map */
193 UINT32 line; /* 0-based line index in line metrics array */
194 BOOL underlined; /* set if this run is underlined */
197 struct layout_effective_inline {
198 struct list entry;
199 IDWriteInlineObject *object;
200 IUnknown *effect;
201 FLOAT origin_x;
202 FLOAT origin_y;
203 FLOAT align_dx;
204 FLOAT width;
205 BOOL is_sideways;
206 BOOL is_rtl;
207 UINT32 line;
210 struct layout_underline {
211 struct list entry;
212 const struct layout_effective_run *run;
213 DWRITE_UNDERLINE u;
216 struct layout_strikethrough {
217 struct list entry;
218 const struct layout_effective_run *run;
219 DWRITE_STRIKETHROUGH s;
222 struct layout_cluster {
223 const struct layout_run *run; /* link to nominal run this cluster belongs to */
224 UINT32 position; /* relative to run, first cluster has 0 position */
227 enum layout_recompute_mask {
228 RECOMPUTE_NOMINAL_RUNS = 1 << 0,
229 RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
230 RECOMPUTE_EFFECTIVE_RUNS = 1 << 2,
231 RECOMPUTE_EVERYTHING = 0xffff
234 struct dwrite_textlayout {
235 IDWriteTextLayout2 IDWriteTextLayout2_iface;
236 IDWriteTextFormat1 IDWriteTextFormat1_iface;
237 IDWriteTextAnalysisSink IDWriteTextAnalysisSink_iface;
238 IDWriteTextAnalysisSource IDWriteTextAnalysisSource_iface;
239 LONG ref;
241 WCHAR *str;
242 UINT32 len;
243 struct dwrite_textformat_data format;
244 struct list strike_ranges;
245 struct list underline_ranges;
246 struct list typographies;
247 struct list effects;
248 struct list spacing;
249 struct list ranges;
250 struct list runs;
251 /* lists ready to use by Draw() */
252 struct list eruns;
253 struct list inlineobjects;
254 struct list underlines;
255 struct list strikethrough;
256 USHORT recompute;
258 DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
259 DWRITE_LINE_BREAKPOINT *actual_breakpoints;
261 struct layout_cluster *clusters;
262 DWRITE_CLUSTER_METRICS *clustermetrics;
263 UINT32 cluster_count;
264 FLOAT minwidth;
266 DWRITE_LINE_METRICS *lines;
267 UINT32 line_alloc;
269 DWRITE_TEXT_METRICS1 metrics;
271 DWRITE_MEASURING_MODE measuringmode;
273 /* gdi-compatible layout specifics */
274 FLOAT ppdip;
275 DWRITE_MATRIX transform;
278 struct dwrite_textformat {
279 IDWriteTextFormat1 IDWriteTextFormat1_iface;
280 LONG ref;
281 struct dwrite_textformat_data format;
284 struct dwrite_trimmingsign {
285 IDWriteInlineObject IDWriteInlineObject_iface;
286 LONG ref;
288 IDWriteTextLayout *layout;
291 struct dwrite_typography {
292 IDWriteTypography IDWriteTypography_iface;
293 LONG ref;
295 DWRITE_FONT_FEATURE *features;
296 UINT32 allocated;
297 UINT32 count;
300 struct dwrite_vec {
301 FLOAT x;
302 FLOAT y;
305 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl;
307 static void release_format_data(struct dwrite_textformat_data *data)
309 if (data->collection) IDWriteFontCollection_Release(data->collection);
310 if (data->fallback) IDWriteFontFallback_Release(data->fallback);
311 if (data->trimmingsign) IDWriteInlineObject_Release(data->trimmingsign);
312 heap_free(data->family_name);
313 heap_free(data->locale);
316 static inline struct dwrite_textlayout *impl_from_IDWriteTextLayout2(IDWriteTextLayout2 *iface)
318 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextLayout2_iface);
321 static inline struct dwrite_textlayout *impl_layout_form_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
323 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextFormat1_iface);
326 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSink(IDWriteTextAnalysisSink *iface)
328 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSink_iface);
331 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSource(IDWriteTextAnalysisSource *iface)
333 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSource_iface);
336 static inline struct dwrite_textformat *impl_from_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
338 return CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat1_iface);
341 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat*);
343 static inline struct dwrite_trimmingsign *impl_from_IDWriteInlineObject(IDWriteInlineObject *iface)
345 return CONTAINING_RECORD(iface, struct dwrite_trimmingsign, IDWriteInlineObject_iface);
348 static inline struct dwrite_typography *impl_from_IDWriteTypography(IDWriteTypography *iface)
350 return CONTAINING_RECORD(iface, struct dwrite_typography, IDWriteTypography_iface);
353 static inline const char *debugstr_run(const struct regular_layout_run *run)
355 return wine_dbg_sprintf("[%u,%u)", run->descr.textPosition, run->descr.textPosition +
356 run->descr.stringLength);
359 static inline BOOL is_layout_gdi_compatible(struct dwrite_textlayout *layout)
361 return layout->measuringmode != DWRITE_MEASURING_MODE_NATURAL;
364 static inline HRESULT format_set_textalignment(struct dwrite_textformat_data *format, DWRITE_TEXT_ALIGNMENT alignment,
365 BOOL *changed)
367 if ((UINT32)alignment > DWRITE_TEXT_ALIGNMENT_JUSTIFIED)
368 return E_INVALIDARG;
369 if (changed) *changed = format->textalignment != alignment;
370 format->textalignment = alignment;
371 return S_OK;
374 static inline HRESULT format_set_paralignment(struct dwrite_textformat_data *format,
375 DWRITE_PARAGRAPH_ALIGNMENT alignment, BOOL *changed)
377 if ((UINT32)alignment > DWRITE_PARAGRAPH_ALIGNMENT_CENTER)
378 return E_INVALIDARG;
379 if (changed) *changed = format->paralign != alignment;
380 format->paralign = alignment;
381 return S_OK;
384 static inline HRESULT format_set_readingdirection(struct dwrite_textformat_data *format,
385 DWRITE_READING_DIRECTION direction, BOOL *changed)
387 if ((UINT32)direction > DWRITE_READING_DIRECTION_BOTTOM_TO_TOP)
388 return E_INVALIDARG;
389 if (changed) *changed = format->readingdir != direction;
390 format->readingdir = direction;
391 return S_OK;
394 static inline HRESULT format_set_wordwrapping(struct dwrite_textformat_data *format,
395 DWRITE_WORD_WRAPPING wrapping, BOOL *changed)
397 if ((UINT32)wrapping > DWRITE_WORD_WRAPPING_CHARACTER)
398 return E_INVALIDARG;
399 if (changed) *changed = format->wrapping != wrapping;
400 format->wrapping = wrapping;
401 return S_OK;
404 static HRESULT get_fontfallback_from_format(const struct dwrite_textformat_data *format, IDWriteFontFallback **fallback)
406 *fallback = format->fallback;
407 if (*fallback)
408 IDWriteFontFallback_AddRef(*fallback);
409 return S_OK;
412 static HRESULT set_fontfallback_for_format(struct dwrite_textformat_data *format, IDWriteFontFallback *fallback)
414 if (format->fallback)
415 IDWriteFontFallback_Release(format->fallback);
416 format->fallback = fallback;
417 if (fallback)
418 IDWriteFontFallback_AddRef(fallback);
419 return S_OK;
422 static HRESULT format_set_optical_alignment(struct dwrite_textformat_data *format,
423 DWRITE_OPTICAL_ALIGNMENT alignment)
425 if ((UINT32)alignment > DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS)
426 return E_INVALIDARG;
427 format->optical_alignment = alignment;
428 return S_OK;
431 static BOOL is_run_rtl(const struct layout_effective_run *run)
433 return run->run->u.regular.run.bidiLevel & 1;
436 static struct layout_run *alloc_layout_run(enum layout_run_kind kind)
438 struct layout_run *ret;
440 ret = heap_alloc(sizeof(*ret));
441 if (!ret) return NULL;
443 memset(ret, 0, sizeof(*ret));
444 ret->kind = kind;
445 if (kind == LAYOUT_RUN_REGULAR) {
446 ret->u.regular.sa.script = Script_Unknown;
447 ret->u.regular.sa.shapes = DWRITE_SCRIPT_SHAPES_DEFAULT;
450 return ret;
453 static void free_layout_runs(struct dwrite_textlayout *layout)
455 struct layout_run *cur, *cur2;
456 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->runs, struct layout_run, entry) {
457 list_remove(&cur->entry);
458 if (cur->kind == LAYOUT_RUN_REGULAR) {
459 if (cur->u.regular.run.fontFace)
460 IDWriteFontFace_Release(cur->u.regular.run.fontFace);
461 heap_free(cur->u.regular.glyphs);
462 heap_free(cur->u.regular.clustermap);
463 heap_free(cur->u.regular.advances);
464 heap_free(cur->u.regular.offsets);
466 heap_free(cur);
470 static void free_layout_eruns(struct dwrite_textlayout *layout)
472 struct layout_effective_inline *in, *in2;
473 struct layout_effective_run *cur, *cur2;
474 struct layout_strikethrough *s, *s2;
475 struct layout_underline *u, *u2;
477 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->eruns, struct layout_effective_run, entry) {
478 list_remove(&cur->entry);
479 heap_free(cur->clustermap);
480 heap_free(cur);
483 LIST_FOR_EACH_ENTRY_SAFE(in, in2, &layout->inlineobjects, struct layout_effective_inline, entry) {
484 list_remove(&in->entry);
485 heap_free(in);
488 LIST_FOR_EACH_ENTRY_SAFE(u, u2, &layout->underlines, struct layout_underline, entry) {
489 list_remove(&u->entry);
490 heap_free(u);
493 LIST_FOR_EACH_ENTRY_SAFE(s, s2, &layout->strikethrough, struct layout_strikethrough, entry) {
494 list_remove(&s->entry);
495 heap_free(s);
499 /* Used to resolve break condition by forcing stronger condition over weaker. */
500 static inline DWRITE_BREAK_CONDITION override_break_condition(DWRITE_BREAK_CONDITION existingbreak, DWRITE_BREAK_CONDITION newbreak)
502 switch (existingbreak) {
503 case DWRITE_BREAK_CONDITION_NEUTRAL:
504 return newbreak;
505 case DWRITE_BREAK_CONDITION_CAN_BREAK:
506 return newbreak == DWRITE_BREAK_CONDITION_NEUTRAL ? existingbreak : newbreak;
507 /* let's keep stronger conditions as is */
508 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK:
509 case DWRITE_BREAK_CONDITION_MUST_BREAK:
510 break;
511 default:
512 ERR("unknown break condition %d\n", existingbreak);
515 return existingbreak;
518 /* This helper should be used to get effective range length, in other words it returns number of text
519 positions from range starting point to the end of the range, limited by layout text length */
520 static inline UINT32 get_clipped_range_length(const struct dwrite_textlayout *layout, const struct layout_range *range)
522 if (range->h.range.startPosition + range->h.range.length <= layout->len)
523 return range->h.range.length;
524 return layout->len - range->h.range.startPosition;
527 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
528 static HRESULT layout_update_breakpoints_range(struct dwrite_textlayout *layout, const struct layout_range *cur)
530 DWRITE_BREAK_CONDITION before, after;
531 UINT32 i, length;
532 HRESULT hr;
534 /* ignore returned conditions if failed */
535 hr = IDWriteInlineObject_GetBreakConditions(cur->object, &before, &after);
536 if (FAILED(hr))
537 after = before = DWRITE_BREAK_CONDITION_NEUTRAL;
539 if (!layout->actual_breakpoints) {
540 layout->actual_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
541 if (!layout->actual_breakpoints)
542 return E_OUTOFMEMORY;
543 memcpy(layout->actual_breakpoints, layout->nominal_breakpoints, sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
546 length = get_clipped_range_length(layout, cur);
547 for (i = cur->h.range.startPosition; i < length + cur->h.range.startPosition; i++) {
548 /* for first codepoint check if there's anything before it and update accordingly */
549 if (i == cur->h.range.startPosition) {
550 if (i > 0)
551 layout->actual_breakpoints[i].breakConditionBefore = layout->actual_breakpoints[i-1].breakConditionAfter =
552 override_break_condition(layout->actual_breakpoints[i-1].breakConditionAfter, before);
553 else
554 layout->actual_breakpoints[i].breakConditionBefore = before;
555 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
557 /* similar check for last codepoint */
558 else if (i == cur->h.range.startPosition + length - 1) {
559 if (i == layout->len - 1)
560 layout->actual_breakpoints[i].breakConditionAfter = after;
561 else
562 layout->actual_breakpoints[i].breakConditionAfter = layout->actual_breakpoints[i+1].breakConditionBefore =
563 override_break_condition(layout->actual_breakpoints[i+1].breakConditionBefore, after);
564 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
566 /* for all positions within a range disable breaks */
567 else {
568 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
569 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
572 layout->actual_breakpoints[i].isWhitespace = FALSE;
573 layout->actual_breakpoints[i].isSoftHyphen = FALSE;
576 return S_OK;
579 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos);
581 static inline DWRITE_LINE_BREAKPOINT get_effective_breakpoint(const struct dwrite_textlayout *layout, UINT32 pos)
583 if (layout->actual_breakpoints)
584 return layout->actual_breakpoints[pos];
585 return layout->nominal_breakpoints[pos];
588 static inline void init_cluster_metrics(const struct dwrite_textlayout *layout, const struct regular_layout_run *run,
589 UINT16 start_glyph, UINT16 stop_glyph, UINT32 stop_position, UINT16 length, DWRITE_CLUSTER_METRICS *metrics)
591 UINT8 breakcondition;
592 UINT32 position;
593 UINT16 j;
595 /* For clusters made of control chars we report zero glyphs, and we need zero cluster
596 width as well; advances are already computed at this point and are not necessary zero. */
597 metrics->width = 0.0f;
598 if (run->run.glyphCount) {
599 for (j = start_glyph; j < stop_glyph; j++)
600 metrics->width += run->run.glyphAdvances[j];
602 metrics->length = length;
604 position = run->descr.textPosition + stop_position;
605 if (stop_glyph == run->glyphcount)
606 breakcondition = get_effective_breakpoint(layout, position).breakConditionAfter;
607 else {
608 breakcondition = get_effective_breakpoint(layout, position).breakConditionBefore;
609 if (stop_position) position -= 1;
612 metrics->canWrapLineAfter = breakcondition == DWRITE_BREAK_CONDITION_CAN_BREAK ||
613 breakcondition == DWRITE_BREAK_CONDITION_MUST_BREAK;
614 if (metrics->length == 1) {
615 DWRITE_LINE_BREAKPOINT bp = get_effective_breakpoint(layout, position);
616 metrics->isWhitespace = bp.isWhitespace;
617 metrics->isNewline = FALSE /* FIXME */;
618 metrics->isSoftHyphen = bp.isSoftHyphen;
620 else {
621 metrics->isWhitespace = FALSE;
622 metrics->isNewline = FALSE;
623 metrics->isSoftHyphen = FALSE;
625 metrics->isRightToLeft = run->run.bidiLevel & 1;
626 metrics->padding = 0;
631 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
632 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
633 Note that there's no need to reallocate anything at this point as we allocate one cluster per
634 codepoint initially.
637 static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 *cluster)
639 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[*cluster];
640 struct layout_cluster *c = &layout->clusters[*cluster];
641 const struct regular_layout_run *run = &r->u.regular;
642 UINT32 i, start = 0;
644 for (i = 0; i < run->descr.stringLength; i++) {
645 BOOL end = i == run->descr.stringLength - 1;
647 if (run->descr.clusterMap[start] != run->descr.clusterMap[i]) {
648 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->descr.clusterMap[i], i,
649 i - start, metrics);
650 c->position = start;
651 c->run = r;
653 *cluster += 1;
654 metrics++;
655 c++;
656 start = i;
659 if (end) {
660 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->glyphcount, i,
661 i - start + 1, metrics);
662 c->position = start;
663 c->run = r;
665 *cluster += 1;
666 return;
671 #define SCALE_FONT_METRIC(metric, emSize, metrics) ((FLOAT)(metric) * (emSize) / (FLOAT)(metrics)->designUnitsPerEm)
673 static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
675 IDWriteTextAnalyzer *analyzer;
676 struct layout_range *range;
677 struct layout_run *r;
678 UINT32 cluster = 0;
679 HRESULT hr;
681 free_layout_eruns(layout);
682 free_layout_runs(layout);
684 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
685 if (!layout->clustermetrics) {
686 layout->clustermetrics = heap_alloc(layout->len*sizeof(*layout->clustermetrics));
687 layout->clusters = heap_alloc(layout->len*sizeof(*layout->clusters));
688 if (!layout->clustermetrics || !layout->clusters) {
689 heap_free(layout->clustermetrics);
690 heap_free(layout->clusters);
691 return E_OUTOFMEMORY;
694 layout->cluster_count = 0;
696 hr = get_textanalyzer(&analyzer);
697 if (FAILED(hr))
698 return hr;
700 LIST_FOR_EACH_ENTRY(range, &layout->ranges, struct layout_range, h.entry) {
701 /* we don't care about ranges that don't contain any text */
702 if (range->h.range.startPosition >= layout->len)
703 break;
705 /* inline objects override actual text in a range */
706 if (range->object) {
707 hr = layout_update_breakpoints_range(layout, range);
708 if (FAILED(hr))
709 return hr;
711 r = alloc_layout_run(LAYOUT_RUN_INLINE);
712 if (!r)
713 return E_OUTOFMEMORY;
715 r->u.object.object = range->object;
716 r->u.object.length = get_clipped_range_length(layout, range);
717 list_add_tail(&layout->runs, &r->entry);
718 continue;
721 /* initial splitting by script */
722 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, &layout->IDWriteTextAnalysisSource_iface,
723 range->h.range.startPosition, get_clipped_range_length(layout, range), &layout->IDWriteTextAnalysisSink_iface);
724 if (FAILED(hr))
725 break;
727 /* this splits it further */
728 hr = IDWriteTextAnalyzer_AnalyzeBidi(analyzer, &layout->IDWriteTextAnalysisSource_iface,
729 range->h.range.startPosition, get_clipped_range_length(layout, range), &layout->IDWriteTextAnalysisSink_iface);
730 if (FAILED(hr))
731 break;
734 /* fill run info */
735 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
736 DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props = NULL;
737 DWRITE_SHAPING_TEXT_PROPERTIES *text_props = NULL;
738 struct regular_layout_run *run = &r->u.regular;
739 DWRITE_FONT_METRICS fontmetrics = { 0 };
740 IDWriteFontFamily *family;
741 UINT32 index, max_count;
742 IDWriteFont *font;
743 BOOL exists = TRUE;
745 /* we need to do very little in case of inline objects */
746 if (r->kind == LAYOUT_RUN_INLINE) {
747 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[cluster];
748 struct layout_cluster *c = &layout->clusters[cluster];
749 DWRITE_INLINE_OBJECT_METRICS inlinemetrics;
751 metrics->width = 0.0f;
752 metrics->length = r->u.object.length;
753 metrics->canWrapLineAfter = FALSE;
754 metrics->isWhitespace = FALSE;
755 metrics->isNewline = FALSE;
756 metrics->isSoftHyphen = FALSE;
757 metrics->isRightToLeft = FALSE;
758 metrics->padding = 0;
759 c->run = r;
760 c->position = 0; /* there's always one cluster per inline object, so 0 is valid value */
761 cluster++;
763 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
764 hr = IDWriteInlineObject_GetMetrics(r->u.object.object, &inlinemetrics);
765 if (FAILED(hr)) {
766 memset(&inlinemetrics, 0, sizeof(inlinemetrics));
767 hr = S_OK;
769 metrics->width = inlinemetrics.width;
770 r->baseline = inlinemetrics.baseline;
771 r->height = inlinemetrics.height;
773 /* FIXME: use resolved breakpoints in this case too */
775 continue;
778 range = get_layout_range_by_pos(layout, run->descr.textPosition);
780 hr = IDWriteFontCollection_FindFamilyName(range->collection, range->fontfamily, &index, &exists);
781 if (FAILED(hr) || !exists) {
782 WARN("%s: family %s not found in collection %p\n", debugstr_run(run), debugstr_w(range->fontfamily), range->collection);
783 continue;
786 hr = IDWriteFontCollection_GetFontFamily(range->collection, index, &family);
787 if (FAILED(hr))
788 continue;
790 hr = IDWriteFontFamily_GetFirstMatchingFont(family, range->weight, range->stretch, range->style, &font);
791 IDWriteFontFamily_Release(family);
792 if (FAILED(hr)) {
793 WARN("%s: failed to get a matching font\n", debugstr_run(run));
794 continue;
797 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
798 IDWriteFont_Release(font);
799 if (FAILED(hr))
800 continue;
802 run->run.fontEmSize = range->fontsize;
803 run->descr.localeName = range->locale;
804 run->clustermap = heap_alloc(run->descr.stringLength*sizeof(UINT16));
806 max_count = 3*run->descr.stringLength/2 + 16;
807 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
808 if (!run->clustermap || !run->glyphs)
809 goto memerr;
811 text_props = heap_alloc(run->descr.stringLength*sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
812 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
813 if (!text_props || !glyph_props)
814 goto memerr;
816 while (1) {
817 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, run->descr.string, run->descr.stringLength,
818 run->run.fontFace, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
819 NULL /* FIXME */, NULL, NULL, 0, max_count, run->clustermap, text_props, run->glyphs, glyph_props,
820 &run->glyphcount);
821 if (hr == E_NOT_SUFFICIENT_BUFFER) {
822 heap_free(run->glyphs);
823 heap_free(glyph_props);
825 max_count = run->glyphcount;
827 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
828 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
829 if (!run->glyphs || !glyph_props)
830 goto memerr;
832 continue;
835 break;
838 if (FAILED(hr)) {
839 heap_free(text_props);
840 heap_free(glyph_props);
841 WARN("%s: shaping failed 0x%08x\n", debugstr_run(run), hr);
842 continue;
845 run->run.glyphIndices = run->glyphs;
846 run->descr.clusterMap = run->clustermap;
848 run->advances = heap_alloc(run->glyphcount*sizeof(FLOAT));
849 run->offsets = heap_alloc(run->glyphcount*sizeof(DWRITE_GLYPH_OFFSET));
850 if (!run->advances || !run->offsets)
851 goto memerr;
853 /* now set advances and offsets */
854 if (is_layout_gdi_compatible(layout))
855 hr = IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap,
856 text_props, run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount,
857 run->run.fontFace, run->run.fontEmSize, layout->ppdip, &layout->transform,
858 layout->measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->run.isSideways,
859 run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL, NULL, 0, run->advances, run->offsets);
860 else
861 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap, text_props,
862 run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount, run->run.fontFace,
863 run->run.fontEmSize, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
864 NULL, NULL, 0, run->advances, run->offsets);
866 heap_free(text_props);
867 heap_free(glyph_props);
868 if (FAILED(hr))
869 WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_run(run), hr);
871 run->run.glyphAdvances = run->advances;
872 run->run.glyphOffsets = run->offsets;
874 /* Special treatment of control script, shaping code adds normal glyphs for it,
875 with non-zero advances, and layout code exposes those as zero width clusters,
876 so we have to do it manually. */
877 if (run->sa.script == Script_Common)
878 run->run.glyphCount = 0;
879 else
880 run->run.glyphCount = run->glyphcount;
882 /* baseline derived from font metrics */
883 if (is_layout_gdi_compatible(layout)) {
884 hr = IDWriteFontFace_GetGdiCompatibleMetrics(run->run.fontFace,
885 run->run.fontEmSize,
886 layout->ppdip,
887 &layout->transform,
888 &fontmetrics);
889 if (FAILED(hr))
890 WARN("failed to get compat metrics, 0x%08x\n", hr);
892 else
893 IDWriteFontFace_GetMetrics(run->run.fontFace, &fontmetrics);
895 r->baseline = SCALE_FONT_METRIC(fontmetrics.ascent, run->run.fontEmSize, &fontmetrics);
896 r->height = SCALE_FONT_METRIC(fontmetrics.ascent + fontmetrics.descent, run->run.fontEmSize, &fontmetrics);
898 layout_set_cluster_metrics(layout, r, &cluster);
900 continue;
902 memerr:
903 heap_free(text_props);
904 heap_free(glyph_props);
905 heap_free(run->clustermap);
906 heap_free(run->glyphs);
907 heap_free(run->advances);
908 heap_free(run->offsets);
909 run->advances = NULL;
910 run->offsets = NULL;
911 run->clustermap = run->glyphs = NULL;
912 hr = E_OUTOFMEMORY;
913 break;
916 if (hr == S_OK) {
917 layout->cluster_count = cluster;
918 if (cluster)
919 layout->clustermetrics[cluster-1].canWrapLineAfter = TRUE;
922 IDWriteTextAnalyzer_Release(analyzer);
923 return hr;
926 static HRESULT layout_compute(struct dwrite_textlayout *layout)
928 HRESULT hr;
930 if (!(layout->recompute & RECOMPUTE_NOMINAL_RUNS))
931 return S_OK;
933 /* nominal breakpoints are evaluated only once, because string never changes */
934 if (!layout->nominal_breakpoints) {
935 IDWriteTextAnalyzer *analyzer;
936 HRESULT hr;
938 layout->nominal_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
939 if (!layout->nominal_breakpoints)
940 return E_OUTOFMEMORY;
942 hr = get_textanalyzer(&analyzer);
943 if (FAILED(hr))
944 return hr;
946 hr = IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer, &layout->IDWriteTextAnalysisSource_iface,
947 0, layout->len, &layout->IDWriteTextAnalysisSink_iface);
948 IDWriteTextAnalyzer_Release(analyzer);
950 if (layout->actual_breakpoints) {
951 heap_free(layout->actual_breakpoints);
952 layout->actual_breakpoints = NULL;
955 hr = layout_compute_runs(layout);
957 if (TRACE_ON(dwrite)) {
958 struct layout_run *cur;
960 LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
961 if (cur->kind == LAYOUT_RUN_INLINE)
962 TRACE("run inline object %p, len %u\n", cur->u.object.object, cur->u.object.length);
963 else
964 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur->u.regular.descr.textPosition, cur->u.regular.descr.textPosition +
965 cur->u.regular.descr.stringLength-1, cur->u.regular.descr.stringLength, cur->u.regular.run.bidiLevel);
969 layout->recompute &= ~RECOMPUTE_NOMINAL_RUNS;
970 return hr;
973 static inline FLOAT get_cluster_range_width(struct dwrite_textlayout *layout, UINT32 start, UINT32 end)
975 FLOAT width = 0.0f;
976 for (; start < end; start++)
977 width += layout->clustermetrics[start].width;
978 return width;
981 static struct layout_range_header *get_layout_range_header_by_pos(struct list *ranges, UINT32 pos)
983 struct layout_range_header *cur;
985 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
986 DWRITE_TEXT_RANGE *r = &cur->range;
987 if (r->startPosition <= pos && pos < r->startPosition + r->length)
988 return cur;
991 return NULL;
994 static inline IUnknown *layout_get_effect_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
996 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->effects, pos);
997 return ((struct layout_range_iface*)h)->iface;
1000 static inline BOOL layout_is_erun_rtl(const struct layout_effective_run *erun)
1002 return erun->run->u.regular.run.bidiLevel & 1;
1005 /* A set of parameters that additionally splits resulting runs. It happens after shaping and all text processing,
1006 no glyph changes are possible. It's understandable for drawing effects, because DrawGlyphRun() reports them as
1007 one of the arguments, but it also happens for decorations, so every effective run has uniform
1008 underline/strikethough/effect tuple. */
1009 struct layout_final_splitting_params {
1010 BOOL strikethrough;
1011 BOOL underline;
1012 IUnknown *effect;
1015 static inline BOOL layout_get_strikethrough_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1017 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->strike_ranges, pos);
1018 return ((struct layout_range_bool*)h)->value;
1021 static inline BOOL layout_get_underline_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1023 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->underline_ranges, pos);
1024 return ((struct layout_range_bool*)h)->value;
1027 static void layout_splitting_params_from_pos(struct dwrite_textlayout *layout, UINT32 pos,
1028 struct layout_final_splitting_params *params)
1030 params->strikethrough = layout_get_strikethrough_from_pos(layout, pos);
1031 params->underline = layout_get_underline_from_pos(layout, pos);
1032 params->effect = layout_get_effect_from_pos(layout, pos);
1035 static BOOL is_same_splitting_params(const struct layout_final_splitting_params *left,
1036 const struct layout_final_splitting_params *right)
1038 return left->strikethrough == right->strikethrough &&
1039 left->underline == right->underline &&
1040 left->effect == right->effect;
1043 static void layout_get_erun_font_metrics(struct dwrite_textlayout *layout, struct layout_effective_run *erun,
1044 DWRITE_FONT_METRICS *metrics)
1046 memset(metrics, 0, sizeof(*metrics));
1047 if (is_layout_gdi_compatible(layout)) {
1048 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(
1049 erun->run->u.regular.run.fontFace,
1050 erun->run->u.regular.run.fontEmSize,
1051 layout->ppdip,
1052 &layout->transform,
1053 metrics);
1054 if (FAILED(hr))
1055 WARN("failed to get font metrics, 0x%08x\n", hr);
1057 else
1058 IDWriteFontFace_GetMetrics(erun->run->u.regular.run.fontFace, metrics);
1061 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
1062 'cluster_count' indicates how many clusters to add, including first one. */
1063 static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 first_cluster,
1064 UINT32 cluster_count, UINT32 line, FLOAT origin_x, struct layout_final_splitting_params *params)
1066 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1067 UINT32 i, start, length, last_cluster;
1068 struct layout_effective_run *run;
1070 if (r->kind == LAYOUT_RUN_INLINE) {
1071 struct layout_effective_inline *inlineobject;
1073 inlineobject = heap_alloc(sizeof(*inlineobject));
1074 if (!inlineobject)
1075 return E_OUTOFMEMORY;
1077 inlineobject->object = r->u.object.object;
1078 inlineobject->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1079 inlineobject->origin_x = is_rtl ? origin_x - inlineobject->width : origin_x;
1080 inlineobject->origin_y = 0.0f; /* set after line is built */
1081 inlineobject->align_dx = 0.0f;
1083 /* It's not clear how these two are set, possibly directionality
1084 is derived from surrounding text (replaced text could have
1085 different ranges which differ in reading direction). */
1086 inlineobject->is_sideways = FALSE;
1087 inlineobject->is_rtl = FALSE;
1088 inlineobject->line = line;
1090 /* effect assigned from start position and on is used for inline objects */
1091 inlineobject->effect = layout_get_effect_from_pos(layout, layout->clusters[first_cluster].position);
1093 list_add_tail(&layout->inlineobjects, &inlineobject->entry);
1094 return S_OK;
1097 run = heap_alloc(sizeof(*run));
1098 if (!run)
1099 return E_OUTOFMEMORY;
1101 /* No need to iterate for that, use simple fact that:
1102 <last cluster position> = first cluster position> + <sum of cluster lengths not including last one> */
1103 last_cluster = first_cluster + cluster_count - 1;
1104 length = layout->clusters[last_cluster].position - layout->clusters[first_cluster].position +
1105 layout->clustermetrics[last_cluster].length;
1107 run->clustermap = heap_alloc(sizeof(UINT16)*length);
1108 if (!run->clustermap) {
1109 heap_free(run);
1110 return E_OUTOFMEMORY;
1113 run->run = r;
1114 run->start = start = layout->clusters[first_cluster].position;
1115 run->length = length;
1116 run->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1118 /* Check if run direction matches paragraph direction, if it doesn't adjust by
1119 run width */
1120 if (layout_is_erun_rtl(run) ^ is_rtl)
1121 run->origin_x = is_rtl ? origin_x - run->width : origin_x + run->width;
1122 else
1123 run->origin_x = origin_x;
1125 run->origin_y = 0.0f; /* set after line is built */
1126 run->align_dx = 0.0f;
1127 run->line = line;
1129 if (r->u.regular.run.glyphCount) {
1130 /* trim from the left */
1131 run->glyphcount = r->u.regular.run.glyphCount - r->u.regular.clustermap[start];
1132 /* trim from the right */
1133 if (start + length < r->u.regular.descr.stringLength - 1)
1134 run->glyphcount -= r->u.regular.run.glyphCount - r->u.regular.clustermap[start + length];
1136 else
1137 run->glyphcount = 0;
1139 /* cluster map needs to be shifted */
1140 for (i = 0; i < length; i++)
1141 run->clustermap[i] = r->u.regular.clustermap[start + i] - r->u.regular.clustermap[start];
1143 run->effect = params->effect;
1144 run->underlined = params->underline;
1145 list_add_tail(&layout->eruns, &run->entry);
1147 /* Strikethrough style is guaranteed to be consistent within effective run,
1148 its width equals to run width, thickness and offset are derived from
1149 font metrics, rest of the values are from layout or run itself */
1150 if (params->strikethrough) {
1151 struct layout_strikethrough *s;
1152 DWRITE_FONT_METRICS metrics;
1154 s = heap_alloc(sizeof(*s));
1155 if (!s)
1156 return E_OUTOFMEMORY;
1158 layout_get_erun_font_metrics(layout, run, &metrics);
1159 s->s.width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1160 s->s.thickness = SCALE_FONT_METRIC(metrics.strikethroughThickness, r->u.regular.run.fontEmSize, &metrics);
1161 /* Negative offset moves it above baseline as Y coordinate grows downward. */
1162 s->s.offset = -SCALE_FONT_METRIC(metrics.strikethroughPosition, r->u.regular.run.fontEmSize, &metrics);
1163 s->s.readingDirection = layout->format.readingdir;
1164 s->s.flowDirection = layout->format.flow;
1165 s->s.localeName = r->u.regular.descr.localeName;
1166 s->s.measuringMode = layout->measuringmode;
1167 s->run = run;
1169 list_add_tail(&layout->strikethrough, &s->entry);
1172 return S_OK;
1175 static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_LINE_METRICS *metrics, UINT32 *line)
1177 if (!layout->line_alloc) {
1178 layout->line_alloc = 5;
1179 layout->lines = heap_alloc(layout->line_alloc*sizeof(*layout->lines));
1180 if (!layout->lines)
1181 return E_OUTOFMEMORY;
1184 if (layout->metrics.lineCount == layout->line_alloc) {
1185 DWRITE_LINE_METRICS *l = heap_realloc(layout->lines, layout->line_alloc*2*sizeof(*layout->lines));
1186 if (!l)
1187 return E_OUTOFMEMORY;
1188 layout->lines = l;
1189 layout->line_alloc *= 2;
1192 layout->lines[*line] = *metrics;
1193 layout->metrics.lineCount += 1;
1194 *line += 1;
1195 return S_OK;
1199 static inline struct layout_effective_run *layout_get_next_erun(struct dwrite_textlayout *layout,
1200 const struct layout_effective_run *cur)
1202 struct list *e;
1204 if (!cur)
1205 e = list_head(&layout->eruns);
1206 else
1207 e = list_next(&layout->eruns, &cur->entry);
1208 if (!e)
1209 return NULL;
1210 return LIST_ENTRY(e, struct layout_effective_run, entry);
1213 static inline struct layout_effective_run *layout_get_prev_erun(struct dwrite_textlayout *layout,
1214 const struct layout_effective_run *cur)
1216 struct list *e;
1218 if (!cur)
1219 e = list_tail(&layout->eruns);
1220 else
1221 e = list_prev(&layout->eruns, &cur->entry);
1222 if (!e)
1223 return NULL;
1224 return LIST_ENTRY(e, struct layout_effective_run, entry);
1227 static inline struct layout_effective_inline *layout_get_next_inline_run(struct dwrite_textlayout *layout,
1228 const struct layout_effective_inline *cur)
1230 struct list *e;
1232 if (!cur)
1233 e = list_head(&layout->inlineobjects);
1234 else
1235 e = list_next(&layout->inlineobjects, &cur->entry);
1236 if (!e)
1237 return NULL;
1238 return LIST_ENTRY(e, struct layout_effective_inline, entry);
1241 static FLOAT layout_get_line_width(struct dwrite_textlayout *layout,
1242 struct layout_effective_run *erun, struct layout_effective_inline *inrun, UINT32 line)
1244 FLOAT width = 0.0f;
1246 while (erun && erun->line == line) {
1247 width += erun->width;
1248 erun = layout_get_next_erun(layout, erun);
1249 if (!erun)
1250 break;
1253 while (inrun && inrun->line == line) {
1254 width += inrun->width;
1255 inrun = layout_get_next_inline_run(layout, inrun);
1256 if (!inrun)
1257 break;
1260 return width;
1263 static inline BOOL should_skip_transform(const DWRITE_MATRIX *m, FLOAT *det)
1265 *det = m->m11 * m->m22 - m->m12 * m->m21;
1266 /* on certain conditions we can skip transform */
1267 return (!memcmp(m, &identity, sizeof(*m)) || fabsf(*det) <= 1e-10f);
1270 static inline void layout_apply_snapping(struct dwrite_vec *vec, BOOL skiptransform, FLOAT ppdip,
1271 const DWRITE_MATRIX *m, FLOAT det)
1273 if (!skiptransform) {
1274 FLOAT vec2[2];
1276 /* apply transform */
1277 vec->x *= ppdip;
1278 vec->y *= ppdip;
1280 vec2[0] = m->m11 * vec->x + m->m21 * vec->y + m->dx;
1281 vec2[1] = m->m12 * vec->x + m->m22 * vec->y + m->dy;
1283 /* snap */
1284 vec2[0] = floorf(vec2[0] + 0.5f);
1285 vec2[1] = floorf(vec2[1] + 0.5f);
1287 /* apply inverted transform, we don't care about X component at this point */
1288 vec->x = (m->m22 * vec2[0] - m->m21 * vec2[1] + m->m21 * m->dy - m->m22 * m->dx) / det;
1289 vec->x /= ppdip;
1291 vec->y = (-m->m12 * vec2[0] + m->m11 * vec2[1] - (m->m11 * m->dy - m->m12 * m->dx)) / det;
1292 vec->y /= ppdip;
1294 else {
1295 vec->x = floorf(vec->x * ppdip + 0.5f) / ppdip;
1296 vec->y = floorf(vec->y * ppdip + 0.5f) / ppdip;
1300 static void layout_apply_leading_alignment(struct dwrite_textlayout *layout)
1302 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1303 struct layout_effective_inline *inrun;
1304 struct layout_effective_run *erun;
1306 erun = layout_get_next_erun(layout, NULL);
1307 inrun = layout_get_next_inline_run(layout, NULL);
1309 while (erun) {
1310 erun->align_dx = 0.0f;
1311 erun = layout_get_next_erun(layout, erun);
1314 while (inrun) {
1315 inrun->align_dx = 0.0f;
1316 inrun = layout_get_next_inline_run(layout, inrun);
1319 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
1322 static void layout_apply_trailing_alignment(struct dwrite_textlayout *layout)
1324 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1325 struct layout_effective_inline *inrun;
1326 struct layout_effective_run *erun;
1327 UINT32 line;
1329 erun = layout_get_next_erun(layout, NULL);
1330 inrun = layout_get_next_inline_run(layout, NULL);
1332 for (line = 0; line < layout->metrics.lineCount; line++) {
1333 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1334 FLOAT shift = layout->metrics.layoutWidth - width;
1336 if (is_rtl)
1337 shift *= -1.0f;
1339 while (erun && erun->line == line) {
1340 erun->align_dx = shift;
1341 erun = layout_get_next_erun(layout, erun);
1344 while (inrun && inrun->line == line) {
1345 inrun->align_dx = shift;
1346 inrun = layout_get_next_inline_run(layout, inrun);
1350 layout->metrics.left = is_rtl ? 0.0f : layout->metrics.layoutWidth - layout->metrics.width;
1353 static inline FLOAT layout_get_centered_shift(struct dwrite_textlayout *layout, BOOL skiptransform,
1354 FLOAT width, FLOAT det)
1356 if (is_layout_gdi_compatible(layout)) {
1357 struct dwrite_vec vec = { layout->metrics.layoutWidth - width, 0.0f};
1358 layout_apply_snapping(&vec, skiptransform, layout->ppdip, &layout->transform, det);
1359 return floorf(vec.x / 2.0f);
1361 else
1362 return (layout->metrics.layoutWidth - width) / 2.0f;
1365 static void layout_apply_centered_alignment(struct dwrite_textlayout *layout)
1367 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1368 struct layout_effective_inline *inrun;
1369 struct layout_effective_run *erun;
1370 BOOL skiptransform;
1371 UINT32 line;
1372 FLOAT det;
1374 erun = layout_get_next_erun(layout, NULL);
1375 inrun = layout_get_next_inline_run(layout, NULL);
1377 skiptransform = should_skip_transform(&layout->transform, &det);
1379 for (line = 0; line < layout->metrics.lineCount; line++) {
1380 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1381 FLOAT shift = layout_get_centered_shift(layout, skiptransform, width, det);
1383 if (is_rtl)
1384 shift *= -1.0f;
1386 while (erun && erun->line == line) {
1387 erun->align_dx = shift;
1388 erun = layout_get_next_erun(layout, erun);
1391 while (inrun && inrun->line == line) {
1392 inrun->align_dx = shift;
1393 inrun = layout_get_next_inline_run(layout, inrun);
1397 layout->metrics.left = (layout->metrics.layoutWidth - layout->metrics.width) / 2.0f;
1400 static void layout_apply_text_alignment(struct dwrite_textlayout *layout)
1402 switch (layout->format.textalignment)
1404 case DWRITE_TEXT_ALIGNMENT_LEADING:
1405 layout_apply_leading_alignment(layout);
1406 break;
1407 case DWRITE_TEXT_ALIGNMENT_TRAILING:
1408 layout_apply_trailing_alignment(layout);
1409 break;
1410 case DWRITE_TEXT_ALIGNMENT_CENTER:
1411 layout_apply_centered_alignment(layout);
1412 break;
1413 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED:
1414 FIXME("alignment %d not implemented\n", layout->format.textalignment);
1415 break;
1416 default:
1421 static void layout_apply_par_alignment(struct dwrite_textlayout *layout)
1423 struct layout_effective_inline *inrun;
1424 struct layout_effective_run *erun;
1425 FLOAT origin_y = 0.0f;
1426 UINT32 line;
1428 /* alignment mode defines origin, after that all run origins are updated
1429 the same way */
1431 switch (layout->format.paralign)
1433 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR:
1434 origin_y = 0.0f;
1435 break;
1436 case DWRITE_PARAGRAPH_ALIGNMENT_FAR:
1437 origin_y = layout->metrics.layoutHeight - layout->metrics.height;
1438 break;
1439 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER:
1440 origin_y = (layout->metrics.layoutHeight - layout->metrics.height) / 2.0f;
1441 break;
1442 default:
1446 layout->metrics.top = origin_y;
1448 erun = layout_get_next_erun(layout, NULL);
1449 inrun = layout_get_next_inline_run(layout, NULL);
1450 for (line = 0; line < layout->metrics.lineCount; line++) {
1451 origin_y += layout->lines[line].baseline;
1453 while (erun && erun->line == line) {
1454 erun->origin_y = origin_y;
1455 erun = layout_get_next_erun(layout, erun);
1458 while (inrun && inrun->line == line) {
1459 inrun->origin_y = origin_y;
1460 inrun = layout_get_next_inline_run(layout, inrun);
1465 struct layout_underline_splitting_params {
1466 const WCHAR *locale; /* points to range data, no additional allocation */
1467 IUnknown *effect; /* does not hold another reference */
1470 static void init_u_splitting_params_from_erun(struct layout_effective_run *erun,
1471 struct layout_underline_splitting_params *params)
1473 params->locale = erun->run->u.regular.descr.localeName;
1474 params->effect = erun->effect;
1477 static BOOL is_same_u_splitting(struct layout_underline_splitting_params *left,
1478 struct layout_underline_splitting_params *right)
1480 return left->effect == right->effect && !strcmpiW(left->locale, right->locale);
1483 static HRESULT layout_add_underline(struct dwrite_textlayout *layout, struct layout_effective_run *first,
1484 struct layout_effective_run *last)
1486 struct layout_effective_run *cur;
1487 DWRITE_FONT_METRICS metrics;
1488 FLOAT thickness, offset;
1490 if (first == layout_get_prev_erun(layout, last)) {
1491 layout_get_erun_font_metrics(layout, first, &metrics);
1492 thickness = SCALE_FONT_METRIC(metrics.underlineThickness, first->run->u.regular.run.fontEmSize, &metrics);
1493 offset = SCALE_FONT_METRIC(metrics.underlinePosition, first->run->u.regular.run.fontEmSize, &metrics);
1495 else {
1496 FLOAT width = 0.0f;
1498 /* Single underline is added for consecutive underlined runs. In this case underline parameters are
1499 calculated as weighted average, where run width acts as a weight. */
1500 thickness = offset = 0.0f;
1501 cur = first;
1502 do {
1503 layout_get_erun_font_metrics(layout, cur, &metrics);
1505 thickness += SCALE_FONT_METRIC(metrics.underlineThickness, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
1506 offset += SCALE_FONT_METRIC(metrics.underlinePosition, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
1507 width += cur->width;
1509 cur = layout_get_next_erun(layout, cur);
1510 } while (cur != last);
1512 thickness /= width;
1513 offset /= width;
1516 cur = first;
1517 do {
1518 struct layout_underline_splitting_params params, prev_params;
1519 struct layout_effective_run *next, *w;
1520 struct layout_underline *u;
1522 init_u_splitting_params_from_erun(cur, &prev_params);
1523 while ((next = layout_get_next_erun(layout, cur)) != last) {
1524 init_u_splitting_params_from_erun(next, &params);
1525 if (!is_same_u_splitting(&prev_params, &params))
1526 break;
1527 cur = next;
1530 u = heap_alloc(sizeof(*u));
1531 if (!u)
1532 return E_OUTOFMEMORY;
1534 w = cur;
1535 u->u.width = 0.0f;
1536 while (w != next) {
1537 u->u.width += w->width;
1538 w = layout_get_next_erun(layout, w);
1541 u->u.thickness = thickness;
1542 /* Font metrics convention is to have it negative when below baseline, for rendering
1543 however Y grows from baseline down for horizontal baseline. */
1544 u->u.offset = -offset;
1545 u->u.runHeight = 0.0f; /* FIXME */
1546 u->u.readingDirection = is_run_rtl(cur) ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
1547 DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
1548 u->u.flowDirection = layout->format.flow;
1549 u->u.localeName = cur->run->u.regular.descr.localeName;
1550 u->u.measuringMode = layout->measuringmode;
1551 u->run = cur;
1552 list_add_tail(&layout->underlines, &u->entry);
1554 cur = next;
1555 } while (cur != last);
1557 return S_OK;
1560 static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
1562 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1563 struct layout_final_splitting_params prev_params, params;
1564 struct layout_effective_run *erun, *first_underlined;
1565 struct layout_effective_inline *inrun;
1566 const struct layout_run *run;
1567 DWRITE_LINE_METRICS metrics;
1568 FLOAT width, origin_x, origin_y;
1569 UINT32 i, start, line, textpos;
1570 HRESULT hr;
1572 if (!(layout->recompute & RECOMPUTE_EFFECTIVE_RUNS))
1573 return S_OK;
1575 hr = layout_compute(layout);
1576 if (FAILED(hr))
1577 return hr;
1579 layout->metrics.lineCount = 0;
1580 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0f;
1581 line = 0;
1582 run = layout->clusters[0].run;
1583 memset(&metrics, 0, sizeof(metrics));
1585 layout_splitting_params_from_pos(layout, 0, &params);
1586 prev_params = params;
1588 for (i = 0, start = 0, textpos = 0, width = 0.0f; i < layout->cluster_count; i++) {
1589 BOOL overflow;
1591 layout_splitting_params_from_pos(layout, textpos, &params);
1593 /* switched to next nominal run, at this point all previous pending clusters are already
1594 checked for layout line overflow, so new effective run will fit in current line */
1595 if (run != layout->clusters[i].run || !is_same_splitting_params(&prev_params, &params)) {
1596 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, &prev_params);
1597 if (FAILED(hr))
1598 return hr;
1599 origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) :
1600 get_cluster_range_width(layout, start, i);
1601 run = layout->clusters[i].run;
1602 start = i;
1605 overflow = layout->clustermetrics[i].canWrapLineAfter &&
1606 (width + layout->clustermetrics[i].width > layout->metrics.layoutWidth) &&
1607 (layout->format.wrapping != DWRITE_WORD_WRAPPING_NO_WRAP);
1608 /* check if we got new */
1609 if (overflow ||
1610 layout->clustermetrics[i].isNewline || /* always wrap on new line */
1611 i == layout->cluster_count - 1) /* end of the text */ {
1613 UINT32 strlength, last_cluster, index;
1614 FLOAT descent, trailingspacewidth;
1615 struct layout_final_splitting_params *p;
1617 if (!overflow) {
1618 width += layout->clustermetrics[i].width;
1619 metrics.length += layout->clustermetrics[i].length;
1620 last_cluster = i;
1621 p = &params;
1623 else {
1624 last_cluster = i ? i - 1 : i;
1625 p = &prev_params;
1628 if (i >= start) {
1629 hr = layout_add_effective_run(layout, run, start, last_cluster - start + 1, line, origin_x, p);
1630 if (FAILED(hr))
1631 return hr;
1632 /* we don't need to update origin for next run as we're going to wrap */
1635 /* take a look at clusters we got for this line in reverse order to set
1636 trailing properties for current line */
1637 strlength = metrics.length;
1638 index = last_cluster;
1639 trailingspacewidth = 0.0f;
1640 while (strlength) {
1641 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1643 if (!cluster->isNewline && !cluster->isWhitespace)
1644 break;
1646 if (cluster->isNewline) {
1647 metrics.trailingWhitespaceLength += cluster->length;
1648 metrics.newlineLength += cluster->length;
1651 if (cluster->isWhitespace) {
1652 metrics.trailingWhitespaceLength += cluster->length;
1653 trailingspacewidth += cluster->width;
1656 strlength -= cluster->length;
1657 index--;
1660 /* look for max baseline and descent for this line */
1661 strlength = metrics.length;
1662 index = last_cluster;
1663 metrics.baseline = 0.0f;
1664 descent = 0.0f;
1665 while (strlength) {
1666 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1667 const struct layout_run *cur = layout->clusters[index].run;
1668 FLOAT cur_descent = cur->height - cur->baseline;
1670 if (cur->baseline > metrics.baseline)
1671 metrics.baseline = cur->baseline;
1673 if (cur_descent > descent)
1674 descent = cur_descent;
1676 strlength -= cluster->length;
1677 index--;
1679 metrics.height = descent + metrics.baseline;
1681 if (width > layout->metrics.widthIncludingTrailingWhitespace)
1682 layout->metrics.widthIncludingTrailingWhitespace = width;
1683 if (width - trailingspacewidth > layout->metrics.width)
1684 layout->metrics.width = width - trailingspacewidth;
1686 metrics.isTrimmed = width > layout->metrics.layoutWidth;
1687 hr = layout_set_line_metrics(layout, &metrics, &line);
1688 if (FAILED(hr))
1689 return hr;
1691 width = layout->clustermetrics[i].width;
1692 memset(&metrics, 0, sizeof(metrics));
1693 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0f;
1694 start = i;
1696 else {
1697 metrics.length += layout->clustermetrics[i].length;
1698 width += layout->clustermetrics[i].width;
1701 prev_params = params;
1702 textpos += layout->clustermetrics[i].length;
1705 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0;
1706 layout->metrics.top = 0.0f;
1707 layout->metrics.maxBidiReorderingDepth = 1; /* FIXME */
1708 layout->metrics.height = 0.0f;
1710 /* Now all line info is here, update effective runs positions in flow direction */
1711 erun = layout_get_next_erun(layout, NULL);
1712 first_underlined = erun && erun->underlined ? erun : NULL;
1714 inrun = layout_get_next_inline_run(layout, NULL);
1716 origin_y = 0.0f;
1717 for (line = 0; line < layout->metrics.lineCount; line++) {
1719 origin_y += layout->lines[line].baseline;
1721 /* For all runs on this line */
1722 while (erun && erun->line == line) {
1723 erun->origin_y = origin_y;
1724 erun = layout_get_next_erun(layout, erun);
1726 if (first_underlined && (!erun || !erun->underlined)) {
1727 layout_add_underline(layout, first_underlined, erun);
1728 first_underlined = NULL;
1730 else if (!first_underlined && erun && erun->underlined)
1731 first_underlined = erun;
1734 /* Same for inline runs */
1735 while (inrun && inrun->line == line) {
1736 inrun->origin_y = origin_y;
1737 inrun = layout_get_next_inline_run(layout, inrun);
1740 layout->metrics.height += layout->lines[line].height;
1743 /* initial alignment is always leading */
1744 if (layout->format.textalignment != DWRITE_TEXT_ALIGNMENT_LEADING)
1745 layout_apply_text_alignment(layout);
1747 /* initial paragraph alignment is always near */
1748 if (layout->format.paralign != DWRITE_PARAGRAPH_ALIGNMENT_NEAR)
1749 layout_apply_par_alignment(layout);
1751 layout->metrics.heightIncludingTrailingWhitespace = layout->metrics.height; /* FIXME: not true for vertical text */
1753 layout->recompute &= ~RECOMPUTE_EFFECTIVE_RUNS;
1754 return hr;
1757 static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
1759 struct layout_range_spacing const *range_spacing = (struct layout_range_spacing*)h;
1760 struct layout_range_iface const *range_iface = (struct layout_range_iface*)h;
1761 struct layout_range_bool const *range_bool = (struct layout_range_bool*)h;
1762 struct layout_range const *range = (struct layout_range*)h;
1764 switch (attr) {
1765 case LAYOUT_RANGE_ATTR_WEIGHT:
1766 return range->weight == value->u.weight;
1767 case LAYOUT_RANGE_ATTR_STYLE:
1768 return range->style == value->u.style;
1769 case LAYOUT_RANGE_ATTR_STRETCH:
1770 return range->stretch == value->u.stretch;
1771 case LAYOUT_RANGE_ATTR_FONTSIZE:
1772 return range->fontsize == value->u.fontsize;
1773 case LAYOUT_RANGE_ATTR_INLINE:
1774 return range->object == value->u.object;
1775 case LAYOUT_RANGE_ATTR_EFFECT:
1776 return range_iface->iface == value->u.effect;
1777 case LAYOUT_RANGE_ATTR_UNDERLINE:
1778 return range_bool->value == value->u.underline;
1779 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
1780 return range_bool->value == value->u.strikethrough;
1781 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
1782 return range->pair_kerning == value->u.pair_kerning;
1783 case LAYOUT_RANGE_ATTR_FONTCOLL:
1784 return range->collection == value->u.collection;
1785 case LAYOUT_RANGE_ATTR_LOCALE:
1786 return strcmpiW(range->locale, value->u.locale) == 0;
1787 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1788 return strcmpW(range->fontfamily, value->u.fontfamily) == 0;
1789 case LAYOUT_RANGE_ATTR_SPACING:
1790 return range_spacing->leading == value->u.spacing[0] &&
1791 range_spacing->trailing == value->u.spacing[1] &&
1792 range_spacing->min_advance == value->u.spacing[2];
1793 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
1794 return range_iface->iface == (IUnknown*)value->u.typography;
1795 default:
1799 return FALSE;
1802 static inline BOOL is_same_layout_attributes(struct layout_range_header const *hleft, struct layout_range_header const *hright)
1804 switch (hleft->kind)
1806 case LAYOUT_RANGE_REGULAR:
1808 struct layout_range const *left = (struct layout_range const*)hleft;
1809 struct layout_range const *right = (struct layout_range const*)hright;
1810 return left->weight == right->weight &&
1811 left->style == right->style &&
1812 left->stretch == right->stretch &&
1813 left->fontsize == right->fontsize &&
1814 left->object == right->object &&
1815 left->pair_kerning == right->pair_kerning &&
1816 left->collection == right->collection &&
1817 !strcmpiW(left->locale, right->locale) &&
1818 !strcmpW(left->fontfamily, right->fontfamily);
1820 case LAYOUT_RANGE_UNDERLINE:
1821 case LAYOUT_RANGE_STRIKETHROUGH:
1823 struct layout_range_bool const *left = (struct layout_range_bool const*)hleft;
1824 struct layout_range_bool const *right = (struct layout_range_bool const*)hright;
1825 return left->value == right->value;
1827 case LAYOUT_RANGE_EFFECT:
1828 case LAYOUT_RANGE_TYPOGRAPHY:
1830 struct layout_range_iface const *left = (struct layout_range_iface const*)hleft;
1831 struct layout_range_iface const *right = (struct layout_range_iface const*)hright;
1832 return left->iface == right->iface;
1834 case LAYOUT_RANGE_SPACING:
1836 struct layout_range_spacing const *left = (struct layout_range_spacing const*)hleft;
1837 struct layout_range_spacing const *right = (struct layout_range_spacing const*)hright;
1838 return left->leading == right->leading &&
1839 left->trailing == right->trailing &&
1840 left->min_advance == right->min_advance;
1842 default:
1843 FIXME("unknown range kind %d\n", hleft->kind);
1844 return FALSE;
1848 static inline BOOL is_same_text_range(const DWRITE_TEXT_RANGE *left, const DWRITE_TEXT_RANGE *right)
1850 return left->startPosition == right->startPosition && left->length == right->length;
1853 /* Allocates range and inits it with default values from text format. */
1854 static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout *layout, const DWRITE_TEXT_RANGE *r,
1855 enum layout_range_kind kind)
1857 struct layout_range_header *h;
1859 switch (kind)
1861 case LAYOUT_RANGE_REGULAR:
1863 struct layout_range *range;
1865 range = heap_alloc(sizeof(*range));
1866 if (!range) return NULL;
1868 range->weight = layout->format.weight;
1869 range->style = layout->format.style;
1870 range->stretch = layout->format.stretch;
1871 range->fontsize = layout->format.fontsize;
1872 range->object = NULL;
1873 range->pair_kerning = FALSE;
1875 range->fontfamily = heap_strdupW(layout->format.family_name);
1876 if (!range->fontfamily) {
1877 heap_free(range);
1878 return NULL;
1881 range->collection = layout->format.collection;
1882 if (range->collection)
1883 IDWriteFontCollection_AddRef(range->collection);
1884 strcpyW(range->locale, layout->format.locale);
1886 h = &range->h;
1887 break;
1889 case LAYOUT_RANGE_UNDERLINE:
1890 case LAYOUT_RANGE_STRIKETHROUGH:
1892 struct layout_range_bool *range;
1894 range = heap_alloc(sizeof(*range));
1895 if (!range) return NULL;
1897 range->value = FALSE;
1898 h = &range->h;
1899 break;
1901 case LAYOUT_RANGE_EFFECT:
1902 case LAYOUT_RANGE_TYPOGRAPHY:
1904 struct layout_range_iface *range;
1906 range = heap_alloc(sizeof(*range));
1907 if (!range) return NULL;
1909 range->iface = NULL;
1910 h = &range->h;
1911 break;
1913 case LAYOUT_RANGE_SPACING:
1915 struct layout_range_spacing *range;
1917 range = heap_alloc(sizeof(*range));
1918 if (!range) return NULL;
1920 range->leading = 0.0f;
1921 range->trailing = 0.0f;
1922 range->min_advance = 0.0f;
1923 h = &range->h;
1924 break;
1926 default:
1927 FIXME("unknown range kind %d\n", kind);
1928 return NULL;
1931 h->kind = kind;
1932 h->range = *r;
1933 return h;
1936 static struct layout_range_header *alloc_layout_range_from(struct layout_range_header *h, const DWRITE_TEXT_RANGE *r)
1938 struct layout_range_header *ret;
1940 switch (h->kind)
1942 case LAYOUT_RANGE_REGULAR:
1944 struct layout_range *from = (struct layout_range*)h;
1946 struct layout_range *range = heap_alloc(sizeof(*range));
1947 if (!range) return NULL;
1949 *range = *from;
1950 range->fontfamily = heap_strdupW(from->fontfamily);
1951 if (!range->fontfamily) {
1952 heap_free(range);
1953 return NULL;
1956 /* update refcounts */
1957 if (range->object)
1958 IDWriteInlineObject_AddRef(range->object);
1959 if (range->collection)
1960 IDWriteFontCollection_AddRef(range->collection);
1961 ret = &range->h;
1962 break;
1964 case LAYOUT_RANGE_UNDERLINE:
1965 case LAYOUT_RANGE_STRIKETHROUGH:
1967 struct layout_range_bool *strike = heap_alloc(sizeof(*strike));
1968 if (!strike) return NULL;
1970 *strike = *(struct layout_range_bool*)h;
1971 ret = &strike->h;
1972 break;
1974 case LAYOUT_RANGE_EFFECT:
1975 case LAYOUT_RANGE_TYPOGRAPHY:
1977 struct layout_range_iface *effect = heap_alloc(sizeof(*effect));
1978 if (!effect) return NULL;
1980 *effect = *(struct layout_range_iface*)h;
1981 if (effect->iface)
1982 IUnknown_AddRef(effect->iface);
1983 ret = &effect->h;
1984 break;
1986 case LAYOUT_RANGE_SPACING:
1988 struct layout_range_spacing *spacing = heap_alloc(sizeof(*spacing));
1989 if (!spacing) return NULL;
1991 *spacing = *(struct layout_range_spacing*)h;
1992 ret = &spacing->h;
1993 break;
1995 default:
1996 FIXME("unknown range kind %d\n", h->kind);
1997 return NULL;
2000 ret->range = *r;
2001 return ret;
2004 static void free_layout_range(struct layout_range_header *h)
2006 if (!h)
2007 return;
2009 switch (h->kind)
2011 case LAYOUT_RANGE_REGULAR:
2013 struct layout_range *range = (struct layout_range*)h;
2015 if (range->object)
2016 IDWriteInlineObject_Release(range->object);
2017 if (range->collection)
2018 IDWriteFontCollection_Release(range->collection);
2019 heap_free(range->fontfamily);
2020 break;
2022 case LAYOUT_RANGE_EFFECT:
2023 case LAYOUT_RANGE_TYPOGRAPHY:
2025 struct layout_range_iface *range = (struct layout_range_iface*)h;
2026 if (range->iface)
2027 IUnknown_Release(range->iface);
2028 break;
2030 default:
2034 heap_free(h);
2037 static void free_layout_ranges_list(struct dwrite_textlayout *layout)
2039 struct layout_range_header *cur, *cur2;
2041 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->ranges, struct layout_range_header, entry) {
2042 list_remove(&cur->entry);
2043 free_layout_range(cur);
2046 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->underline_ranges, struct layout_range_header, entry) {
2047 list_remove(&cur->entry);
2048 free_layout_range(cur);
2051 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->strike_ranges, struct layout_range_header, entry) {
2052 list_remove(&cur->entry);
2053 free_layout_range(cur);
2056 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->effects, struct layout_range_header, entry) {
2057 list_remove(&cur->entry);
2058 free_layout_range(cur);
2061 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->spacing, struct layout_range_header, entry) {
2062 list_remove(&cur->entry);
2063 free_layout_range(cur);
2066 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->typographies, struct layout_range_header, entry) {
2067 list_remove(&cur->entry);
2068 free_layout_range(cur);
2072 static struct layout_range_header *find_outer_range(struct list *ranges, const DWRITE_TEXT_RANGE *range)
2074 struct layout_range_header *cur;
2076 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
2078 if (cur->range.startPosition > range->startPosition)
2079 return NULL;
2081 if ((cur->range.startPosition + cur->range.length < range->startPosition + range->length) &&
2082 (range->startPosition < cur->range.startPosition + cur->range.length))
2083 return NULL;
2084 if (cur->range.startPosition + cur->range.length >= range->startPosition + range->length)
2085 return cur;
2088 return NULL;
2091 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos)
2093 struct layout_range *cur;
2095 LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, h.entry) {
2096 DWRITE_TEXT_RANGE *r = &cur->h.range;
2097 if (r->startPosition <= pos && pos < r->startPosition + r->length)
2098 return cur;
2101 return NULL;
2104 static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
2106 if (*dest == value) return FALSE;
2108 if (*dest)
2109 IUnknown_Release(*dest);
2110 *dest = value;
2111 if (*dest)
2112 IUnknown_AddRef(*dest);
2114 return TRUE;
2117 static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2119 struct layout_range_spacing *dest_spacing = (struct layout_range_spacing*)h;
2120 struct layout_range_iface *dest_iface = (struct layout_range_iface*)h;
2121 struct layout_range_bool *dest_bool = (struct layout_range_bool*)h;
2122 struct layout_range *dest = (struct layout_range*)h;
2124 BOOL changed = FALSE;
2126 switch (attr) {
2127 case LAYOUT_RANGE_ATTR_WEIGHT:
2128 changed = dest->weight != value->u.weight;
2129 dest->weight = value->u.weight;
2130 break;
2131 case LAYOUT_RANGE_ATTR_STYLE:
2132 changed = dest->style != value->u.style;
2133 dest->style = value->u.style;
2134 break;
2135 case LAYOUT_RANGE_ATTR_STRETCH:
2136 changed = dest->stretch != value->u.stretch;
2137 dest->stretch = value->u.stretch;
2138 break;
2139 case LAYOUT_RANGE_ATTR_FONTSIZE:
2140 changed = dest->fontsize != value->u.fontsize;
2141 dest->fontsize = value->u.fontsize;
2142 break;
2143 case LAYOUT_RANGE_ATTR_INLINE:
2144 changed = set_layout_range_iface_attr((IUnknown**)&dest->object, (IUnknown*)value->u.object);
2145 break;
2146 case LAYOUT_RANGE_ATTR_EFFECT:
2147 changed = set_layout_range_iface_attr((IUnknown**)&dest_iface->iface, (IUnknown*)value->u.effect);
2148 break;
2149 case LAYOUT_RANGE_ATTR_UNDERLINE:
2150 changed = dest_bool->value != value->u.underline;
2151 dest_bool->value = value->u.underline;
2152 break;
2153 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2154 changed = dest_bool->value != value->u.strikethrough;
2155 dest_bool->value = value->u.strikethrough;
2156 break;
2157 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2158 changed = dest->pair_kerning != value->u.pair_kerning;
2159 dest->pair_kerning = value->u.pair_kerning;
2160 break;
2161 case LAYOUT_RANGE_ATTR_FONTCOLL:
2162 changed = set_layout_range_iface_attr((IUnknown**)&dest->collection, (IUnknown*)value->u.collection);
2163 break;
2164 case LAYOUT_RANGE_ATTR_LOCALE:
2165 changed = strcmpiW(dest->locale, value->u.locale) != 0;
2166 if (changed) {
2167 strcpyW(dest->locale, value->u.locale);
2168 strlwrW(dest->locale);
2170 break;
2171 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2172 changed = strcmpW(dest->fontfamily, value->u.fontfamily) != 0;
2173 if (changed) {
2174 heap_free(dest->fontfamily);
2175 dest->fontfamily = heap_strdupW(value->u.fontfamily);
2177 break;
2178 case LAYOUT_RANGE_ATTR_SPACING:
2179 changed = dest_spacing->leading != value->u.spacing[0] ||
2180 dest_spacing->trailing != value->u.spacing[1] ||
2181 dest_spacing->min_advance != value->u.spacing[2];
2182 dest_spacing->leading = value->u.spacing[0];
2183 dest_spacing->trailing = value->u.spacing[1];
2184 dest_spacing->min_advance = value->u.spacing[2];
2185 break;
2186 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2187 changed = set_layout_range_iface_attr((IUnknown**)&dest_iface->iface, (IUnknown*)value->u.typography);
2188 break;
2189 default:
2193 return changed;
2196 static inline BOOL is_in_layout_range(const DWRITE_TEXT_RANGE *outer, const DWRITE_TEXT_RANGE *inner)
2198 return (inner->startPosition >= outer->startPosition) &&
2199 (inner->startPosition + inner->length <= outer->startPosition + outer->length);
2202 static inline HRESULT return_range(const struct layout_range_header *h, DWRITE_TEXT_RANGE *r)
2204 if (r) *r = h->range;
2205 return S_OK;
2208 /* Sets attribute value for given range, does all needed splitting/merging of existing ranges. */
2209 static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2211 struct layout_range_header *cur, *right, *left, *outer;
2212 BOOL changed = FALSE;
2213 struct list *ranges;
2214 DWRITE_TEXT_RANGE r;
2216 /* ignore zero length ranges */
2217 if (value->range.length == 0)
2218 return S_OK;
2220 /* select from ranges lists */
2221 switch (attr)
2223 case LAYOUT_RANGE_ATTR_WEIGHT:
2224 case LAYOUT_RANGE_ATTR_STYLE:
2225 case LAYOUT_RANGE_ATTR_STRETCH:
2226 case LAYOUT_RANGE_ATTR_FONTSIZE:
2227 case LAYOUT_RANGE_ATTR_INLINE:
2228 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2229 case LAYOUT_RANGE_ATTR_FONTCOLL:
2230 case LAYOUT_RANGE_ATTR_LOCALE:
2231 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2232 ranges = &layout->ranges;
2233 break;
2234 case LAYOUT_RANGE_ATTR_UNDERLINE:
2235 ranges = &layout->underline_ranges;
2236 break;
2237 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2238 ranges = &layout->strike_ranges;
2239 break;
2240 case LAYOUT_RANGE_ATTR_EFFECT:
2241 ranges = &layout->effects;
2242 break;
2243 case LAYOUT_RANGE_ATTR_SPACING:
2244 ranges = &layout->spacing;
2245 break;
2246 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2247 ranges = &layout->typographies;
2248 break;
2249 default:
2250 FIXME("unknown attr kind %d\n", attr);
2251 return E_FAIL;
2254 /* If new range is completely within existing range, split existing range in two */
2255 if ((outer = find_outer_range(ranges, &value->range))) {
2257 /* no need to add same range */
2258 if (is_same_layout_attrvalue(outer, attr, value))
2259 return S_OK;
2261 /* for matching range bounds just replace data */
2262 if (is_same_text_range(&outer->range, &value->range)) {
2263 changed = set_layout_range_attrval(outer, attr, value);
2264 goto done;
2267 /* add new range to the left */
2268 if (value->range.startPosition == outer->range.startPosition) {
2269 left = alloc_layout_range_from(outer, &value->range);
2270 if (!left) return E_OUTOFMEMORY;
2272 changed = set_layout_range_attrval(left, attr, value);
2273 list_add_before(&outer->entry, &left->entry);
2274 outer->range.startPosition += value->range.length;
2275 outer->range.length -= value->range.length;
2276 goto done;
2279 /* add new range to the right */
2280 if (value->range.startPosition + value->range.length == outer->range.startPosition + outer->range.length) {
2281 right = alloc_layout_range_from(outer, &value->range);
2282 if (!right) return E_OUTOFMEMORY;
2284 changed = set_layout_range_attrval(right, attr, value);
2285 list_add_after(&outer->entry, &right->entry);
2286 outer->range.length -= value->range.length;
2287 goto done;
2290 r.startPosition = value->range.startPosition + value->range.length;
2291 r.length = outer->range.length + outer->range.startPosition - r.startPosition;
2293 /* right part */
2294 right = alloc_layout_range_from(outer, &r);
2295 /* new range in the middle */
2296 cur = alloc_layout_range_from(outer, &value->range);
2297 if (!right || !cur) {
2298 free_layout_range(right);
2299 free_layout_range(cur);
2300 return E_OUTOFMEMORY;
2303 /* reuse container range as a left part */
2304 outer->range.length = value->range.startPosition - outer->range.startPosition;
2306 /* new part */
2307 set_layout_range_attrval(cur, attr, value);
2309 list_add_after(&outer->entry, &cur->entry);
2310 list_add_after(&cur->entry, &right->entry);
2312 return S_OK;
2315 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2316 Update all of them. */
2317 left = get_layout_range_header_by_pos(ranges, value->range.startPosition);
2318 if (left->range.startPosition == value->range.startPosition)
2319 changed = set_layout_range_attrval(left, attr, value);
2320 else /* need to split */ {
2321 r.startPosition = value->range.startPosition;
2322 r.length = left->range.length - value->range.startPosition + left->range.startPosition;
2323 left->range.length -= r.length;
2324 cur = alloc_layout_range_from(left, &r);
2325 changed = set_layout_range_attrval(cur, attr, value);
2326 list_add_after(&left->entry, &cur->entry);
2328 cur = LIST_ENTRY(list_next(ranges, &left->entry), struct layout_range_header, entry);
2330 /* for all existing ranges covered by new one update value */
2331 while (cur && is_in_layout_range(&value->range, &cur->range)) {
2332 changed |= set_layout_range_attrval(cur, attr, value);
2333 cur = LIST_ENTRY(list_next(ranges, &cur->entry), struct layout_range_header, entry);
2336 /* it's possible rightmost range intersects */
2337 if (cur && (cur->range.startPosition < value->range.startPosition + value->range.length)) {
2338 r.startPosition = cur->range.startPosition;
2339 r.length = value->range.startPosition + value->range.length - cur->range.startPosition;
2340 left = alloc_layout_range_from(cur, &r);
2341 changed |= set_layout_range_attrval(left, attr, value);
2342 cur->range.startPosition += left->range.length;
2343 cur->range.length -= left->range.length;
2344 list_add_before(&cur->entry, &left->entry);
2347 done:
2348 if (changed) {
2349 struct list *next, *i;
2351 layout->recompute = RECOMPUTE_EVERYTHING;
2352 i = list_head(ranges);
2353 while ((next = list_next(ranges, i))) {
2354 struct layout_range_header *next_range = LIST_ENTRY(next, struct layout_range_header, entry);
2356 cur = LIST_ENTRY(i, struct layout_range_header, entry);
2357 if (is_same_layout_attributes(cur, next_range)) {
2358 /* remove similar range */
2359 cur->range.length += next_range->range.length;
2360 list_remove(next);
2361 free_layout_range(next_range);
2363 else
2364 i = list_next(ranges, i);
2368 return S_OK;
2371 static inline const WCHAR *get_string_attribute_ptr(struct layout_range *range, enum layout_range_attr_kind kind)
2373 const WCHAR *str;
2375 switch (kind) {
2376 case LAYOUT_RANGE_ATTR_LOCALE:
2377 str = range->locale;
2378 break;
2379 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2380 str = range->fontfamily;
2381 break;
2382 default:
2383 str = NULL;
2386 return str;
2389 static HRESULT get_string_attribute_length(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2390 UINT32 *length, DWRITE_TEXT_RANGE *r)
2392 struct layout_range *range;
2393 const WCHAR *str;
2395 range = get_layout_range_by_pos(layout, position);
2396 if (!range) {
2397 *length = 0;
2398 return S_OK;
2401 str = get_string_attribute_ptr(range, kind);
2402 *length = strlenW(str);
2403 return return_range(&range->h, r);
2406 static HRESULT get_string_attribute_value(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2407 WCHAR *ret, UINT32 length, DWRITE_TEXT_RANGE *r)
2409 struct layout_range *range;
2410 const WCHAR *str;
2412 if (length == 0)
2413 return E_INVALIDARG;
2415 ret[0] = 0;
2416 range = get_layout_range_by_pos(layout, position);
2417 if (!range)
2418 return E_INVALIDARG;
2420 str = get_string_attribute_ptr(range, kind);
2421 if (length < strlenW(str) + 1)
2422 return E_NOT_SUFFICIENT_BUFFER;
2424 strcpyW(ret, str);
2425 return return_range(&range->h, r);
2428 static HRESULT WINAPI dwritetextlayout_QueryInterface(IDWriteTextLayout2 *iface, REFIID riid, void **obj)
2430 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2432 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2434 *obj = NULL;
2436 if (IsEqualIID(riid, &IID_IDWriteTextLayout2) ||
2437 IsEqualIID(riid, &IID_IDWriteTextLayout1) ||
2438 IsEqualIID(riid, &IID_IDWriteTextLayout) ||
2439 IsEqualIID(riid, &IID_IUnknown))
2441 *obj = iface;
2443 else if (IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
2444 IsEqualIID(riid, &IID_IDWriteTextFormat))
2445 *obj = &This->IDWriteTextFormat1_iface;
2447 if (*obj) {
2448 IDWriteTextLayout2_AddRef(iface);
2449 return S_OK;
2452 return E_NOINTERFACE;
2455 static ULONG WINAPI dwritetextlayout_AddRef(IDWriteTextLayout2 *iface)
2457 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2458 ULONG ref = InterlockedIncrement(&This->ref);
2459 TRACE("(%p)->(%d)\n", This, ref);
2460 return ref;
2463 static ULONG WINAPI dwritetextlayout_Release(IDWriteTextLayout2 *iface)
2465 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2466 ULONG ref = InterlockedDecrement(&This->ref);
2468 TRACE("(%p)->(%d)\n", This, ref);
2470 if (!ref) {
2471 free_layout_ranges_list(This);
2472 free_layout_eruns(This);
2473 free_layout_runs(This);
2474 release_format_data(&This->format);
2475 heap_free(This->nominal_breakpoints);
2476 heap_free(This->actual_breakpoints);
2477 heap_free(This->clustermetrics);
2478 heap_free(This->clusters);
2479 heap_free(This->lines);
2480 heap_free(This->str);
2481 heap_free(This);
2484 return ref;
2487 static HRESULT WINAPI dwritetextlayout_SetTextAlignment(IDWriteTextLayout2 *iface, DWRITE_TEXT_ALIGNMENT alignment)
2489 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2490 return IDWriteTextFormat1_SetTextAlignment(&This->IDWriteTextFormat1_iface, alignment);
2493 static HRESULT WINAPI dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout2 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
2495 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2496 return IDWriteTextFormat1_SetParagraphAlignment(&This->IDWriteTextFormat1_iface, alignment);
2499 static HRESULT WINAPI dwritetextlayout_SetWordWrapping(IDWriteTextLayout2 *iface, DWRITE_WORD_WRAPPING wrapping)
2501 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2502 return IDWriteTextFormat1_SetWordWrapping(&This->IDWriteTextFormat1_iface, wrapping);
2505 static HRESULT WINAPI dwritetextlayout_SetReadingDirection(IDWriteTextLayout2 *iface, DWRITE_READING_DIRECTION direction)
2507 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2508 return IDWriteTextFormat1_SetReadingDirection(&This->IDWriteTextFormat1_iface, direction);
2511 static HRESULT WINAPI dwritetextlayout_SetFlowDirection(IDWriteTextLayout2 *iface, DWRITE_FLOW_DIRECTION direction)
2513 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2514 TRACE("(%p)->(%d)\n", This, direction);
2515 return IDWriteTextFormat1_SetFlowDirection(&This->IDWriteTextFormat1_iface, direction);
2518 static HRESULT WINAPI dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout2 *iface, FLOAT tabstop)
2520 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2521 TRACE("(%p)->(%.2f)\n", This, tabstop);
2522 return IDWriteTextFormat1_SetIncrementalTabStop(&This->IDWriteTextFormat1_iface, tabstop);
2525 static HRESULT WINAPI dwritetextlayout_SetTrimming(IDWriteTextLayout2 *iface, DWRITE_TRIMMING const *trimming,
2526 IDWriteInlineObject *trimming_sign)
2528 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2529 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
2530 return IDWriteTextFormat1_SetTrimming(&This->IDWriteTextFormat1_iface, trimming, trimming_sign);
2533 static HRESULT WINAPI dwritetextlayout_SetLineSpacing(IDWriteTextLayout2 *iface, DWRITE_LINE_SPACING_METHOD spacing,
2534 FLOAT line_spacing, FLOAT baseline)
2536 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2537 TRACE("(%p)->(%d %.2f %.2f)\n", This, spacing, line_spacing, baseline);
2538 return IDWriteTextFormat1_SetLineSpacing(&This->IDWriteTextFormat1_iface, spacing, line_spacing, baseline);
2541 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextlayout_GetTextAlignment(IDWriteTextLayout2 *iface)
2543 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2544 return IDWriteTextFormat1_GetTextAlignment(&This->IDWriteTextFormat1_iface);
2547 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout2 *iface)
2549 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2550 return IDWriteTextFormat1_GetParagraphAlignment(&This->IDWriteTextFormat1_iface);
2553 static DWRITE_WORD_WRAPPING WINAPI dwritetextlayout_GetWordWrapping(IDWriteTextLayout2 *iface)
2555 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2556 return IDWriteTextFormat1_GetWordWrapping(&This->IDWriteTextFormat1_iface);
2559 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_GetReadingDirection(IDWriteTextLayout2 *iface)
2561 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2562 return IDWriteTextFormat1_GetReadingDirection(&This->IDWriteTextFormat1_iface);
2565 static DWRITE_FLOW_DIRECTION WINAPI dwritetextlayout_GetFlowDirection(IDWriteTextLayout2 *iface)
2567 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2568 return IDWriteTextFormat1_GetFlowDirection(&This->IDWriteTextFormat1_iface);
2571 static FLOAT WINAPI dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout2 *iface)
2573 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2574 return IDWriteTextFormat1_GetIncrementalTabStop(&This->IDWriteTextFormat1_iface);
2577 static HRESULT WINAPI dwritetextlayout_GetTrimming(IDWriteTextLayout2 *iface, DWRITE_TRIMMING *options,
2578 IDWriteInlineObject **trimming_sign)
2580 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2581 return IDWriteTextFormat1_GetTrimming(&This->IDWriteTextFormat1_iface, options, trimming_sign);
2584 static HRESULT WINAPI dwritetextlayout_GetLineSpacing(IDWriteTextLayout2 *iface, DWRITE_LINE_SPACING_METHOD *method,
2585 FLOAT *spacing, FLOAT *baseline)
2587 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2588 return IDWriteTextFormat1_GetLineSpacing(&This->IDWriteTextFormat1_iface, method, spacing, baseline);
2591 static HRESULT WINAPI dwritetextlayout_GetFontCollection(IDWriteTextLayout2 *iface, IDWriteFontCollection **collection)
2593 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2594 return IDWriteTextFormat1_GetFontCollection(&This->IDWriteTextFormat1_iface, collection);
2597 static UINT32 WINAPI dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout2 *iface)
2599 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2600 return IDWriteTextFormat1_GetFontFamilyNameLength(&This->IDWriteTextFormat1_iface);
2603 static HRESULT WINAPI dwritetextlayout_GetFontFamilyName(IDWriteTextLayout2 *iface, WCHAR *name, UINT32 size)
2605 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2606 return IDWriteTextFormat1_GetFontFamilyName(&This->IDWriteTextFormat1_iface, name, size);
2609 static DWRITE_FONT_WEIGHT WINAPI dwritetextlayout_GetFontWeight(IDWriteTextLayout2 *iface)
2611 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2612 return IDWriteTextFormat1_GetFontWeight(&This->IDWriteTextFormat1_iface);
2615 static DWRITE_FONT_STYLE WINAPI dwritetextlayout_GetFontStyle(IDWriteTextLayout2 *iface)
2617 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2618 return IDWriteTextFormat1_GetFontStyle(&This->IDWriteTextFormat1_iface);
2621 static DWRITE_FONT_STRETCH WINAPI dwritetextlayout_GetFontStretch(IDWriteTextLayout2 *iface)
2623 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2624 return IDWriteTextFormat1_GetFontStretch(&This->IDWriteTextFormat1_iface);
2627 static FLOAT WINAPI dwritetextlayout_GetFontSize(IDWriteTextLayout2 *iface)
2629 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2630 return IDWriteTextFormat1_GetFontSize(&This->IDWriteTextFormat1_iface);
2633 static UINT32 WINAPI dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout2 *iface)
2635 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2636 return IDWriteTextFormat1_GetLocaleNameLength(&This->IDWriteTextFormat1_iface);
2639 static HRESULT WINAPI dwritetextlayout_GetLocaleName(IDWriteTextLayout2 *iface, WCHAR *name, UINT32 size)
2641 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2642 return IDWriteTextFormat1_GetLocaleName(&This->IDWriteTextFormat1_iface, name, size);
2645 static HRESULT WINAPI dwritetextlayout_SetMaxWidth(IDWriteTextLayout2 *iface, FLOAT maxWidth)
2647 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2649 TRACE("(%p)->(%.2f)\n", This, maxWidth);
2651 if (maxWidth < 0.0f)
2652 return E_INVALIDARG;
2654 This->metrics.layoutWidth = maxWidth;
2655 return S_OK;
2658 static HRESULT WINAPI dwritetextlayout_SetMaxHeight(IDWriteTextLayout2 *iface, FLOAT maxHeight)
2660 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2662 TRACE("(%p)->(%.2f)\n", This, maxHeight);
2664 if (maxHeight < 0.0f)
2665 return E_INVALIDARG;
2667 This->metrics.layoutHeight = maxHeight;
2668 return S_OK;
2671 static HRESULT WINAPI dwritetextlayout_SetFontCollection(IDWriteTextLayout2 *iface, IDWriteFontCollection* collection, DWRITE_TEXT_RANGE range)
2673 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2674 struct layout_range_attr_value value;
2676 TRACE("(%p)->(%p %s)\n", This, collection, debugstr_range(&range));
2678 value.range = range;
2679 value.u.collection = collection;
2680 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTCOLL, &value);
2683 static HRESULT WINAPI dwritetextlayout_SetFontFamilyName(IDWriteTextLayout2 *iface, WCHAR const *name, DWRITE_TEXT_RANGE range)
2685 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2686 struct layout_range_attr_value value;
2688 TRACE("(%p)->(%s %s)\n", This, debugstr_w(name), debugstr_range(&range));
2690 if (!name)
2691 return E_INVALIDARG;
2693 value.range = range;
2694 value.u.fontfamily = name;
2695 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTFAMILY, &value);
2698 static HRESULT WINAPI dwritetextlayout_SetFontWeight(IDWriteTextLayout2 *iface, DWRITE_FONT_WEIGHT weight, DWRITE_TEXT_RANGE range)
2700 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2701 struct layout_range_attr_value value;
2703 TRACE("(%p)->(%d %s)\n", This, weight, debugstr_range(&range));
2705 value.range = range;
2706 value.u.weight = weight;
2707 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_WEIGHT, &value);
2710 static HRESULT WINAPI dwritetextlayout_SetFontStyle(IDWriteTextLayout2 *iface, DWRITE_FONT_STYLE style, DWRITE_TEXT_RANGE range)
2712 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2713 struct layout_range_attr_value value;
2715 TRACE("(%p)->(%d %s)\n", This, style, debugstr_range(&range));
2717 if ((UINT32)style > DWRITE_FONT_STYLE_ITALIC)
2718 return E_INVALIDARG;
2720 value.range = range;
2721 value.u.style = style;
2722 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STYLE, &value);
2725 static HRESULT WINAPI dwritetextlayout_SetFontStretch(IDWriteTextLayout2 *iface, DWRITE_FONT_STRETCH stretch, DWRITE_TEXT_RANGE range)
2727 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2728 struct layout_range_attr_value value;
2730 TRACE("(%p)->(%d %s)\n", This, stretch, debugstr_range(&range));
2732 if (stretch == DWRITE_FONT_STRETCH_UNDEFINED || (UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
2733 return E_INVALIDARG;
2735 value.range = range;
2736 value.u.stretch = stretch;
2737 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRETCH, &value);
2740 static HRESULT WINAPI dwritetextlayout_SetFontSize(IDWriteTextLayout2 *iface, FLOAT size, DWRITE_TEXT_RANGE range)
2742 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2743 struct layout_range_attr_value value;
2745 TRACE("(%p)->(%.2f %s)\n", This, size, debugstr_range(&range));
2747 if (size <= 0.0f)
2748 return E_INVALIDARG;
2750 value.range = range;
2751 value.u.fontsize = size;
2752 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTSIZE, &value);
2755 static HRESULT WINAPI dwritetextlayout_SetUnderline(IDWriteTextLayout2 *iface, BOOL underline, DWRITE_TEXT_RANGE range)
2757 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2758 struct layout_range_attr_value value;
2760 TRACE("(%p)->(%d %s)\n", This, underline, debugstr_range(&range));
2762 value.range = range;
2763 value.u.underline = underline;
2764 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_UNDERLINE, &value);
2767 static HRESULT WINAPI dwritetextlayout_SetStrikethrough(IDWriteTextLayout2 *iface, BOOL strikethrough, DWRITE_TEXT_RANGE range)
2769 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2770 struct layout_range_attr_value value;
2772 TRACE("(%p)->(%d %s)\n", This, strikethrough, debugstr_range(&range));
2774 value.range = range;
2775 value.u.strikethrough = strikethrough;
2776 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRIKETHROUGH, &value);
2779 static HRESULT WINAPI dwritetextlayout_SetDrawingEffect(IDWriteTextLayout2 *iface, IUnknown* effect, DWRITE_TEXT_RANGE range)
2781 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2782 struct layout_range_attr_value value;
2784 TRACE("(%p)->(%p %s)\n", This, effect, debugstr_range(&range));
2786 value.range = range;
2787 value.u.effect = effect;
2788 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_EFFECT, &value);
2791 static HRESULT WINAPI dwritetextlayout_SetInlineObject(IDWriteTextLayout2 *iface, IDWriteInlineObject *object, DWRITE_TEXT_RANGE range)
2793 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2794 struct layout_range_attr_value value;
2796 TRACE("(%p)->(%p %s)\n", This, object, debugstr_range(&range));
2798 value.range = range;
2799 value.u.object = object;
2800 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_INLINE, &value);
2803 static HRESULT WINAPI dwritetextlayout_SetTypography(IDWriteTextLayout2 *iface, IDWriteTypography* typography, DWRITE_TEXT_RANGE range)
2805 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2806 struct layout_range_attr_value value;
2808 TRACE("(%p)->(%p %s)\n", This, typography, debugstr_range(&range));
2810 value.range = range;
2811 value.u.typography = typography;
2812 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_TYPOGRAPHY, &value);
2815 static HRESULT WINAPI dwritetextlayout_SetLocaleName(IDWriteTextLayout2 *iface, WCHAR const* locale, DWRITE_TEXT_RANGE range)
2817 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2818 struct layout_range_attr_value value;
2820 TRACE("(%p)->(%s %s)\n", This, debugstr_w(locale), debugstr_range(&range));
2822 if (!locale || strlenW(locale) > LOCALE_NAME_MAX_LENGTH-1)
2823 return E_INVALIDARG;
2825 value.range = range;
2826 value.u.locale = locale;
2827 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_LOCALE, &value);
2830 static FLOAT WINAPI dwritetextlayout_GetMaxWidth(IDWriteTextLayout2 *iface)
2832 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2833 TRACE("(%p)\n", This);
2834 return This->metrics.layoutWidth;
2837 static FLOAT WINAPI dwritetextlayout_GetMaxHeight(IDWriteTextLayout2 *iface)
2839 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2840 TRACE("(%p)\n", This);
2841 return This->metrics.layoutHeight;
2844 static HRESULT WINAPI dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout2 *iface, UINT32 position,
2845 IDWriteFontCollection** collection, DWRITE_TEXT_RANGE *r)
2847 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2848 struct layout_range *range;
2850 TRACE("(%p)->(%u %p %p)\n", This, position, collection, r);
2852 if (position >= This->len)
2853 return S_OK;
2855 range = get_layout_range_by_pos(This, position);
2856 *collection = range->collection;
2857 if (*collection)
2858 IDWriteFontCollection_AddRef(*collection);
2860 return return_range(&range->h, r);
2863 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout2 *iface,
2864 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
2866 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2867 TRACE("(%p)->(%d %p %p)\n", This, position, length, r);
2868 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, length, r);
2871 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout2 *iface,
2872 UINT32 position, WCHAR *name, UINT32 length, DWRITE_TEXT_RANGE *r)
2874 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2875 TRACE("(%p)->(%u %p %u %p)\n", This, position, name, length, r);
2876 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, name, length, r);
2879 static HRESULT WINAPI dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout2 *iface,
2880 UINT32 position, DWRITE_FONT_WEIGHT *weight, DWRITE_TEXT_RANGE *r)
2882 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2883 struct layout_range *range;
2885 TRACE("(%p)->(%u %p %p)\n", This, position, weight, r);
2887 if (position >= This->len)
2888 return S_OK;
2890 range = get_layout_range_by_pos(This, position);
2891 *weight = range->weight;
2893 return return_range(&range->h, r);
2896 static HRESULT WINAPI dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout2 *iface,
2897 UINT32 position, DWRITE_FONT_STYLE *style, DWRITE_TEXT_RANGE *r)
2899 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2900 struct layout_range *range;
2902 TRACE("(%p)->(%u %p %p)\n", This, position, style, r);
2904 range = get_layout_range_by_pos(This, position);
2905 *style = range->style;
2906 return return_range(&range->h, r);
2909 static HRESULT WINAPI dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout2 *iface,
2910 UINT32 position, DWRITE_FONT_STRETCH *stretch, DWRITE_TEXT_RANGE *r)
2912 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2913 struct layout_range *range;
2915 TRACE("(%p)->(%u %p %p)\n", This, position, stretch, r);
2917 range = get_layout_range_by_pos(This, position);
2918 *stretch = range->stretch;
2919 return return_range(&range->h, r);
2922 static HRESULT WINAPI dwritetextlayout_layout_GetFontSize(IDWriteTextLayout2 *iface,
2923 UINT32 position, FLOAT *size, DWRITE_TEXT_RANGE *r)
2925 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2926 struct layout_range *range;
2928 TRACE("(%p)->(%u %p %p)\n", This, position, size, r);
2930 range = get_layout_range_by_pos(This, position);
2931 *size = range->fontsize;
2932 return return_range(&range->h, r);
2935 static HRESULT WINAPI dwritetextlayout_GetUnderline(IDWriteTextLayout2 *iface,
2936 UINT32 position, BOOL *underline, DWRITE_TEXT_RANGE *r)
2938 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2939 struct layout_range_bool *range;
2941 TRACE("(%p)->(%u %p %p)\n", This, position, underline, r);
2943 range = (struct layout_range_bool*)get_layout_range_header_by_pos(&This->underline_ranges, position);
2944 *underline = range->value;
2946 return return_range(&range->h, r);
2949 static HRESULT WINAPI dwritetextlayout_GetStrikethrough(IDWriteTextLayout2 *iface,
2950 UINT32 position, BOOL *strikethrough, DWRITE_TEXT_RANGE *r)
2952 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2953 struct layout_range_bool *range;
2955 TRACE("(%p)->(%u %p %p)\n", This, position, strikethrough, r);
2957 range = (struct layout_range_bool*)get_layout_range_header_by_pos(&This->strike_ranges, position);
2958 *strikethrough = range->value;
2960 return return_range(&range->h, r);
2963 static HRESULT WINAPI dwritetextlayout_GetDrawingEffect(IDWriteTextLayout2 *iface,
2964 UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r)
2966 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2967 struct layout_range_iface *range;
2969 TRACE("(%p)->(%u %p %p)\n", This, position, effect, r);
2971 range = (struct layout_range_iface*)get_layout_range_header_by_pos(&This->effects, position);
2972 *effect = range->iface;
2973 if (*effect)
2974 IUnknown_AddRef(*effect);
2976 return return_range(&range->h, r);
2979 static HRESULT WINAPI dwritetextlayout_GetInlineObject(IDWriteTextLayout2 *iface,
2980 UINT32 position, IDWriteInlineObject **object, DWRITE_TEXT_RANGE *r)
2982 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2983 struct layout_range *range;
2985 TRACE("(%p)->(%u %p %p)\n", This, position, object, r);
2987 if (position >= This->len)
2988 return S_OK;
2990 range = get_layout_range_by_pos(This, position);
2991 *object = range->object;
2992 if (*object)
2993 IDWriteInlineObject_AddRef(*object);
2995 return return_range(&range->h, r);
2998 static HRESULT WINAPI dwritetextlayout_GetTypography(IDWriteTextLayout2 *iface,
2999 UINT32 position, IDWriteTypography** typography, DWRITE_TEXT_RANGE *r)
3001 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3002 struct layout_range_iface *range;
3004 TRACE("(%p)->(%u %p %p)\n", This, position, typography, r);
3006 range = (struct layout_range_iface*)get_layout_range_header_by_pos(&This->typographies, position);
3007 *typography = (IDWriteTypography*)range->iface;
3008 if (*typography)
3009 IDWriteTypography_AddRef(*typography);
3011 return return_range(&range->h, r);
3014 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout2 *iface,
3015 UINT32 position, UINT32* length, DWRITE_TEXT_RANGE *r)
3017 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3018 TRACE("(%p)->(%u %p %p)\n", This, position, length, r);
3019 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_LOCALE, position, length, r);
3022 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout2 *iface,
3023 UINT32 position, WCHAR* locale, UINT32 length, DWRITE_TEXT_RANGE *r)
3025 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3026 TRACE("(%p)->(%u %p %u %p)\n", This, position, locale, length, r);
3027 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_LOCALE, position, locale, length, r);
3030 static inline FLOAT renderer_apply_snapping(FLOAT coord, BOOL skiptransform, FLOAT ppdip, FLOAT det,
3031 const DWRITE_MATRIX *m)
3033 FLOAT vec[2], vec2[2];
3035 if (!skiptransform) {
3036 /* apply transform */
3037 vec[0] = 0.0f;
3038 vec[1] = coord * ppdip;
3040 vec2[0] = m->m11 * vec[0] + m->m21 * vec[1] + m->dx;
3041 vec2[1] = m->m12 * vec[0] + m->m22 * vec[1] + m->dy;
3043 /* snap */
3044 vec2[0] = floorf(vec2[0] + 0.5f);
3045 vec2[1] = floorf(vec2[1] + 0.5f);
3047 /* apply inverted transform, we don't care about X component at this point */
3048 vec[1] = (-m->m12 * vec2[0] + m->m11 * vec2[1] - (m->m11 * m->dy - m->m12 * m->dx)) / det;
3049 vec[1] /= ppdip;
3051 else
3052 vec[1] = floorf(coord * ppdip + 0.5f) / ppdip;
3054 return vec[1];
3057 static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface,
3058 void *context, IDWriteTextRenderer* renderer, FLOAT origin_x, FLOAT origin_y)
3060 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3061 BOOL disabled = FALSE, skiptransform = FALSE;
3062 struct layout_effective_inline *inlineobject;
3063 struct layout_effective_run *run;
3064 struct layout_strikethrough *s;
3065 struct layout_underline *u;
3066 FLOAT det = 0.0f, ppdip = 0.0f;
3067 DWRITE_MATRIX m = { 0 };
3068 HRESULT hr;
3070 TRACE("(%p)->(%p %p %.2f %.2f)\n", This, context, renderer, origin_x, origin_y);
3072 hr = layout_compute_effective_runs(This);
3073 if (FAILED(hr))
3074 return hr;
3076 hr = IDWriteTextRenderer_IsPixelSnappingDisabled(renderer, context, &disabled);
3077 if (FAILED(hr))
3078 return hr;
3080 if (!disabled) {
3081 hr = IDWriteTextRenderer_GetPixelsPerDip(renderer, context, &ppdip);
3082 if (FAILED(hr))
3083 return hr;
3085 hr = IDWriteTextRenderer_GetCurrentTransform(renderer, context, &m);
3086 if (FAILED(hr))
3087 return hr;
3089 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
3090 if (ppdip <= 0.0f ||
3091 (m.m11 * m.m22 != 0.0f && (m.m12 != 0.0f || m.m21 != 0.0f)) ||
3092 (m.m12 * m.m21 != 0.0f && (m.m11 != 0.0f || m.m22 != 0.0f)))
3093 disabled = TRUE;
3094 else
3095 skiptransform = should_skip_transform(&m, &det);
3098 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
3099 /* 1. Regular runs */
3100 LIST_FOR_EACH_ENTRY(run, &This->eruns, struct layout_effective_run, entry) {
3101 const struct regular_layout_run *regular = &run->run->u.regular;
3102 UINT32 start_glyph = regular->clustermap[run->start];
3103 DWRITE_GLYPH_RUN_DESCRIPTION descr;
3104 DWRITE_GLYPH_RUN glyph_run;
3106 /* Everything but cluster map will be reused from nominal run, as we only need
3107 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
3108 it can't be reused because it has to start with 0 index for each reported run. */
3109 glyph_run = regular->run;
3110 glyph_run.glyphCount = run->glyphcount;
3112 /* fixup glyph data arrays */
3113 glyph_run.glyphIndices += start_glyph;
3114 glyph_run.glyphAdvances += start_glyph;
3115 glyph_run.glyphOffsets += start_glyph;
3117 /* description */
3118 descr = regular->descr;
3119 descr.stringLength = run->length;
3120 descr.string += run->start;
3121 descr.clusterMap = run->clustermap;
3122 descr.textPosition += run->start;
3124 /* return value is ignored */
3125 IDWriteTextRenderer_DrawGlyphRun(renderer,
3126 context,
3127 run->origin_x + run->align_dx + origin_x,
3128 SNAP_COORD(run->origin_y + origin_y),
3129 This->measuringmode,
3130 &glyph_run,
3131 &descr,
3132 run->effect);
3135 /* 2. Inline objects */
3136 LIST_FOR_EACH_ENTRY(inlineobject, &This->inlineobjects, struct layout_effective_inline, entry) {
3137 IDWriteTextRenderer_DrawInlineObject(renderer,
3138 context,
3139 inlineobject->origin_x + inlineobject->align_dx + origin_x,
3140 SNAP_COORD(inlineobject->origin_y + origin_y),
3141 inlineobject->object,
3142 inlineobject->is_sideways,
3143 inlineobject->is_rtl,
3144 inlineobject->effect);
3147 /* 3. Underlines */
3148 LIST_FOR_EACH_ENTRY(u, &This->underlines, struct layout_underline, entry) {
3149 IDWriteTextRenderer_DrawUnderline(renderer,
3150 context,
3151 /* horizontal underline always grows from left to right, width is always added to origin regardless of run direction */
3152 (is_run_rtl(u->run) ? u->run->origin_x - u->run->width : u->run->origin_x) + u->run->align_dx + origin_x,
3153 SNAP_COORD(u->run->origin_y + origin_y),
3154 &u->u,
3155 u->run->effect);
3158 /* 4. Strikethrough */
3159 LIST_FOR_EACH_ENTRY(s, &This->strikethrough, struct layout_strikethrough, entry) {
3160 IDWriteTextRenderer_DrawStrikethrough(renderer,
3161 context,
3162 s->run->origin_x + s->run->align_dx + origin_x,
3163 SNAP_COORD(s->run->origin_y + origin_y),
3164 &s->s,
3165 s->run->effect);
3167 #undef SNAP_COORD
3169 return S_OK;
3172 static HRESULT WINAPI dwritetextlayout_GetLineMetrics(IDWriteTextLayout2 *iface,
3173 DWRITE_LINE_METRICS *metrics, UINT32 max_count, UINT32 *count)
3175 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3176 HRESULT hr;
3178 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
3180 hr = layout_compute_effective_runs(This);
3181 if (FAILED(hr))
3182 return hr;
3184 if (metrics)
3185 memcpy(metrics, This->lines, sizeof(*metrics)*min(max_count, This->metrics.lineCount));
3187 *count = This->metrics.lineCount;
3188 return max_count >= This->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3191 static HRESULT WINAPI dwritetextlayout_GetMetrics(IDWriteTextLayout2 *iface, DWRITE_TEXT_METRICS *metrics)
3193 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3194 DWRITE_TEXT_METRICS1 metrics1;
3195 HRESULT hr;
3197 TRACE("(%p)->(%p)\n", This, metrics);
3199 hr = IDWriteTextLayout2_GetMetrics(iface, &metrics1);
3200 if (hr == S_OK)
3201 memcpy(metrics, &metrics1, sizeof(*metrics));
3203 return hr;
3206 static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout2 *iface, DWRITE_OVERHANG_METRICS *overhangs)
3208 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3209 FIXME("(%p)->(%p): stub\n", This, overhangs);
3210 return E_NOTIMPL;
3213 static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout2 *iface,
3214 DWRITE_CLUSTER_METRICS *metrics, UINT32 max_count, UINT32 *count)
3216 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3217 HRESULT hr;
3219 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
3221 hr = layout_compute(This);
3222 if (FAILED(hr))
3223 return hr;
3225 if (metrics)
3226 memcpy(metrics, This->clustermetrics, sizeof(DWRITE_CLUSTER_METRICS)*min(max_count, This->cluster_count));
3228 *count = This->cluster_count;
3229 return max_count >= This->cluster_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3232 static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout2 *iface, FLOAT* min_width)
3234 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3235 UINT32 start;
3236 FLOAT width;
3237 HRESULT hr;
3239 TRACE("(%p)->(%p)\n", This, min_width);
3241 if (!min_width)
3242 return E_INVALIDARG;
3244 if (!(This->recompute & RECOMPUTE_MINIMAL_WIDTH))
3245 goto width_done;
3247 *min_width = 0.0f;
3248 hr = layout_compute(This);
3249 if (FAILED(hr))
3250 return hr;
3252 /* Find widest word without emergency breaking between clusters, trailing whitespaces
3253 preceding breaking point do not contribute to word width. */
3254 for (start = 0; start < This->cluster_count;) {
3255 UINT32 end = start, j, next;
3257 /* Last cluster always could be wrapped after. */
3258 while (!This->clustermetrics[end].canWrapLineAfter)
3259 end++;
3260 /* make is so current cluster range that we can wrap after is [start,end) */
3261 end++;
3263 next = end;
3265 /* Ignore trailing whitespace clusters, in case of single space range will
3266 be reduced to empty range, or [start,start+1). */
3267 while ((end - 1) >= start && This->clustermetrics[end-1].isWhitespace)
3268 end--;
3270 /* check if cluster range exceeds last minimal width */
3271 width = 0.0f;
3272 for (j = start; j < end; j++)
3273 width += This->clustermetrics[j].width;
3275 start = next;
3277 if (width > This->minwidth)
3278 This->minwidth = width;
3280 This->recompute &= ~RECOMPUTE_MINIMAL_WIDTH;
3282 width_done:
3283 *min_width = This->minwidth;
3284 return S_OK;
3287 static HRESULT WINAPI dwritetextlayout_HitTestPoint(IDWriteTextLayout2 *iface,
3288 FLOAT pointX, FLOAT pointY, BOOL* is_trailinghit, BOOL* is_inside, DWRITE_HIT_TEST_METRICS *metrics)
3290 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3291 FIXME("(%p)->(%f %f %p %p %p): stub\n", This, pointX, pointY, is_trailinghit, is_inside, metrics);
3292 return E_NOTIMPL;
3295 static HRESULT WINAPI dwritetextlayout_HitTestTextPosition(IDWriteTextLayout2 *iface,
3296 UINT32 textPosition, BOOL is_trailinghit, FLOAT* pointX, FLOAT* pointY, DWRITE_HIT_TEST_METRICS *metrics)
3298 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3299 FIXME("(%p)->(%u %d %p %p %p): stub\n", This, textPosition, is_trailinghit, pointX, pointY, metrics);
3300 return E_NOTIMPL;
3303 static HRESULT WINAPI dwritetextlayout_HitTestTextRange(IDWriteTextLayout2 *iface,
3304 UINT32 textPosition, UINT32 textLength, FLOAT originX, FLOAT originY,
3305 DWRITE_HIT_TEST_METRICS *metrics, UINT32 max_metricscount, UINT32* actual_metricscount)
3307 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3308 FIXME("(%p)->(%u %u %f %f %p %u %p): stub\n", This, textPosition, textLength, originX, originY, metrics,
3309 max_metricscount, actual_metricscount);
3310 return E_NOTIMPL;
3313 static HRESULT WINAPI dwritetextlayout1_SetPairKerning(IDWriteTextLayout2 *iface, BOOL is_pairkerning_enabled,
3314 DWRITE_TEXT_RANGE range)
3316 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3317 struct layout_range_attr_value value;
3319 TRACE("(%p)->(%d %s)\n", This, is_pairkerning_enabled, debugstr_range(&range));
3321 value.range = range;
3322 value.u.pair_kerning = !!is_pairkerning_enabled;
3323 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_PAIR_KERNING, &value);
3326 static HRESULT WINAPI dwritetextlayout1_GetPairKerning(IDWriteTextLayout2 *iface, UINT32 position, BOOL *is_pairkerning_enabled,
3327 DWRITE_TEXT_RANGE *r)
3329 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3330 struct layout_range *range;
3332 TRACE("(%p)->(%u %p %p)\n", This, position, is_pairkerning_enabled, r);
3334 if (position >= This->len)
3335 return S_OK;
3337 range = get_layout_range_by_pos(This, position);
3338 *is_pairkerning_enabled = range->pair_kerning;
3340 return return_range(&range->h, r);
3343 static HRESULT WINAPI dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout2 *iface, FLOAT leading, FLOAT trailing,
3344 FLOAT min_advance, DWRITE_TEXT_RANGE range)
3346 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3347 struct layout_range_attr_value value;
3349 TRACE("(%p)->(%.2f %.2f %.2f %s)\n", This, leading, trailing, min_advance, debugstr_range(&range));
3351 if (min_advance < 0.0f)
3352 return E_INVALIDARG;
3354 value.range = range;
3355 value.u.spacing[0] = leading;
3356 value.u.spacing[1] = trailing;
3357 value.u.spacing[2] = min_advance;
3358 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_SPACING, &value);
3361 static HRESULT WINAPI dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout2 *iface, UINT32 position, FLOAT *leading,
3362 FLOAT *trailing, FLOAT *min_advance, DWRITE_TEXT_RANGE *r)
3364 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3365 struct layout_range_spacing *range;
3367 TRACE("(%p)->(%u %p %p %p %p)\n", This, position, leading, trailing, min_advance, r);
3369 range = (struct layout_range_spacing*)get_layout_range_header_by_pos(&This->spacing, position);
3370 *leading = range->leading;
3371 *trailing = range->trailing;
3372 *min_advance = range->min_advance;
3374 return return_range(&range->h, r);
3377 static HRESULT WINAPI dwritetextlayout2_GetMetrics(IDWriteTextLayout2 *iface, DWRITE_TEXT_METRICS1 *metrics)
3379 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3380 HRESULT hr;
3382 TRACE("(%p)->(%p)\n", This, metrics);
3384 hr = layout_compute_effective_runs(This);
3385 if (FAILED(hr))
3386 return hr;
3388 *metrics = This->metrics;
3389 return S_OK;
3392 static HRESULT WINAPI dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout2 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
3394 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3396 TRACE("(%p)->(%d)\n", This, orientation);
3398 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
3399 return E_INVALIDARG;
3401 This->format.vertical_orientation = orientation;
3402 return S_OK;
3405 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout2 *iface)
3407 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3408 TRACE("(%p)\n", This);
3409 return This->format.vertical_orientation;
3412 static HRESULT WINAPI dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout2 *iface, BOOL lastline_wrapping_enabled)
3414 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3415 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
3416 return IDWriteTextFormat1_SetLastLineWrapping(&This->IDWriteTextFormat1_iface, lastline_wrapping_enabled);
3419 static BOOL WINAPI dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout2 *iface)
3421 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3422 TRACE("(%p)\n", This);
3423 return IDWriteTextFormat1_GetLastLineWrapping(&This->IDWriteTextFormat1_iface);
3426 static HRESULT WINAPI dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout2 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
3428 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3429 TRACE("(%p)->(%d)\n", This, alignment);
3430 return IDWriteTextFormat1_SetOpticalAlignment(&This->IDWriteTextFormat1_iface, alignment);
3433 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout2 *iface)
3435 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3436 TRACE("(%p)\n", This);
3437 return IDWriteTextFormat1_GetOpticalAlignment(&This->IDWriteTextFormat1_iface);
3440 static HRESULT WINAPI dwritetextlayout2_SetFontFallback(IDWriteTextLayout2 *iface, IDWriteFontFallback *fallback)
3442 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3443 TRACE("(%p)->(%p)\n", This, fallback);
3444 return set_fontfallback_for_format(&This->format, fallback);
3447 static HRESULT WINAPI dwritetextlayout2_GetFontFallback(IDWriteTextLayout2 *iface, IDWriteFontFallback **fallback)
3449 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3450 TRACE("(%p)->(%p)\n", This, fallback);
3451 return get_fontfallback_from_format(&This->format, fallback);
3454 static const IDWriteTextLayout2Vtbl dwritetextlayoutvtbl = {
3455 dwritetextlayout_QueryInterface,
3456 dwritetextlayout_AddRef,
3457 dwritetextlayout_Release,
3458 dwritetextlayout_SetTextAlignment,
3459 dwritetextlayout_SetParagraphAlignment,
3460 dwritetextlayout_SetWordWrapping,
3461 dwritetextlayout_SetReadingDirection,
3462 dwritetextlayout_SetFlowDirection,
3463 dwritetextlayout_SetIncrementalTabStop,
3464 dwritetextlayout_SetTrimming,
3465 dwritetextlayout_SetLineSpacing,
3466 dwritetextlayout_GetTextAlignment,
3467 dwritetextlayout_GetParagraphAlignment,
3468 dwritetextlayout_GetWordWrapping,
3469 dwritetextlayout_GetReadingDirection,
3470 dwritetextlayout_GetFlowDirection,
3471 dwritetextlayout_GetIncrementalTabStop,
3472 dwritetextlayout_GetTrimming,
3473 dwritetextlayout_GetLineSpacing,
3474 dwritetextlayout_GetFontCollection,
3475 dwritetextlayout_GetFontFamilyNameLength,
3476 dwritetextlayout_GetFontFamilyName,
3477 dwritetextlayout_GetFontWeight,
3478 dwritetextlayout_GetFontStyle,
3479 dwritetextlayout_GetFontStretch,
3480 dwritetextlayout_GetFontSize,
3481 dwritetextlayout_GetLocaleNameLength,
3482 dwritetextlayout_GetLocaleName,
3483 dwritetextlayout_SetMaxWidth,
3484 dwritetextlayout_SetMaxHeight,
3485 dwritetextlayout_SetFontCollection,
3486 dwritetextlayout_SetFontFamilyName,
3487 dwritetextlayout_SetFontWeight,
3488 dwritetextlayout_SetFontStyle,
3489 dwritetextlayout_SetFontStretch,
3490 dwritetextlayout_SetFontSize,
3491 dwritetextlayout_SetUnderline,
3492 dwritetextlayout_SetStrikethrough,
3493 dwritetextlayout_SetDrawingEffect,
3494 dwritetextlayout_SetInlineObject,
3495 dwritetextlayout_SetTypography,
3496 dwritetextlayout_SetLocaleName,
3497 dwritetextlayout_GetMaxWidth,
3498 dwritetextlayout_GetMaxHeight,
3499 dwritetextlayout_layout_GetFontCollection,
3500 dwritetextlayout_layout_GetFontFamilyNameLength,
3501 dwritetextlayout_layout_GetFontFamilyName,
3502 dwritetextlayout_layout_GetFontWeight,
3503 dwritetextlayout_layout_GetFontStyle,
3504 dwritetextlayout_layout_GetFontStretch,
3505 dwritetextlayout_layout_GetFontSize,
3506 dwritetextlayout_GetUnderline,
3507 dwritetextlayout_GetStrikethrough,
3508 dwritetextlayout_GetDrawingEffect,
3509 dwritetextlayout_GetInlineObject,
3510 dwritetextlayout_GetTypography,
3511 dwritetextlayout_layout_GetLocaleNameLength,
3512 dwritetextlayout_layout_GetLocaleName,
3513 dwritetextlayout_Draw,
3514 dwritetextlayout_GetLineMetrics,
3515 dwritetextlayout_GetMetrics,
3516 dwritetextlayout_GetOverhangMetrics,
3517 dwritetextlayout_GetClusterMetrics,
3518 dwritetextlayout_DetermineMinWidth,
3519 dwritetextlayout_HitTestPoint,
3520 dwritetextlayout_HitTestTextPosition,
3521 dwritetextlayout_HitTestTextRange,
3522 dwritetextlayout1_SetPairKerning,
3523 dwritetextlayout1_GetPairKerning,
3524 dwritetextlayout1_SetCharacterSpacing,
3525 dwritetextlayout1_GetCharacterSpacing,
3526 dwritetextlayout2_GetMetrics,
3527 dwritetextlayout2_SetVerticalGlyphOrientation,
3528 dwritetextlayout2_GetVerticalGlyphOrientation,
3529 dwritetextlayout2_SetLastLineWrapping,
3530 dwritetextlayout2_GetLastLineWrapping,
3531 dwritetextlayout2_SetOpticalAlignment,
3532 dwritetextlayout2_GetOpticalAlignment,
3533 dwritetextlayout2_SetFontFallback,
3534 dwritetextlayout2_GetFontFallback
3537 static HRESULT WINAPI dwritetextformat1_layout_QueryInterface(IDWriteTextFormat1 *iface, REFIID riid, void **obj)
3539 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3540 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3541 return IDWriteTextLayout2_QueryInterface(&This->IDWriteTextLayout2_iface, riid, obj);
3544 static ULONG WINAPI dwritetextformat1_layout_AddRef(IDWriteTextFormat1 *iface)
3546 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3547 return IDWriteTextLayout2_AddRef(&This->IDWriteTextLayout2_iface);
3550 static ULONG WINAPI dwritetextformat1_layout_Release(IDWriteTextFormat1 *iface)
3552 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3553 return IDWriteTextLayout2_Release(&This->IDWriteTextLayout2_iface);
3556 static HRESULT WINAPI dwritetextformat1_layout_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
3558 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3559 BOOL changed;
3560 HRESULT hr;
3562 TRACE("(%p)->(%d)\n", This, alignment);
3564 hr = format_set_textalignment(&This->format, alignment, &changed);
3565 if (FAILED(hr))
3566 return hr;
3568 /* if layout is not ready there's nothing to align */
3569 if (changed && !(This->recompute & RECOMPUTE_EFFECTIVE_RUNS))
3570 layout_apply_text_alignment(This);
3572 return S_OK;
3575 static HRESULT WINAPI dwritetextformat1_layout_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
3577 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3578 BOOL changed;
3579 HRESULT hr;
3581 TRACE("(%p)->(%d)\n", This, alignment);
3583 hr = format_set_paralignment(&This->format, alignment, &changed);
3584 if (FAILED(hr))
3585 return hr;
3587 /* if layout is not ready there's nothing to align */
3588 if (changed && !(This->recompute & RECOMPUTE_EFFECTIVE_RUNS))
3589 layout_apply_par_alignment(This);
3591 return S_OK;
3594 static HRESULT WINAPI dwritetextformat1_layout_SetWordWrapping(IDWriteTextFormat1 *iface, DWRITE_WORD_WRAPPING wrapping)
3596 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3597 BOOL changed;
3598 HRESULT hr;
3600 TRACE("(%p)->(%d)\n", This, wrapping);
3602 hr = format_set_wordwrapping(&This->format, wrapping, &changed);
3603 if (FAILED(hr))
3604 return hr;
3606 if (changed)
3607 This->recompute |= RECOMPUTE_EFFECTIVE_RUNS;
3609 return S_OK;
3612 static HRESULT WINAPI dwritetextformat1_layout_SetReadingDirection(IDWriteTextFormat1 *iface, DWRITE_READING_DIRECTION direction)
3614 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3615 BOOL changed;
3616 HRESULT hr;
3618 TRACE("(%p)->(%d)\n", This, direction);
3620 hr = format_set_readingdirection(&This->format, direction, &changed);
3621 if (FAILED(hr))
3622 return hr;
3624 if (changed)
3625 This->recompute = RECOMPUTE_EVERYTHING;
3627 return S_OK;
3630 static HRESULT WINAPI dwritetextformat1_layout_SetFlowDirection(IDWriteTextFormat1 *iface, DWRITE_FLOW_DIRECTION direction)
3632 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3633 FIXME("(%p)->(%d): stub\n", This, direction);
3634 return E_NOTIMPL;
3637 static HRESULT WINAPI dwritetextformat1_layout_SetIncrementalTabStop(IDWriteTextFormat1 *iface, FLOAT tabstop)
3639 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3640 FIXME("(%p)->(%f): stub\n", This, tabstop);
3641 return E_NOTIMPL;
3644 static HRESULT WINAPI dwritetextformat1_layout_SetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING const *trimming,
3645 IDWriteInlineObject *trimming_sign)
3647 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3648 FIXME("(%p)->(%p %p): stub\n", This, trimming, trimming_sign);
3649 return E_NOTIMPL;
3652 static HRESULT WINAPI dwritetextformat1_layout_SetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD spacing,
3653 FLOAT line_spacing, FLOAT baseline)
3655 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3656 FIXME("(%p)->(%d %f %f): stub\n", This, spacing, line_spacing, baseline);
3657 return E_NOTIMPL;
3660 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat1_layout_GetTextAlignment(IDWriteTextFormat1 *iface)
3662 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3663 TRACE("(%p)\n", This);
3664 return This->format.textalignment;
3667 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat1_layout_GetParagraphAlignment(IDWriteTextFormat1 *iface)
3669 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3670 TRACE("(%p)\n", This);
3671 return This->format.paralign;
3674 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat1_layout_GetWordWrapping(IDWriteTextFormat1 *iface)
3676 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3677 TRACE("(%p)\n", This);
3678 return This->format.wrapping;
3681 static DWRITE_READING_DIRECTION WINAPI dwritetextformat1_layout_GetReadingDirection(IDWriteTextFormat1 *iface)
3683 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3684 TRACE("(%p)\n", This);
3685 return This->format.readingdir;
3688 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat1_layout_GetFlowDirection(IDWriteTextFormat1 *iface)
3690 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3691 TRACE("(%p)\n", This);
3692 return This->format.flow;
3695 static FLOAT WINAPI dwritetextformat1_layout_GetIncrementalTabStop(IDWriteTextFormat1 *iface)
3697 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3698 FIXME("(%p): stub\n", This);
3699 return 0.0f;
3702 static HRESULT WINAPI dwritetextformat1_layout_GetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING *options,
3703 IDWriteInlineObject **trimming_sign)
3705 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3707 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
3709 *options = This->format.trimming;
3710 *trimming_sign = This->format.trimmingsign;
3711 if (*trimming_sign)
3712 IDWriteInlineObject_AddRef(*trimming_sign);
3713 return S_OK;
3716 static HRESULT WINAPI dwritetextformat1_layout_GetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD *method,
3717 FLOAT *spacing, FLOAT *baseline)
3719 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3721 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
3723 *method = This->format.spacingmethod;
3724 *spacing = This->format.spacing;
3725 *baseline = This->format.baseline;
3726 return S_OK;
3729 static HRESULT WINAPI dwritetextformat1_layout_GetFontCollection(IDWriteTextFormat1 *iface, IDWriteFontCollection **collection)
3731 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3733 TRACE("(%p)->(%p)\n", This, collection);
3735 *collection = This->format.collection;
3736 if (*collection)
3737 IDWriteFontCollection_AddRef(*collection);
3738 return S_OK;
3741 static UINT32 WINAPI dwritetextformat1_layout_GetFontFamilyNameLength(IDWriteTextFormat1 *iface)
3743 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3744 TRACE("(%p)\n", This);
3745 return This->format.family_len;
3748 static HRESULT WINAPI dwritetextformat1_layout_GetFontFamilyName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
3750 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3752 TRACE("(%p)->(%p %u)\n", This, name, size);
3754 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
3755 strcpyW(name, This->format.family_name);
3756 return S_OK;
3759 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat1_layout_GetFontWeight(IDWriteTextFormat1 *iface)
3761 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3762 TRACE("(%p)\n", This);
3763 return This->format.weight;
3766 static DWRITE_FONT_STYLE WINAPI dwritetextformat1_layout_GetFontStyle(IDWriteTextFormat1 *iface)
3768 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3769 TRACE("(%p)\n", This);
3770 return This->format.style;
3773 static DWRITE_FONT_STRETCH WINAPI dwritetextformat1_layout_GetFontStretch(IDWriteTextFormat1 *iface)
3775 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3776 TRACE("(%p)\n", This);
3777 return This->format.stretch;
3780 static FLOAT WINAPI dwritetextformat1_layout_GetFontSize(IDWriteTextFormat1 *iface)
3782 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3783 TRACE("(%p)\n", This);
3784 return This->format.fontsize;
3787 static UINT32 WINAPI dwritetextformat1_layout_GetLocaleNameLength(IDWriteTextFormat1 *iface)
3789 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3790 TRACE("(%p)\n", This);
3791 return This->format.locale_len;
3794 static HRESULT WINAPI dwritetextformat1_layout_GetLocaleName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
3796 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3798 TRACE("(%p)->(%p %u)\n", This, name, size);
3800 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
3801 strcpyW(name, This->format.locale);
3802 return S_OK;
3805 static HRESULT WINAPI dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat1 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
3807 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3808 FIXME("(%p)->(%d): stub\n", This, orientation);
3809 return E_NOTIMPL;
3812 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat1 *iface)
3814 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3815 FIXME("(%p): stub\n", This);
3816 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
3819 static HRESULT WINAPI dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat1 *iface, BOOL lastline_wrapping_enabled)
3821 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3823 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
3825 This->format.last_line_wrapping = !!lastline_wrapping_enabled;
3826 return S_OK;
3829 static BOOL WINAPI dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat1 *iface)
3831 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3832 TRACE("(%p)\n", This);
3833 return This->format.last_line_wrapping;
3836 static HRESULT WINAPI dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat1 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
3838 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3839 TRACE("(%p)->(%d)\n", This, alignment);
3840 return format_set_optical_alignment(&This->format, alignment);
3843 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat1 *iface)
3845 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3846 TRACE("(%p)\n", This);
3847 return This->format.optical_alignment;
3850 static HRESULT WINAPI dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback *fallback)
3852 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3853 TRACE("(%p)->(%p)\n", This, fallback);
3854 return IDWriteTextLayout2_SetFontFallback(&This->IDWriteTextLayout2_iface, fallback);
3857 static HRESULT WINAPI dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback **fallback)
3859 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3860 TRACE("(%p)->(%p)\n", This, fallback);
3861 return IDWriteTextLayout2_GetFontFallback(&This->IDWriteTextLayout2_iface, fallback);
3864 static const IDWriteTextFormat1Vtbl dwritetextformat1_layout_vtbl = {
3865 dwritetextformat1_layout_QueryInterface,
3866 dwritetextformat1_layout_AddRef,
3867 dwritetextformat1_layout_Release,
3868 dwritetextformat1_layout_SetTextAlignment,
3869 dwritetextformat1_layout_SetParagraphAlignment,
3870 dwritetextformat1_layout_SetWordWrapping,
3871 dwritetextformat1_layout_SetReadingDirection,
3872 dwritetextformat1_layout_SetFlowDirection,
3873 dwritetextformat1_layout_SetIncrementalTabStop,
3874 dwritetextformat1_layout_SetTrimming,
3875 dwritetextformat1_layout_SetLineSpacing,
3876 dwritetextformat1_layout_GetTextAlignment,
3877 dwritetextformat1_layout_GetParagraphAlignment,
3878 dwritetextformat1_layout_GetWordWrapping,
3879 dwritetextformat1_layout_GetReadingDirection,
3880 dwritetextformat1_layout_GetFlowDirection,
3881 dwritetextformat1_layout_GetIncrementalTabStop,
3882 dwritetextformat1_layout_GetTrimming,
3883 dwritetextformat1_layout_GetLineSpacing,
3884 dwritetextformat1_layout_GetFontCollection,
3885 dwritetextformat1_layout_GetFontFamilyNameLength,
3886 dwritetextformat1_layout_GetFontFamilyName,
3887 dwritetextformat1_layout_GetFontWeight,
3888 dwritetextformat1_layout_GetFontStyle,
3889 dwritetextformat1_layout_GetFontStretch,
3890 dwritetextformat1_layout_GetFontSize,
3891 dwritetextformat1_layout_GetLocaleNameLength,
3892 dwritetextformat1_layout_GetLocaleName,
3893 dwritetextformat1_layout_SetVerticalGlyphOrientation,
3894 dwritetextformat1_layout_GetVerticalGlyphOrientation,
3895 dwritetextformat1_layout_SetLastLineWrapping,
3896 dwritetextformat1_layout_GetLastLineWrapping,
3897 dwritetextformat1_layout_SetOpticalAlignment,
3898 dwritetextformat1_layout_GetOpticalAlignment,
3899 dwritetextformat1_layout_SetFontFallback,
3900 dwritetextformat1_layout_GetFontFallback
3903 static HRESULT WINAPI dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink *iface,
3904 REFIID riid, void **obj)
3906 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) || IsEqualIID(riid, &IID_IUnknown)) {
3907 *obj = iface;
3908 IDWriteTextAnalysisSink_AddRef(iface);
3909 return S_OK;
3912 *obj = NULL;
3913 return E_NOINTERFACE;
3916 static ULONG WINAPI dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink *iface)
3918 return 2;
3921 static ULONG WINAPI dwritetextlayout_sink_Release(IDWriteTextAnalysisSink *iface)
3923 return 1;
3926 static HRESULT WINAPI dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink *iface,
3927 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
3929 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
3930 struct layout_run *run;
3932 TRACE("%u %u script=%d\n", position, length, sa->script);
3934 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
3935 if (!run)
3936 return E_OUTOFMEMORY;
3938 run->u.regular.descr.string = &layout->str[position];
3939 run->u.regular.descr.stringLength = length;
3940 run->u.regular.descr.textPosition = position;
3941 run->u.regular.sa = *sa;
3942 list_add_tail(&layout->runs, &run->entry);
3943 return S_OK;
3946 static HRESULT WINAPI dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink *iface,
3947 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
3949 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
3951 if (position + length > layout->len)
3952 return E_FAIL;
3954 memcpy(&layout->nominal_breakpoints[position], breakpoints, length*sizeof(DWRITE_LINE_BREAKPOINT));
3955 return S_OK;
3958 static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink *iface, UINT32 position,
3959 UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
3961 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
3962 struct layout_run *cur_run;
3964 TRACE("%u %u %u %u\n", position, length, explicitLevel, resolvedLevel);
3966 LIST_FOR_EACH_ENTRY(cur_run, &layout->runs, struct layout_run, entry) {
3967 struct regular_layout_run *cur = &cur_run->u.regular;
3968 struct layout_run *run;
3970 if (cur_run->kind == LAYOUT_RUN_INLINE)
3971 continue;
3973 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
3974 if (position < cur->descr.textPosition || position >= cur->descr.textPosition + cur->descr.stringLength)
3975 continue;
3977 /* full hit - just set run level */
3978 if (cur->descr.textPosition == position && cur->descr.stringLength == length) {
3979 cur->run.bidiLevel = resolvedLevel;
3980 break;
3983 /* current run is fully covered, move to next one */
3984 if (cur->descr.textPosition == position && cur->descr.stringLength < length) {
3985 cur->run.bidiLevel = resolvedLevel;
3986 position += cur->descr.stringLength;
3987 length -= cur->descr.stringLength;
3988 continue;
3991 /* all fully covered runs are processed at this point, reuse existing run for remaining
3992 reported bidi range and add another run for the rest of original one */
3994 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
3995 if (!run)
3996 return E_OUTOFMEMORY;
3998 *run = *cur_run;
3999 run->u.regular.descr.textPosition = position + length;
4000 run->u.regular.descr.stringLength = cur->descr.stringLength - length;
4001 run->u.regular.descr.string = &layout->str[position + length];
4003 /* reduce existing run */
4004 cur->run.bidiLevel = resolvedLevel;
4005 cur->descr.stringLength = length;
4007 list_add_after(&cur_run->entry, &run->entry);
4008 break;
4011 return S_OK;
4014 static HRESULT WINAPI dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink *iface,
4015 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
4017 return E_NOTIMPL;
4020 static const IDWriteTextAnalysisSinkVtbl dwritetextlayoutsinkvtbl = {
4021 dwritetextlayout_sink_QueryInterface,
4022 dwritetextlayout_sink_AddRef,
4023 dwritetextlayout_sink_Release,
4024 dwritetextlayout_sink_SetScriptAnalysis,
4025 dwritetextlayout_sink_SetLineBreakpoints,
4026 dwritetextlayout_sink_SetBidiLevel,
4027 dwritetextlayout_sink_SetNumberSubstitution
4030 static HRESULT WINAPI dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource *iface,
4031 REFIID riid, void **obj)
4033 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) ||
4034 IsEqualIID(riid, &IID_IUnknown))
4036 *obj = iface;
4037 IDWriteTextAnalysisSource_AddRef(iface);
4038 return S_OK;
4041 *obj = NULL;
4042 return E_NOINTERFACE;
4045 static ULONG WINAPI dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource *iface)
4047 return 2;
4050 static ULONG WINAPI dwritetextlayout_source_Release(IDWriteTextAnalysisSource *iface)
4052 return 1;
4055 static HRESULT WINAPI dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource *iface,
4056 UINT32 position, WCHAR const** text, UINT32* text_len)
4058 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource(iface);
4060 TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
4062 if (position < layout->len) {
4063 *text = &layout->str[position];
4064 *text_len = layout->len - position;
4066 else {
4067 *text = NULL;
4068 *text_len = 0;
4071 return S_OK;
4074 static HRESULT WINAPI dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource *iface,
4075 UINT32 position, WCHAR const** text, UINT32* text_len)
4077 FIXME("%u %p %p: stub\n", position, text, text_len);
4078 return E_NOTIMPL;
4081 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource *iface)
4083 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource(iface);
4084 return IDWriteTextLayout2_GetReadingDirection(&layout->IDWriteTextLayout2_iface);
4087 static HRESULT WINAPI dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource *iface,
4088 UINT32 position, UINT32* text_len, WCHAR const** locale)
4090 FIXME("%u %p %p: stub\n", position, text_len, locale);
4091 return E_NOTIMPL;
4094 static HRESULT WINAPI dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource *iface,
4095 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
4097 FIXME("%u %p %p: stub\n", position, text_len, substitution);
4098 return E_NOTIMPL;
4101 static const IDWriteTextAnalysisSourceVtbl dwritetextlayoutsourcevtbl = {
4102 dwritetextlayout_source_QueryInterface,
4103 dwritetextlayout_source_AddRef,
4104 dwritetextlayout_source_Release,
4105 dwritetextlayout_source_GetTextAtPosition,
4106 dwritetextlayout_source_GetTextBeforePosition,
4107 dwritetextlayout_source_GetParagraphReadingDirection,
4108 dwritetextlayout_source_GetLocaleName,
4109 dwritetextlayout_source_GetNumberSubstitution
4112 static HRESULT layout_format_from_textformat(struct dwrite_textlayout *layout, IDWriteTextFormat *format)
4114 struct dwrite_textformat *textformat;
4115 IDWriteTextFormat1 *format1;
4116 UINT32 len;
4117 HRESULT hr;
4119 if ((textformat = unsafe_impl_from_IDWriteTextFormat(format))) {
4120 layout->format = textformat->format;
4122 layout->format.locale = heap_strdupW(textformat->format.locale);
4123 layout->format.family_name = heap_strdupW(textformat->format.family_name);
4124 if (!layout->format.locale || !layout->format.family_name)
4126 heap_free(layout->format.locale);
4127 heap_free(layout->format.family_name);
4128 return E_OUTOFMEMORY;
4131 if (layout->format.trimmingsign)
4132 IDWriteInlineObject_AddRef(layout->format.trimmingsign);
4133 if (layout->format.collection)
4134 IDWriteFontCollection_AddRef(layout->format.collection);
4135 if (layout->format.fallback)
4136 IDWriteFontFallback_AddRef(layout->format.fallback);
4138 return S_OK;
4141 layout->format.weight = IDWriteTextFormat_GetFontWeight(format);
4142 layout->format.style = IDWriteTextFormat_GetFontStyle(format);
4143 layout->format.stretch = IDWriteTextFormat_GetFontStretch(format);
4144 layout->format.fontsize= IDWriteTextFormat_GetFontSize(format);
4145 layout->format.textalignment = IDWriteTextFormat_GetTextAlignment(format);
4146 layout->format.paralign = IDWriteTextFormat_GetParagraphAlignment(format);
4147 layout->format.wrapping = IDWriteTextFormat_GetWordWrapping(format);
4148 layout->format.readingdir = IDWriteTextFormat_GetReadingDirection(format);
4149 layout->format.flow = IDWriteTextFormat_GetFlowDirection(format);
4150 layout->format.fallback = NULL;
4151 hr = IDWriteTextFormat_GetLineSpacing(format, &layout->format.spacingmethod,
4152 &layout->format.spacing, &layout->format.baseline);
4153 if (FAILED(hr))
4154 return hr;
4156 hr = IDWriteTextFormat_GetTrimming(format, &layout->format.trimming, &layout->format.trimmingsign);
4157 if (FAILED(hr))
4158 return hr;
4160 /* locale name and length */
4161 len = IDWriteTextFormat_GetLocaleNameLength(format);
4162 layout->format.locale = heap_alloc((len+1)*sizeof(WCHAR));
4163 if (!layout->format.locale)
4164 return E_OUTOFMEMORY;
4166 hr = IDWriteTextFormat_GetLocaleName(format, layout->format.locale, len+1);
4167 if (FAILED(hr))
4168 return hr;
4169 layout->format.locale_len = len;
4171 /* font family name and length */
4172 len = IDWriteTextFormat_GetFontFamilyNameLength(format);
4173 layout->format.family_name = heap_alloc((len+1)*sizeof(WCHAR));
4174 if (!layout->format.family_name)
4175 return E_OUTOFMEMORY;
4177 hr = IDWriteTextFormat_GetFontFamilyName(format, layout->format.family_name, len+1);
4178 if (FAILED(hr))
4179 return hr;
4180 layout->format.family_len = len;
4182 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
4183 if (hr == S_OK) {
4184 layout->format.vertical_orientation = IDWriteTextFormat1_GetVerticalGlyphOrientation(format1);
4185 layout->format.optical_alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
4186 IDWriteTextFormat1_GetFontFallback(format1, &layout->format.fallback);
4187 IDWriteTextFormat1_Release(format1);
4189 else {
4190 layout->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
4191 layout->format.optical_alignment = DWRITE_OPTICAL_ALIGNMENT_NONE;
4194 return IDWriteTextFormat_GetFontCollection(format, &layout->format.collection);
4197 static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, struct dwrite_textlayout *layout)
4199 struct layout_range_header *range, *strike, *underline, *effect, *spacing, *typography;
4200 static const DWRITE_TEXT_RANGE r = { 0, ~0u };
4201 HRESULT hr;
4203 layout->IDWriteTextLayout2_iface.lpVtbl = &dwritetextlayoutvtbl;
4204 layout->IDWriteTextFormat1_iface.lpVtbl = &dwritetextformat1_layout_vtbl;
4205 layout->IDWriteTextAnalysisSink_iface.lpVtbl = &dwritetextlayoutsinkvtbl;
4206 layout->IDWriteTextAnalysisSource_iface.lpVtbl = &dwritetextlayoutsourcevtbl;
4207 layout->ref = 1;
4208 layout->len = len;
4209 layout->recompute = RECOMPUTE_EVERYTHING;
4210 layout->nominal_breakpoints = NULL;
4211 layout->actual_breakpoints = NULL;
4212 layout->cluster_count = 0;
4213 layout->clustermetrics = NULL;
4214 layout->clusters = NULL;
4215 layout->lines = NULL;
4216 layout->line_alloc = 0;
4217 layout->minwidth = 0.0f;
4218 list_init(&layout->eruns);
4219 list_init(&layout->inlineobjects);
4220 list_init(&layout->underlines);
4221 list_init(&layout->strikethrough);
4222 list_init(&layout->runs);
4223 list_init(&layout->ranges);
4224 list_init(&layout->strike_ranges);
4225 list_init(&layout->underline_ranges);
4226 list_init(&layout->effects);
4227 list_init(&layout->spacing);
4228 list_init(&layout->typographies);
4229 memset(&layout->format, 0, sizeof(layout->format));
4230 memset(&layout->metrics, 0, sizeof(layout->metrics));
4231 layout->metrics.layoutWidth = maxwidth;
4232 layout->metrics.layoutHeight = maxheight;
4233 layout->measuringmode = DWRITE_MEASURING_MODE_NATURAL;
4235 layout->ppdip = 0.0f;
4236 memset(&layout->transform, 0, sizeof(layout->transform));
4238 layout->str = heap_strdupnW(str, len);
4239 if (len && !layout->str) {
4240 hr = E_OUTOFMEMORY;
4241 goto fail;
4244 hr = layout_format_from_textformat(layout, format);
4245 if (FAILED(hr))
4246 goto fail;
4248 range = alloc_layout_range(layout, &r, LAYOUT_RANGE_REGULAR);
4249 strike = alloc_layout_range(layout, &r, LAYOUT_RANGE_STRIKETHROUGH);
4250 underline = alloc_layout_range(layout, &r, LAYOUT_RANGE_UNDERLINE);
4251 effect = alloc_layout_range(layout, &r, LAYOUT_RANGE_EFFECT);
4252 spacing = alloc_layout_range(layout, &r, LAYOUT_RANGE_SPACING);
4253 typography = alloc_layout_range(layout, &r, LAYOUT_RANGE_TYPOGRAPHY);
4254 if (!range || !strike || !effect || !spacing || !typography || !underline) {
4255 free_layout_range(range);
4256 free_layout_range(strike);
4257 free_layout_range(underline);
4258 free_layout_range(effect);
4259 free_layout_range(spacing);
4260 free_layout_range(typography);
4261 hr = E_OUTOFMEMORY;
4262 goto fail;
4265 list_add_head(&layout->ranges, &range->entry);
4266 list_add_head(&layout->strike_ranges, &strike->entry);
4267 list_add_head(&layout->underline_ranges, &underline->entry);
4268 list_add_head(&layout->effects, &effect->entry);
4269 list_add_head(&layout->spacing, &spacing->entry);
4270 list_add_head(&layout->typographies, &typography->entry);
4271 return S_OK;
4273 fail:
4274 IDWriteTextLayout2_Release(&layout->IDWriteTextLayout2_iface);
4275 return hr;
4278 HRESULT create_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, IDWriteTextLayout **ret)
4280 struct dwrite_textlayout *layout;
4281 HRESULT hr;
4283 *ret = NULL;
4285 layout = heap_alloc(sizeof(struct dwrite_textlayout));
4286 if (!layout) return E_OUTOFMEMORY;
4288 hr = init_textlayout(str, len, format, maxwidth, maxheight, layout);
4289 if (hr == S_OK)
4290 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout2_iface;
4292 return hr;
4295 HRESULT create_gdicompat_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight,
4296 FLOAT ppdip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural, IDWriteTextLayout **ret)
4298 struct dwrite_textlayout *layout;
4299 HRESULT hr;
4301 *ret = NULL;
4303 layout = heap_alloc(sizeof(struct dwrite_textlayout));
4304 if (!layout) return E_OUTOFMEMORY;
4306 hr = init_textlayout(str, len, format, maxwidth, maxheight, layout);
4307 if (hr == S_OK) {
4308 layout->measuringmode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
4310 /* set gdi-specific properties */
4311 layout->ppdip = ppdip;
4312 layout->transform = transform ? *transform : identity;
4314 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout2_iface;
4317 return hr;
4320 static HRESULT WINAPI dwritetrimmingsign_QueryInterface(IDWriteInlineObject *iface, REFIID riid, void **obj)
4322 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4324 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4326 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteInlineObject)) {
4327 *obj = iface;
4328 IDWriteInlineObject_AddRef(iface);
4329 return S_OK;
4332 *obj = NULL;
4333 return E_NOINTERFACE;
4336 static ULONG WINAPI dwritetrimmingsign_AddRef(IDWriteInlineObject *iface)
4338 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4339 ULONG ref = InterlockedIncrement(&This->ref);
4340 TRACE("(%p)->(%d)\n", This, ref);
4341 return ref;
4344 static ULONG WINAPI dwritetrimmingsign_Release(IDWriteInlineObject *iface)
4346 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4347 ULONG ref = InterlockedDecrement(&This->ref);
4349 TRACE("(%p)->(%d)\n", This, ref);
4351 if (!ref) {
4352 IDWriteTextLayout_Release(This->layout);
4353 heap_free(This);
4356 return ref;
4359 static HRESULT WINAPI dwritetrimmingsign_Draw(IDWriteInlineObject *iface, void *context, IDWriteTextRenderer *renderer,
4360 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *effect)
4362 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4363 DWRITE_TEXT_RANGE range = { 0, ~0u };
4365 TRACE("(%p)->(%p %p %.2f %.2f %d %d %p)\n", This, context, renderer, originX, originY, is_sideways, is_rtl, effect);
4367 IDWriteTextLayout_SetDrawingEffect(This->layout, effect, range);
4368 return IDWriteTextLayout_Draw(This->layout, context, renderer, originX, originY);
4371 static HRESULT WINAPI dwritetrimmingsign_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *ret)
4373 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4374 DWRITE_TEXT_METRICS metrics;
4375 HRESULT hr;
4377 TRACE("(%p)->(%p)\n", This, ret);
4379 hr = IDWriteTextLayout_GetMetrics(This->layout, &metrics);
4380 if (FAILED(hr)) {
4381 memset(ret, 0, sizeof(*ret));
4382 return hr;
4385 ret->width = metrics.width;
4386 ret->height = 0.0f;
4387 ret->baseline = 0.0f;
4388 ret->supportsSideways = FALSE;
4389 return S_OK;
4392 static HRESULT WINAPI dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
4394 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4395 FIXME("(%p)->(%p): stub\n", This, overhangs);
4396 return E_NOTIMPL;
4399 static HRESULT WINAPI dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
4400 DWRITE_BREAK_CONDITION *after)
4402 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4404 TRACE("(%p)->(%p %p)\n", This, before, after);
4406 *before = *after = DWRITE_BREAK_CONDITION_NEUTRAL;
4407 return S_OK;
4410 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl = {
4411 dwritetrimmingsign_QueryInterface,
4412 dwritetrimmingsign_AddRef,
4413 dwritetrimmingsign_Release,
4414 dwritetrimmingsign_Draw,
4415 dwritetrimmingsign_GetMetrics,
4416 dwritetrimmingsign_GetOverhangMetrics,
4417 dwritetrimmingsign_GetBreakConditions
4420 static inline BOOL is_reading_direction_horz(DWRITE_READING_DIRECTION direction)
4422 return (direction == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT) ||
4423 (direction == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
4426 static inline BOOL is_reading_direction_vert(DWRITE_READING_DIRECTION direction)
4428 return (direction == DWRITE_READING_DIRECTION_TOP_TO_BOTTOM) ||
4429 (direction == DWRITE_READING_DIRECTION_BOTTOM_TO_TOP);
4432 static inline BOOL is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction)
4434 return (direction == DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT) ||
4435 (direction == DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT);
4438 static inline BOOL is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction)
4440 return (direction == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM) ||
4441 (direction == DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP);
4444 HRESULT create_trimmingsign(IDWriteFactory2 *factory, IDWriteTextFormat *format, IDWriteInlineObject **sign)
4446 static const WCHAR ellipsisW = 0x2026;
4447 struct dwrite_trimmingsign *This;
4448 DWRITE_READING_DIRECTION reading;
4449 DWRITE_FLOW_DIRECTION flow;
4450 HRESULT hr;
4452 *sign = NULL;
4454 /* Validate reading/flow direction here, layout creation won't complain about
4455 invalid combinations. */
4456 reading = IDWriteTextFormat_GetReadingDirection(format);
4457 flow = IDWriteTextFormat_GetFlowDirection(format);
4459 if ((is_reading_direction_horz(reading) && is_flow_direction_horz(flow)) ||
4460 (is_reading_direction_vert(reading) && is_flow_direction_vert(flow)))
4461 return DWRITE_E_FLOWDIRECTIONCONFLICTS;
4463 This = heap_alloc(sizeof(*This));
4464 if (!This)
4465 return E_OUTOFMEMORY;
4467 This->IDWriteInlineObject_iface.lpVtbl = &dwritetrimmingsignvtbl;
4468 This->ref = 1;
4470 hr = IDWriteFactory2_CreateTextLayout(factory, &ellipsisW, 1, format, 0.0f, 0.0f, &This->layout);
4471 if (FAILED(hr)) {
4472 heap_free(This);
4473 return hr;
4476 IDWriteTextLayout_SetWordWrapping(This->layout, DWRITE_WORD_WRAPPING_NO_WRAP);
4477 *sign = &This->IDWriteInlineObject_iface;
4479 return S_OK;
4482 static HRESULT WINAPI dwritetextformat_QueryInterface(IDWriteTextFormat1 *iface, REFIID riid, void **obj)
4484 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4486 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4488 if (IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
4489 IsEqualIID(riid, &IID_IDWriteTextFormat) ||
4490 IsEqualIID(riid, &IID_IUnknown))
4492 *obj = iface;
4493 IDWriteTextFormat1_AddRef(iface);
4494 return S_OK;
4497 *obj = NULL;
4499 return E_NOINTERFACE;
4502 static ULONG WINAPI dwritetextformat_AddRef(IDWriteTextFormat1 *iface)
4504 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4505 ULONG ref = InterlockedIncrement(&This->ref);
4506 TRACE("(%p)->(%d)\n", This, ref);
4507 return ref;
4510 static ULONG WINAPI dwritetextformat_Release(IDWriteTextFormat1 *iface)
4512 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4513 ULONG ref = InterlockedDecrement(&This->ref);
4515 TRACE("(%p)->(%d)\n", This, ref);
4517 if (!ref)
4519 release_format_data(&This->format);
4520 heap_free(This);
4523 return ref;
4526 static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
4528 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4529 TRACE("(%p)->(%d)\n", This, alignment);
4530 return format_set_textalignment(&This->format, alignment, NULL);
4533 static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
4535 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4536 TRACE("(%p)->(%d)\n", This, alignment);
4537 return format_set_paralignment(&This->format, alignment, NULL);
4540 static HRESULT WINAPI dwritetextformat_SetWordWrapping(IDWriteTextFormat1 *iface, DWRITE_WORD_WRAPPING wrapping)
4542 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4543 TRACE("(%p)->(%d)\n", This, wrapping);
4544 return format_set_wordwrapping(&This->format, wrapping, NULL);
4547 static HRESULT WINAPI dwritetextformat_SetReadingDirection(IDWriteTextFormat1 *iface, DWRITE_READING_DIRECTION direction)
4549 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4550 TRACE("(%p)->(%d)\n", This, direction);
4551 return format_set_readingdirection(&This->format, direction, NULL);
4554 static HRESULT WINAPI dwritetextformat_SetFlowDirection(IDWriteTextFormat1 *iface, DWRITE_FLOW_DIRECTION direction)
4556 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4558 TRACE("(%p)->(%d)\n", This, direction);
4560 if ((UINT32)direction > DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT)
4561 return E_INVALIDARG;
4563 This->format.flow = direction;
4564 return S_OK;
4567 static HRESULT WINAPI dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat1 *iface, FLOAT tabstop)
4569 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4570 FIXME("(%p)->(%f): stub\n", This, tabstop);
4571 return E_NOTIMPL;
4574 static HRESULT WINAPI dwritetextformat_SetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING const *trimming,
4575 IDWriteInlineObject *trimming_sign)
4577 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4578 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
4580 This->format.trimming = *trimming;
4581 if (This->format.trimmingsign)
4582 IDWriteInlineObject_Release(This->format.trimmingsign);
4583 This->format.trimmingsign = trimming_sign;
4584 if (This->format.trimmingsign)
4585 IDWriteInlineObject_AddRef(This->format.trimmingsign);
4586 return S_OK;
4589 static HRESULT WINAPI dwritetextformat_SetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD method,
4590 FLOAT spacing, FLOAT baseline)
4592 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4594 TRACE("(%p)->(%d %f %f)\n", This, method, spacing, baseline);
4596 if (spacing < 0.0f || (UINT32)method > DWRITE_LINE_SPACING_METHOD_UNIFORM)
4597 return E_INVALIDARG;
4599 This->format.spacingmethod = method;
4600 This->format.spacing = spacing;
4601 This->format.baseline = baseline;
4602 return S_OK;
4605 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_GetTextAlignment(IDWriteTextFormat1 *iface)
4607 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4608 TRACE("(%p)\n", This);
4609 return This->format.textalignment;
4612 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_GetParagraphAlignment(IDWriteTextFormat1 *iface)
4614 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4615 TRACE("(%p)\n", This);
4616 return This->format.paralign;
4619 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_GetWordWrapping(IDWriteTextFormat1 *iface)
4621 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4622 TRACE("(%p)\n", This);
4623 return This->format.wrapping;
4626 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_GetReadingDirection(IDWriteTextFormat1 *iface)
4628 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4629 TRACE("(%p)\n", This);
4630 return This->format.readingdir;
4633 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_GetFlowDirection(IDWriteTextFormat1 *iface)
4635 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4636 TRACE("(%p)\n", This);
4637 return This->format.flow;
4640 static FLOAT WINAPI dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat1 *iface)
4642 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4643 FIXME("(%p): stub\n", This);
4644 return 0.0f;
4647 static HRESULT WINAPI dwritetextformat_GetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING *options,
4648 IDWriteInlineObject **trimming_sign)
4650 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4651 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
4653 *options = This->format.trimming;
4654 if ((*trimming_sign = This->format.trimmingsign))
4655 IDWriteInlineObject_AddRef(*trimming_sign);
4657 return S_OK;
4660 static HRESULT WINAPI dwritetextformat_GetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD *method,
4661 FLOAT *spacing, FLOAT *baseline)
4663 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4664 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
4666 *method = This->format.spacingmethod;
4667 *spacing = This->format.spacing;
4668 *baseline = This->format.baseline;
4669 return S_OK;
4672 static HRESULT WINAPI dwritetextformat_GetFontCollection(IDWriteTextFormat1 *iface, IDWriteFontCollection **collection)
4674 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4676 TRACE("(%p)->(%p)\n", This, collection);
4678 *collection = This->format.collection;
4679 IDWriteFontCollection_AddRef(*collection);
4681 return S_OK;
4684 static UINT32 WINAPI dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat1 *iface)
4686 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4687 TRACE("(%p)\n", This);
4688 return This->format.family_len;
4691 static HRESULT WINAPI dwritetextformat_GetFontFamilyName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
4693 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4695 TRACE("(%p)->(%p %u)\n", This, name, size);
4697 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
4698 strcpyW(name, This->format.family_name);
4699 return S_OK;
4702 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_GetFontWeight(IDWriteTextFormat1 *iface)
4704 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4705 TRACE("(%p)\n", This);
4706 return This->format.weight;
4709 static DWRITE_FONT_STYLE WINAPI dwritetextformat_GetFontStyle(IDWriteTextFormat1 *iface)
4711 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4712 TRACE("(%p)\n", This);
4713 return This->format.style;
4716 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_GetFontStretch(IDWriteTextFormat1 *iface)
4718 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4719 TRACE("(%p)\n", This);
4720 return This->format.stretch;
4723 static FLOAT WINAPI dwritetextformat_GetFontSize(IDWriteTextFormat1 *iface)
4725 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4726 TRACE("(%p)\n", This);
4727 return This->format.fontsize;
4730 static UINT32 WINAPI dwritetextformat_GetLocaleNameLength(IDWriteTextFormat1 *iface)
4732 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4733 TRACE("(%p)\n", This);
4734 return This->format.locale_len;
4737 static HRESULT WINAPI dwritetextformat_GetLocaleName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
4739 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4741 TRACE("(%p)->(%p %u)\n", This, name, size);
4743 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
4744 strcpyW(name, This->format.locale);
4745 return S_OK;
4748 static HRESULT WINAPI dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat1 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4750 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4752 TRACE("(%p)->(%d)\n", This, orientation);
4754 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
4755 return E_INVALIDARG;
4757 This->format.vertical_orientation = orientation;
4758 return S_OK;
4761 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat1 *iface)
4763 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4764 TRACE("(%p)\n", This);
4765 return This->format.vertical_orientation;
4768 static HRESULT WINAPI dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat1 *iface, BOOL lastline_wrapping_enabled)
4770 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4772 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
4774 This->format.last_line_wrapping = !!lastline_wrapping_enabled;
4775 return S_OK;
4778 static BOOL WINAPI dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat1 *iface)
4780 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4781 TRACE("(%p)\n", This);
4782 return This->format.last_line_wrapping;
4785 static HRESULT WINAPI dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat1 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
4787 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4788 TRACE("(%p)->(%d)\n", This, alignment);
4789 return format_set_optical_alignment(&This->format, alignment);
4792 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat1 *iface)
4794 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4795 TRACE("(%p)\n", This);
4796 return This->format.optical_alignment;
4799 static HRESULT WINAPI dwritetextformat1_SetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback *fallback)
4801 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4802 TRACE("(%p)->(%p)\n", This, fallback);
4803 return set_fontfallback_for_format(&This->format, fallback);
4806 static HRESULT WINAPI dwritetextformat1_GetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback **fallback)
4808 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4809 TRACE("(%p)->(%p)\n", This, fallback);
4810 return get_fontfallback_from_format(&This->format, fallback);
4813 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl = {
4814 dwritetextformat_QueryInterface,
4815 dwritetextformat_AddRef,
4816 dwritetextformat_Release,
4817 dwritetextformat_SetTextAlignment,
4818 dwritetextformat_SetParagraphAlignment,
4819 dwritetextformat_SetWordWrapping,
4820 dwritetextformat_SetReadingDirection,
4821 dwritetextformat_SetFlowDirection,
4822 dwritetextformat_SetIncrementalTabStop,
4823 dwritetextformat_SetTrimming,
4824 dwritetextformat_SetLineSpacing,
4825 dwritetextformat_GetTextAlignment,
4826 dwritetextformat_GetParagraphAlignment,
4827 dwritetextformat_GetWordWrapping,
4828 dwritetextformat_GetReadingDirection,
4829 dwritetextformat_GetFlowDirection,
4830 dwritetextformat_GetIncrementalTabStop,
4831 dwritetextformat_GetTrimming,
4832 dwritetextformat_GetLineSpacing,
4833 dwritetextformat_GetFontCollection,
4834 dwritetextformat_GetFontFamilyNameLength,
4835 dwritetextformat_GetFontFamilyName,
4836 dwritetextformat_GetFontWeight,
4837 dwritetextformat_GetFontStyle,
4838 dwritetextformat_GetFontStretch,
4839 dwritetextformat_GetFontSize,
4840 dwritetextformat_GetLocaleNameLength,
4841 dwritetextformat_GetLocaleName,
4842 dwritetextformat1_SetVerticalGlyphOrientation,
4843 dwritetextformat1_GetVerticalGlyphOrientation,
4844 dwritetextformat1_SetLastLineWrapping,
4845 dwritetextformat1_GetLastLineWrapping,
4846 dwritetextformat1_SetOpticalAlignment,
4847 dwritetextformat1_GetOpticalAlignment,
4848 dwritetextformat1_SetFontFallback,
4849 dwritetextformat1_GetFontFallback
4852 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat *iface)
4854 return (iface->lpVtbl == (IDWriteTextFormatVtbl*)&dwritetextformatvtbl) ?
4855 CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat1_iface) : NULL;
4858 HRESULT create_textformat(const WCHAR *family_name, IDWriteFontCollection *collection, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style,
4859 DWRITE_FONT_STRETCH stretch, FLOAT size, const WCHAR *locale, IDWriteTextFormat **format)
4861 struct dwrite_textformat *This;
4863 *format = NULL;
4865 This = heap_alloc(sizeof(struct dwrite_textformat));
4866 if (!This) return E_OUTOFMEMORY;
4868 This->IDWriteTextFormat1_iface.lpVtbl = &dwritetextformatvtbl;
4869 This->ref = 1;
4870 This->format.family_name = heap_strdupW(family_name);
4871 This->format.family_len = strlenW(family_name);
4872 This->format.locale = heap_strdupW(locale);
4873 This->format.locale_len = strlenW(locale);
4874 /* force locale name to lower case, layout will inherit this modified value */
4875 strlwrW(This->format.locale);
4876 This->format.weight = weight;
4877 This->format.style = style;
4878 This->format.fontsize = size;
4879 This->format.stretch = stretch;
4880 This->format.textalignment = DWRITE_TEXT_ALIGNMENT_LEADING;
4881 This->format.optical_alignment = DWRITE_OPTICAL_ALIGNMENT_NONE;
4882 This->format.paralign = DWRITE_PARAGRAPH_ALIGNMENT_NEAR;
4883 This->format.wrapping = DWRITE_WORD_WRAPPING_WRAP;
4884 This->format.last_line_wrapping = TRUE;
4885 This->format.readingdir = DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
4886 This->format.flow = DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM;
4887 This->format.spacingmethod = DWRITE_LINE_SPACING_METHOD_DEFAULT;
4888 This->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
4889 This->format.spacing = 0.0f;
4890 This->format.baseline = 0.0f;
4891 This->format.trimming.granularity = DWRITE_TRIMMING_GRANULARITY_NONE;
4892 This->format.trimming.delimiter = 0;
4893 This->format.trimming.delimiterCount = 0;
4894 This->format.trimmingsign = NULL;
4895 This->format.collection = collection;
4896 This->format.fallback = NULL;
4897 IDWriteFontCollection_AddRef(collection);
4899 *format = (IDWriteTextFormat*)&This->IDWriteTextFormat1_iface;
4901 return S_OK;
4904 static HRESULT WINAPI dwritetypography_QueryInterface(IDWriteTypography *iface, REFIID riid, void **obj)
4906 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4908 TRACE("(%p)->(%s %p)\n", typography, debugstr_guid(riid), obj);
4910 if (IsEqualIID(riid, &IID_IDWriteTypography) || IsEqualIID(riid, &IID_IUnknown)) {
4911 *obj = iface;
4912 IDWriteTypography_AddRef(iface);
4913 return S_OK;
4916 *obj = NULL;
4918 return E_NOINTERFACE;
4921 static ULONG WINAPI dwritetypography_AddRef(IDWriteTypography *iface)
4923 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4924 ULONG ref = InterlockedIncrement(&typography->ref);
4925 TRACE("(%p)->(%d)\n", typography, ref);
4926 return ref;
4929 static ULONG WINAPI dwritetypography_Release(IDWriteTypography *iface)
4931 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4932 ULONG ref = InterlockedDecrement(&typography->ref);
4934 TRACE("(%p)->(%d)\n", typography, ref);
4936 if (!ref) {
4937 heap_free(typography->features);
4938 heap_free(typography);
4941 return ref;
4944 static HRESULT WINAPI dwritetypography_AddFontFeature(IDWriteTypography *iface, DWRITE_FONT_FEATURE feature)
4946 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4948 TRACE("(%p)->(%x %u)\n", typography, feature.nameTag, feature.parameter);
4950 if (typography->count == typography->allocated) {
4951 DWRITE_FONT_FEATURE *ptr = heap_realloc(typography->features, 2*typography->allocated*sizeof(DWRITE_FONT_FEATURE));
4952 if (!ptr)
4953 return E_OUTOFMEMORY;
4955 typography->features = ptr;
4956 typography->allocated *= 2;
4959 typography->features[typography->count++] = feature;
4960 return S_OK;
4963 static UINT32 WINAPI dwritetypography_GetFontFeatureCount(IDWriteTypography *iface)
4965 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4966 TRACE("(%p)\n", typography);
4967 return typography->count;
4970 static HRESULT WINAPI dwritetypography_GetFontFeature(IDWriteTypography *iface, UINT32 index, DWRITE_FONT_FEATURE *feature)
4972 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4974 TRACE("(%p)->(%u %p)\n", typography, index, feature);
4976 if (index >= typography->count)
4977 return E_INVALIDARG;
4979 *feature = typography->features[index];
4980 return S_OK;
4983 static const IDWriteTypographyVtbl dwritetypographyvtbl = {
4984 dwritetypography_QueryInterface,
4985 dwritetypography_AddRef,
4986 dwritetypography_Release,
4987 dwritetypography_AddFontFeature,
4988 dwritetypography_GetFontFeatureCount,
4989 dwritetypography_GetFontFeature
4992 HRESULT create_typography(IDWriteTypography **ret)
4994 struct dwrite_typography *typography;
4996 *ret = NULL;
4998 typography = heap_alloc(sizeof(*typography));
4999 if (!typography)
5000 return E_OUTOFMEMORY;
5002 typography->IDWriteTypography_iface.lpVtbl = &dwritetypographyvtbl;
5003 typography->ref = 1;
5004 typography->allocated = 2;
5005 typography->count = 0;
5007 typography->features = heap_alloc(typography->allocated*sizeof(DWRITE_FONT_FEATURE));
5008 if (!typography->features) {
5009 heap_free(typography);
5010 return E_OUTOFMEMORY;
5013 *ret = &typography->IDWriteTypography_iface;
5014 return S_OK;