shell32/tests: Create_test_association() should either succeed or fail due to insuffi...
[wine.git] / dlls / dwrite / layout.c
blob02772ffc2a3a5787a5e3f675da559ef2484b1f68
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_STRIKETHROUGH,
106 LAYOUT_RANGE_EFFECT,
107 LAYOUT_RANGE_SPACING,
108 LAYOUT_RANGE_TYPOGRAPHY
111 struct layout_range_header {
112 struct list entry;
113 enum layout_range_kind kind;
114 DWRITE_TEXT_RANGE range;
117 struct layout_range {
118 struct layout_range_header h;
119 DWRITE_FONT_WEIGHT weight;
120 DWRITE_FONT_STYLE style;
121 FLOAT fontsize;
122 DWRITE_FONT_STRETCH stretch;
123 IDWriteInlineObject *object;
124 BOOL underline;
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 FLOAT origin_x; /* baseline X position */
188 FLOAT origin_y; /* baseline Y position */
189 FLOAT align_dx; /* adjustment from text alignment */
190 FLOAT width; /* run width */
191 UINT16 *clustermap; /* effective clustermap, allocated separately, is not reused from nominal map */
192 UINT32 line;
195 struct layout_effective_inline {
196 struct list entry;
197 IDWriteInlineObject *object;
198 IUnknown *effect;
199 FLOAT origin_x;
200 FLOAT origin_y;
201 FLOAT align_dx;
202 FLOAT width;
203 BOOL is_sideways;
204 BOOL is_rtl;
205 UINT32 line;
208 struct layout_strikethrough {
209 struct list entry;
210 const struct layout_effective_run *run;
211 DWRITE_STRIKETHROUGH s;
214 struct layout_cluster {
215 const struct layout_run *run; /* link to nominal run this cluster belongs to */
216 UINT32 position; /* relative to run, first cluster has 0 position */
219 enum layout_recompute_mask {
220 RECOMPUTE_NOMINAL_RUNS = 1 << 0,
221 RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
222 RECOMPUTE_EFFECTIVE_RUNS = 1 << 2,
223 RECOMPUTE_EVERYTHING = 0xffff
226 struct dwrite_textlayout {
227 IDWriteTextLayout2 IDWriteTextLayout2_iface;
228 IDWriteTextFormat1 IDWriteTextFormat1_iface;
229 IDWriteTextAnalysisSink IDWriteTextAnalysisSink_iface;
230 IDWriteTextAnalysisSource IDWriteTextAnalysisSource_iface;
231 LONG ref;
233 WCHAR *str;
234 UINT32 len;
235 struct dwrite_textformat_data format;
236 struct list strike_ranges;
237 struct list typographies;
238 struct list effects;
239 struct list spacing;
240 struct list ranges;
241 struct list runs;
242 /* lists ready to use by Draw() */
243 struct list eruns;
244 struct list inlineobjects;
245 struct list strikethrough;
246 USHORT recompute;
248 DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
249 DWRITE_LINE_BREAKPOINT *actual_breakpoints;
251 struct layout_cluster *clusters;
252 DWRITE_CLUSTER_METRICS *clustermetrics;
253 UINT32 cluster_count;
254 FLOAT minwidth;
256 DWRITE_LINE_METRICS *lines;
257 UINT32 line_alloc;
259 DWRITE_TEXT_METRICS1 metrics;
261 DWRITE_MEASURING_MODE measuringmode;
263 /* gdi-compatible layout specifics */
264 FLOAT ppdip;
265 DWRITE_MATRIX transform;
268 struct dwrite_textformat {
269 IDWriteTextFormat1 IDWriteTextFormat1_iface;
270 LONG ref;
271 struct dwrite_textformat_data format;
274 struct dwrite_trimmingsign {
275 IDWriteInlineObject IDWriteInlineObject_iface;
276 LONG ref;
278 IDWriteTextLayout *layout;
281 struct dwrite_typography {
282 IDWriteTypography IDWriteTypography_iface;
283 LONG ref;
285 DWRITE_FONT_FEATURE *features;
286 UINT32 allocated;
287 UINT32 count;
290 struct dwrite_vec {
291 FLOAT x;
292 FLOAT y;
295 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl;
297 static void release_format_data(struct dwrite_textformat_data *data)
299 if (data->collection) IDWriteFontCollection_Release(data->collection);
300 if (data->fallback) IDWriteFontFallback_Release(data->fallback);
301 if (data->trimmingsign) IDWriteInlineObject_Release(data->trimmingsign);
302 heap_free(data->family_name);
303 heap_free(data->locale);
306 static inline struct dwrite_textlayout *impl_from_IDWriteTextLayout2(IDWriteTextLayout2 *iface)
308 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextLayout2_iface);
311 static inline struct dwrite_textlayout *impl_layout_form_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
313 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextFormat1_iface);
316 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSink(IDWriteTextAnalysisSink *iface)
318 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSink_iface);
321 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSource(IDWriteTextAnalysisSource *iface)
323 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSource_iface);
326 static inline struct dwrite_textformat *impl_from_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
328 return CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat1_iface);
331 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat*);
333 static inline struct dwrite_trimmingsign *impl_from_IDWriteInlineObject(IDWriteInlineObject *iface)
335 return CONTAINING_RECORD(iface, struct dwrite_trimmingsign, IDWriteInlineObject_iface);
338 static inline struct dwrite_typography *impl_from_IDWriteTypography(IDWriteTypography *iface)
340 return CONTAINING_RECORD(iface, struct dwrite_typography, IDWriteTypography_iface);
343 static inline const char *debugstr_run(const struct regular_layout_run *run)
345 return wine_dbg_sprintf("[%u,%u)", run->descr.textPosition, run->descr.textPosition +
346 run->descr.stringLength);
349 static inline BOOL is_layout_gdi_compatible(struct dwrite_textlayout *layout)
351 return layout->measuringmode != DWRITE_MEASURING_MODE_NATURAL;
354 static inline HRESULT format_set_textalignment(struct dwrite_textformat_data *format, DWRITE_TEXT_ALIGNMENT alignment,
355 BOOL *changed)
357 if ((UINT32)alignment > DWRITE_TEXT_ALIGNMENT_JUSTIFIED)
358 return E_INVALIDARG;
359 if (changed) *changed = format->textalignment != alignment;
360 format->textalignment = alignment;
361 return S_OK;
364 static inline HRESULT format_set_paralignment(struct dwrite_textformat_data *format,
365 DWRITE_PARAGRAPH_ALIGNMENT alignment, BOOL *changed)
367 if ((UINT32)alignment > DWRITE_PARAGRAPH_ALIGNMENT_CENTER)
368 return E_INVALIDARG;
369 if (changed) *changed = format->paralign != alignment;
370 format->paralign = alignment;
371 return S_OK;
374 static inline HRESULT format_set_readingdirection(struct dwrite_textformat_data *format,
375 DWRITE_READING_DIRECTION direction, BOOL *changed)
377 if ((UINT32)direction > DWRITE_READING_DIRECTION_BOTTOM_TO_TOP)
378 return E_INVALIDARG;
379 if (changed) *changed = format->readingdir != direction;
380 format->readingdir = direction;
381 return S_OK;
384 static inline HRESULT format_set_wordwrapping(struct dwrite_textformat_data *format,
385 DWRITE_WORD_WRAPPING wrapping, BOOL *changed)
387 if ((UINT32)wrapping > DWRITE_WORD_WRAPPING_CHARACTER)
388 return E_INVALIDARG;
389 if (changed) *changed = format->wrapping != wrapping;
390 format->wrapping = wrapping;
391 return S_OK;
394 static HRESULT get_fontfallback_from_format(const struct dwrite_textformat_data *format, IDWriteFontFallback **fallback)
396 *fallback = format->fallback;
397 if (*fallback)
398 IDWriteFontFallback_AddRef(*fallback);
399 return S_OK;
402 static HRESULT set_fontfallback_for_format(struct dwrite_textformat_data *format, IDWriteFontFallback *fallback)
404 if (format->fallback)
405 IDWriteFontFallback_Release(format->fallback);
406 format->fallback = fallback;
407 if (fallback)
408 IDWriteFontFallback_AddRef(fallback);
409 return S_OK;
412 static HRESULT format_set_optical_alignment(struct dwrite_textformat_data *format,
413 DWRITE_OPTICAL_ALIGNMENT alignment)
415 if ((UINT32)alignment > DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS)
416 return E_INVALIDARG;
417 format->optical_alignment = alignment;
418 return S_OK;
421 static struct layout_run *alloc_layout_run(enum layout_run_kind kind)
423 struct layout_run *ret;
425 ret = heap_alloc(sizeof(*ret));
426 if (!ret) return NULL;
428 memset(ret, 0, sizeof(*ret));
429 ret->kind = kind;
430 if (kind == LAYOUT_RUN_REGULAR) {
431 ret->u.regular.sa.script = Script_Unknown;
432 ret->u.regular.sa.shapes = DWRITE_SCRIPT_SHAPES_DEFAULT;
435 return ret;
438 static void free_layout_runs(struct dwrite_textlayout *layout)
440 struct layout_run *cur, *cur2;
441 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->runs, struct layout_run, entry) {
442 list_remove(&cur->entry);
443 if (cur->kind == LAYOUT_RUN_REGULAR) {
444 if (cur->u.regular.run.fontFace)
445 IDWriteFontFace_Release(cur->u.regular.run.fontFace);
446 heap_free(cur->u.regular.glyphs);
447 heap_free(cur->u.regular.clustermap);
448 heap_free(cur->u.regular.advances);
449 heap_free(cur->u.regular.offsets);
451 heap_free(cur);
455 static void free_layout_eruns(struct dwrite_textlayout *layout)
457 struct layout_effective_inline *in, *in2;
458 struct layout_effective_run *cur, *cur2;
459 struct layout_strikethrough *s, *s2;
461 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->eruns, struct layout_effective_run, entry) {
462 list_remove(&cur->entry);
463 heap_free(cur->clustermap);
464 heap_free(cur);
467 LIST_FOR_EACH_ENTRY_SAFE(in, in2, &layout->inlineobjects, struct layout_effective_inline, entry) {
468 list_remove(&in->entry);
469 heap_free(in);
472 LIST_FOR_EACH_ENTRY_SAFE(s, s2, &layout->strikethrough, struct layout_strikethrough, entry) {
473 list_remove(&s->entry);
474 heap_free(s);
478 /* Used to resolve break condition by forcing stronger condition over weaker. */
479 static inline DWRITE_BREAK_CONDITION override_break_condition(DWRITE_BREAK_CONDITION existingbreak, DWRITE_BREAK_CONDITION newbreak)
481 switch (existingbreak) {
482 case DWRITE_BREAK_CONDITION_NEUTRAL:
483 return newbreak;
484 case DWRITE_BREAK_CONDITION_CAN_BREAK:
485 return newbreak == DWRITE_BREAK_CONDITION_NEUTRAL ? existingbreak : newbreak;
486 /* let's keep stronger conditions as is */
487 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK:
488 case DWRITE_BREAK_CONDITION_MUST_BREAK:
489 break;
490 default:
491 ERR("unknown break condition %d\n", existingbreak);
494 return existingbreak;
497 /* This helper should be used to get effective range length, in other words it returns number of text
498 positions from range starting point to the end of the range, limited by layout text length */
499 static inline UINT32 get_clipped_range_length(const struct dwrite_textlayout *layout, const struct layout_range *range)
501 if (range->h.range.startPosition + range->h.range.length <= layout->len)
502 return range->h.range.length;
503 return layout->len - range->h.range.startPosition;
506 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
507 static HRESULT layout_update_breakpoints_range(struct dwrite_textlayout *layout, const struct layout_range *cur)
509 DWRITE_BREAK_CONDITION before, after;
510 UINT32 i, length;
511 HRESULT hr;
513 /* ignore returned conditions if failed */
514 hr = IDWriteInlineObject_GetBreakConditions(cur->object, &before, &after);
515 if (FAILED(hr))
516 after = before = DWRITE_BREAK_CONDITION_NEUTRAL;
518 if (!layout->actual_breakpoints) {
519 layout->actual_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
520 if (!layout->actual_breakpoints)
521 return E_OUTOFMEMORY;
522 memcpy(layout->actual_breakpoints, layout->nominal_breakpoints, sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
525 length = get_clipped_range_length(layout, cur);
526 for (i = cur->h.range.startPosition; i < length + cur->h.range.startPosition; i++) {
527 /* for first codepoint check if there's anything before it and update accordingly */
528 if (i == cur->h.range.startPosition) {
529 if (i > 0)
530 layout->actual_breakpoints[i].breakConditionBefore = layout->actual_breakpoints[i-1].breakConditionAfter =
531 override_break_condition(layout->actual_breakpoints[i-1].breakConditionAfter, before);
532 else
533 layout->actual_breakpoints[i].breakConditionBefore = before;
534 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
536 /* similar check for last codepoint */
537 else if (i == cur->h.range.startPosition + length - 1) {
538 if (i == layout->len - 1)
539 layout->actual_breakpoints[i].breakConditionAfter = after;
540 else
541 layout->actual_breakpoints[i].breakConditionAfter = layout->actual_breakpoints[i+1].breakConditionBefore =
542 override_break_condition(layout->actual_breakpoints[i+1].breakConditionBefore, after);
543 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
545 /* for all positions within a range disable breaks */
546 else {
547 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
548 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
551 layout->actual_breakpoints[i].isWhitespace = FALSE;
552 layout->actual_breakpoints[i].isSoftHyphen = FALSE;
555 return S_OK;
558 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos);
560 static inline DWRITE_LINE_BREAKPOINT get_effective_breakpoint(const struct dwrite_textlayout *layout, UINT32 pos)
562 if (layout->actual_breakpoints)
563 return layout->actual_breakpoints[pos];
564 return layout->nominal_breakpoints[pos];
567 static inline void init_cluster_metrics(const struct dwrite_textlayout *layout, const struct regular_layout_run *run,
568 UINT16 start_glyph, UINT16 stop_glyph, UINT32 stop_position, UINT16 length, DWRITE_CLUSTER_METRICS *metrics)
570 UINT8 breakcondition;
571 UINT32 position;
572 UINT16 j;
574 /* For clusters made of control chars we report zero glyphs, and we need zero cluster
575 width as well; advances are already computed at this point and are not necessary zero. */
576 metrics->width = 0.0f;
577 if (run->run.glyphCount) {
578 for (j = start_glyph; j < stop_glyph; j++)
579 metrics->width += run->run.glyphAdvances[j];
581 metrics->length = length;
583 position = stop_position;
584 if (stop_glyph == run->glyphcount)
585 breakcondition = get_effective_breakpoint(layout, stop_position).breakConditionAfter;
586 else {
587 breakcondition = get_effective_breakpoint(layout, stop_position).breakConditionBefore;
588 if (stop_position) position = stop_position - 1;
591 metrics->canWrapLineAfter = breakcondition == DWRITE_BREAK_CONDITION_CAN_BREAK ||
592 breakcondition == DWRITE_BREAK_CONDITION_MUST_BREAK;
593 if (metrics->length == 1) {
594 WORD type = 0;
596 GetStringTypeW(CT_CTYPE1, &layout->str[position], 1, &type);
597 metrics->isWhitespace = !!(type & C1_SPACE);
598 metrics->isNewline = FALSE /* FIXME */;
599 metrics->isSoftHyphen = layout->str[position] == 0x00ad /* Unicode Soft Hyphen */;
601 else {
602 metrics->isWhitespace = FALSE;
603 metrics->isNewline = FALSE;
604 metrics->isSoftHyphen = FALSE;
606 metrics->isRightToLeft = run->run.bidiLevel & 1;
607 metrics->padding = 0;
612 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
613 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
614 Note that there's no need to reallocate anything at this point as we allocate one cluster per
615 codepoint initially.
618 static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 *cluster)
620 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[*cluster];
621 struct layout_cluster *c = &layout->clusters[*cluster];
622 const struct regular_layout_run *run = &r->u.regular;
623 UINT32 i, start = 0;
625 for (i = 0; i < run->descr.stringLength; i++) {
626 BOOL end = i == run->descr.stringLength - 1;
628 if (run->descr.clusterMap[start] != run->descr.clusterMap[i]) {
629 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->descr.clusterMap[i], i,
630 i - start, metrics);
631 c->position = start;
632 c->run = r;
634 *cluster += 1;
635 metrics++;
636 c++;
637 start = i;
640 if (end) {
641 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->glyphcount, i,
642 i - start + 1, metrics);
643 c->position = start;
644 c->run = r;
646 *cluster += 1;
647 return;
652 static inline FLOAT get_scaled_font_metric(UINT32 metric, FLOAT emSize, const DWRITE_FONT_METRICS *metrics)
654 return (FLOAT)metric * emSize / (FLOAT)metrics->designUnitsPerEm;
657 static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
659 IDWriteTextAnalyzer *analyzer;
660 struct layout_range *range;
661 struct layout_run *r;
662 UINT32 cluster = 0;
663 HRESULT hr;
665 free_layout_eruns(layout);
666 free_layout_runs(layout);
668 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
669 if (!layout->clustermetrics) {
670 layout->clustermetrics = heap_alloc(layout->len*sizeof(*layout->clustermetrics));
671 layout->clusters = heap_alloc(layout->len*sizeof(*layout->clusters));
672 if (!layout->clustermetrics || !layout->clusters) {
673 heap_free(layout->clustermetrics);
674 heap_free(layout->clusters);
675 return E_OUTOFMEMORY;
678 layout->cluster_count = 0;
680 hr = get_textanalyzer(&analyzer);
681 if (FAILED(hr))
682 return hr;
684 LIST_FOR_EACH_ENTRY(range, &layout->ranges, struct layout_range, h.entry) {
685 /* we don't care about ranges that don't contain any text */
686 if (range->h.range.startPosition >= layout->len)
687 break;
689 /* inline objects override actual text in a range */
690 if (range->object) {
691 hr = layout_update_breakpoints_range(layout, range);
692 if (FAILED(hr))
693 return hr;
695 r = alloc_layout_run(LAYOUT_RUN_INLINE);
696 if (!r)
697 return E_OUTOFMEMORY;
699 r->u.object.object = range->object;
700 r->u.object.length = get_clipped_range_length(layout, range);
701 list_add_tail(&layout->runs, &r->entry);
702 continue;
705 /* initial splitting by script */
706 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, &layout->IDWriteTextAnalysisSource_iface,
707 range->h.range.startPosition, get_clipped_range_length(layout, range), &layout->IDWriteTextAnalysisSink_iface);
708 if (FAILED(hr))
709 break;
711 /* this splits it further */
712 hr = IDWriteTextAnalyzer_AnalyzeBidi(analyzer, &layout->IDWriteTextAnalysisSource_iface,
713 range->h.range.startPosition, get_clipped_range_length(layout, range), &layout->IDWriteTextAnalysisSink_iface);
714 if (FAILED(hr))
715 break;
718 /* fill run info */
719 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
720 DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props = NULL;
721 DWRITE_SHAPING_TEXT_PROPERTIES *text_props = NULL;
722 struct regular_layout_run *run = &r->u.regular;
723 DWRITE_FONT_METRICS fontmetrics = { 0 };
724 IDWriteFontFamily *family;
725 UINT32 index, max_count;
726 IDWriteFont *font;
727 BOOL exists = TRUE;
729 /* we need to do very little in case of inline objects */
730 if (r->kind == LAYOUT_RUN_INLINE) {
731 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[cluster];
732 struct layout_cluster *c = &layout->clusters[cluster];
733 DWRITE_INLINE_OBJECT_METRICS inlinemetrics;
735 metrics->width = 0.0f;
736 metrics->length = r->u.object.length;
737 metrics->canWrapLineAfter = FALSE;
738 metrics->isWhitespace = FALSE;
739 metrics->isNewline = FALSE;
740 metrics->isSoftHyphen = FALSE;
741 metrics->isRightToLeft = FALSE;
742 metrics->padding = 0;
743 c->run = r;
744 c->position = 0; /* there's always one cluster per inline object, so 0 is valid value */
745 cluster++;
747 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
748 hr = IDWriteInlineObject_GetMetrics(r->u.object.object, &inlinemetrics);
749 if (FAILED(hr)) {
750 memset(&inlinemetrics, 0, sizeof(inlinemetrics));
751 hr = S_OK;
753 metrics->width = inlinemetrics.width;
754 r->baseline = inlinemetrics.baseline;
755 r->height = inlinemetrics.height;
757 /* FIXME: use resolved breakpoints in this case too */
759 continue;
762 range = get_layout_range_by_pos(layout, run->descr.textPosition);
764 hr = IDWriteFontCollection_FindFamilyName(range->collection, range->fontfamily, &index, &exists);
765 if (FAILED(hr) || !exists) {
766 WARN("%s: family %s not found in collection %p\n", debugstr_run(run), debugstr_w(range->fontfamily), range->collection);
767 continue;
770 hr = IDWriteFontCollection_GetFontFamily(range->collection, index, &family);
771 if (FAILED(hr))
772 continue;
774 hr = IDWriteFontFamily_GetFirstMatchingFont(family, range->weight, range->stretch, range->style, &font);
775 IDWriteFontFamily_Release(family);
776 if (FAILED(hr)) {
777 WARN("%s: failed to get a matching font\n", debugstr_run(run));
778 continue;
781 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
782 IDWriteFont_Release(font);
783 if (FAILED(hr))
784 continue;
786 run->run.fontEmSize = range->fontsize;
787 run->descr.localeName = range->locale;
788 run->clustermap = heap_alloc(run->descr.stringLength*sizeof(UINT16));
790 max_count = 3*run->descr.stringLength/2 + 16;
791 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
792 if (!run->clustermap || !run->glyphs)
793 goto memerr;
795 text_props = heap_alloc(run->descr.stringLength*sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
796 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
797 if (!text_props || !glyph_props)
798 goto memerr;
800 while (1) {
801 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, run->descr.string, run->descr.stringLength,
802 run->run.fontFace, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
803 NULL /* FIXME */, NULL, NULL, 0, max_count, run->clustermap, text_props, run->glyphs, glyph_props,
804 &run->glyphcount);
805 if (hr == E_NOT_SUFFICIENT_BUFFER) {
806 heap_free(run->glyphs);
807 heap_free(glyph_props);
809 max_count = run->glyphcount;
811 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
812 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
813 if (!run->glyphs || !glyph_props)
814 goto memerr;
816 continue;
819 break;
822 if (FAILED(hr)) {
823 heap_free(text_props);
824 heap_free(glyph_props);
825 WARN("%s: shaping failed 0x%08x\n", debugstr_run(run), hr);
826 continue;
829 run->run.glyphIndices = run->glyphs;
830 run->descr.clusterMap = run->clustermap;
832 run->advances = heap_alloc(run->glyphcount*sizeof(FLOAT));
833 run->offsets = heap_alloc(run->glyphcount*sizeof(DWRITE_GLYPH_OFFSET));
834 if (!run->advances || !run->offsets)
835 goto memerr;
837 /* now set advances and offsets */
838 if (is_layout_gdi_compatible(layout))
839 hr = IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap,
840 text_props, run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount,
841 run->run.fontFace, run->run.fontEmSize, layout->ppdip, &layout->transform,
842 layout->measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->run.isSideways,
843 run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL, NULL, 0, run->advances, run->offsets);
844 else
845 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap, text_props,
846 run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount, run->run.fontFace,
847 run->run.fontEmSize, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
848 NULL, NULL, 0, run->advances, run->offsets);
850 heap_free(text_props);
851 heap_free(glyph_props);
852 if (FAILED(hr))
853 WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_run(run), hr);
855 run->run.glyphAdvances = run->advances;
856 run->run.glyphOffsets = run->offsets;
858 /* Special treatment of control script, shaping code adds normal glyphs for it,
859 with non-zero advances, and layout code exposes those as zero width clusters,
860 so we have to do it manually. */
861 if (run->sa.script == Script_Common)
862 run->run.glyphCount = 0;
863 else
864 run->run.glyphCount = run->glyphcount;
866 /* baseline derived from font metrics */
867 if (is_layout_gdi_compatible(layout)) {
868 hr = IDWriteFontFace_GetGdiCompatibleMetrics(run->run.fontFace,
869 run->run.fontEmSize,
870 layout->ppdip,
871 &layout->transform,
872 &fontmetrics);
873 if (FAILED(hr))
874 WARN("failed to get compat metrics, 0x%08x\n", hr);
876 else
877 IDWriteFontFace_GetMetrics(run->run.fontFace, &fontmetrics);
879 r->baseline = get_scaled_font_metric(fontmetrics.ascent, run->run.fontEmSize, &fontmetrics);
880 r->height = get_scaled_font_metric(fontmetrics.ascent + fontmetrics.descent, run->run.fontEmSize, &fontmetrics);
882 layout_set_cluster_metrics(layout, r, &cluster);
884 continue;
886 memerr:
887 heap_free(text_props);
888 heap_free(glyph_props);
889 heap_free(run->clustermap);
890 heap_free(run->glyphs);
891 heap_free(run->advances);
892 heap_free(run->offsets);
893 run->advances = NULL;
894 run->offsets = NULL;
895 run->clustermap = run->glyphs = NULL;
896 hr = E_OUTOFMEMORY;
897 break;
900 if (hr == S_OK) {
901 layout->cluster_count = cluster;
902 if (cluster)
903 layout->clustermetrics[cluster-1].canWrapLineAfter = TRUE;
906 IDWriteTextAnalyzer_Release(analyzer);
907 return hr;
910 static HRESULT layout_compute(struct dwrite_textlayout *layout)
912 HRESULT hr;
914 if (!(layout->recompute & RECOMPUTE_NOMINAL_RUNS))
915 return S_OK;
917 /* nominal breakpoints are evaluated only once, because string never changes */
918 if (!layout->nominal_breakpoints) {
919 IDWriteTextAnalyzer *analyzer;
920 HRESULT hr;
922 layout->nominal_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
923 if (!layout->nominal_breakpoints)
924 return E_OUTOFMEMORY;
926 hr = get_textanalyzer(&analyzer);
927 if (FAILED(hr))
928 return hr;
930 hr = IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer, &layout->IDWriteTextAnalysisSource_iface,
931 0, layout->len, &layout->IDWriteTextAnalysisSink_iface);
932 IDWriteTextAnalyzer_Release(analyzer);
934 if (layout->actual_breakpoints) {
935 heap_free(layout->actual_breakpoints);
936 layout->actual_breakpoints = NULL;
939 hr = layout_compute_runs(layout);
941 if (TRACE_ON(dwrite)) {
942 struct layout_run *cur;
944 LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
945 if (cur->kind == LAYOUT_RUN_INLINE)
946 TRACE("run inline object %p, len %u\n", cur->u.object.object, cur->u.object.length);
947 else
948 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur->u.regular.descr.textPosition, cur->u.regular.descr.textPosition +
949 cur->u.regular.descr.stringLength-1, cur->u.regular.descr.stringLength, cur->u.regular.run.bidiLevel);
953 layout->recompute &= ~RECOMPUTE_NOMINAL_RUNS;
954 return hr;
957 static inline FLOAT get_cluster_range_width(struct dwrite_textlayout *layout, UINT32 start, UINT32 end)
959 FLOAT width = 0.0f;
960 for (; start < end; start++)
961 width += layout->clustermetrics[start].width;
962 return width;
965 static struct layout_range_header *get_layout_range_header_by_pos(struct list *ranges, UINT32 pos)
967 struct layout_range_header *cur;
969 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
970 DWRITE_TEXT_RANGE *r = &cur->range;
971 if (r->startPosition <= pos && pos < r->startPosition + r->length)
972 return cur;
975 return NULL;
978 static inline IUnknown *layout_get_effect_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
980 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->effects, pos);
981 return ((struct layout_range_iface*)h)->iface;
984 static inline BOOL layout_is_erun_rtl(const struct layout_effective_run *erun)
986 return erun->run->u.regular.run.bidiLevel & 1;
989 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
990 'cluster_count' indicates how many clusters to add, including first one. */
991 static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 first_cluster,
992 UINT32 cluster_count, UINT32 line, FLOAT origin_x, BOOL strikethrough)
994 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
995 UINT32 i, start, length, last_cluster;
996 struct layout_effective_run *run;
998 if (r->kind == LAYOUT_RUN_INLINE) {
999 struct layout_effective_inline *inlineobject;
1001 inlineobject = heap_alloc(sizeof(*inlineobject));
1002 if (!inlineobject)
1003 return E_OUTOFMEMORY;
1005 inlineobject->object = r->u.object.object;
1006 inlineobject->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1007 inlineobject->origin_x = is_rtl ? origin_x - inlineobject->width : origin_x;
1008 inlineobject->origin_y = 0.0f; /* set after line is built */
1009 inlineobject->align_dx = 0.0f;
1011 /* It's not clear how these two are set, possibly directionality
1012 is derived from surrounding text (replaced text could have
1013 different ranges which differ in reading direction). */
1014 inlineobject->is_sideways = FALSE;
1015 inlineobject->is_rtl = FALSE;
1016 inlineobject->line = line;
1018 /* effect assigned from start position and on is used for inline objects */
1019 inlineobject->effect = layout_get_effect_from_pos(layout, layout->clusters[first_cluster].position);
1021 list_add_tail(&layout->inlineobjects, &inlineobject->entry);
1022 return S_OK;
1025 run = heap_alloc(sizeof(*run));
1026 if (!run)
1027 return E_OUTOFMEMORY;
1029 /* No need to iterate for that, use simple fact that:
1030 <last cluster position> = first cluster position> + <sum of cluster lengths not including last one> */
1031 last_cluster = first_cluster + cluster_count - 1;
1032 length = layout->clusters[last_cluster].position - layout->clusters[first_cluster].position +
1033 layout->clustermetrics[last_cluster].length;
1035 run->clustermap = heap_alloc(sizeof(UINT16)*length);
1036 if (!run->clustermap) {
1037 heap_free(run);
1038 return E_OUTOFMEMORY;
1041 run->run = r;
1042 run->start = start = layout->clusters[first_cluster].position;
1043 run->length = length;
1044 run->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1046 /* Check if run direction matches paragraph direction, if it doesn't adjust by
1047 run width */
1048 if (layout_is_erun_rtl(run) ^ is_rtl)
1049 run->origin_x = is_rtl ? origin_x - run->width : origin_x + run->width;
1050 else
1051 run->origin_x = origin_x;
1053 run->origin_y = 0.0f; /* set after line is built */
1054 run->align_dx = 0.0f;
1055 run->line = line;
1057 if (r->u.regular.run.glyphCount) {
1058 /* trim from the left */
1059 run->glyphcount = r->u.regular.run.glyphCount - r->u.regular.clustermap[start];
1060 /* trim from the right */
1061 if (start + length < r->u.regular.descr.stringLength - 1)
1062 run->glyphcount -= r->u.regular.run.glyphCount - r->u.regular.clustermap[start + length];
1064 else
1065 run->glyphcount = 0;
1067 /* cluster map needs to be shifted */
1068 for (i = 0; i < length; i++)
1069 run->clustermap[i] = r->u.regular.clustermap[start + i] - r->u.regular.clustermap[start];
1071 list_add_tail(&layout->eruns, &run->entry);
1073 /* Strikethrough style is guaranteed to be consistent within effective run,
1074 it's width equals to run width, thikness and offset are derived from
1075 font metrics, rest of the values are from layout or run itself */
1076 if (strikethrough) {
1077 DWRITE_FONT_METRICS metrics = { 0 };
1078 struct layout_strikethrough *s;
1080 s = heap_alloc(sizeof(*s));
1081 if (!s)
1082 return E_OUTOFMEMORY;
1084 if (is_layout_gdi_compatible(layout)) {
1085 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(
1086 r->u.regular.run.fontFace,
1087 r->u.regular.run.fontEmSize,
1088 layout->ppdip,
1089 &layout->transform,
1090 &metrics);
1091 if (FAILED(hr))
1092 WARN("failed to get font metrics, 0x%08x\n", hr);
1094 else
1095 IDWriteFontFace_GetMetrics(r->u.regular.run.fontFace, &metrics);
1097 s->s.width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1098 s->s.thickness = metrics.strikethroughThickness;
1099 s->s.offset = metrics.strikethroughPosition;
1100 s->s.readingDirection = layout->format.readingdir;
1101 s->s.flowDirection = layout->format.flow;
1102 s->s.localeName = r->u.regular.descr.localeName;
1103 s->s.measuringMode = layout->measuringmode;
1104 s->run = run;
1106 list_add_tail(&layout->strikethrough, &s->entry);
1109 return S_OK;
1112 static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_LINE_METRICS *metrics, UINT32 *line)
1114 if (!layout->line_alloc) {
1115 layout->line_alloc = 5;
1116 layout->lines = heap_alloc(layout->line_alloc*sizeof(*layout->lines));
1117 if (!layout->lines)
1118 return E_OUTOFMEMORY;
1121 if (layout->metrics.lineCount == layout->line_alloc) {
1122 DWRITE_LINE_METRICS *l = heap_realloc(layout->lines, layout->line_alloc*2*sizeof(*layout->lines));
1123 if (!l)
1124 return E_OUTOFMEMORY;
1125 layout->lines = l;
1126 layout->line_alloc *= 2;
1129 layout->lines[*line] = *metrics;
1130 layout->metrics.lineCount += 1;
1131 *line += 1;
1132 return S_OK;
1135 static inline BOOL layout_get_strikethrough_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1137 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->strike_ranges, pos);
1138 return ((struct layout_range_bool*)h)->value;
1141 static inline struct layout_effective_run *layout_get_next_erun(struct dwrite_textlayout *layout,
1142 const struct layout_effective_run *cur)
1144 struct list *e;
1146 if (!cur)
1147 e = list_head(&layout->eruns);
1148 else
1149 e = list_next(&layout->eruns, &cur->entry);
1150 if (!e)
1151 return NULL;
1152 return LIST_ENTRY(e, struct layout_effective_run, entry);
1155 static inline struct layout_effective_inline *layout_get_next_inline_run(struct dwrite_textlayout *layout,
1156 const struct layout_effective_inline *cur)
1158 struct list *e;
1160 if (!cur)
1161 e = list_head(&layout->inlineobjects);
1162 else
1163 e = list_next(&layout->inlineobjects, &cur->entry);
1164 if (!e)
1165 return NULL;
1166 return LIST_ENTRY(e, struct layout_effective_inline, entry);
1169 static FLOAT layout_get_line_width(struct dwrite_textlayout *layout,
1170 struct layout_effective_run *erun, struct layout_effective_inline *inrun, UINT32 line)
1172 FLOAT width = 0.0f;
1174 while (erun && erun->line == line) {
1175 width += erun->width;
1176 erun = layout_get_next_erun(layout, erun);
1177 if (!erun)
1178 break;
1181 while (inrun && inrun->line == line) {
1182 width += inrun->width;
1183 inrun = layout_get_next_inline_run(layout, inrun);
1184 if (!inrun)
1185 break;
1188 return width;
1191 static inline BOOL should_skip_transform(const DWRITE_MATRIX *m, FLOAT *det)
1193 *det = m->m11 * m->m22 - m->m12 * m->m21;
1194 /* on certain conditions we can skip transform */
1195 return (!memcmp(m, &identity, sizeof(*m)) || fabsf(*det) <= 1e-10f);
1198 static inline void layout_apply_snapping(struct dwrite_vec *vec, BOOL skiptransform, FLOAT ppdip,
1199 const DWRITE_MATRIX *m, FLOAT det)
1201 if (!skiptransform) {
1202 FLOAT vec2[2];
1204 /* apply transform */
1205 vec->x *= ppdip;
1206 vec->y *= ppdip;
1208 vec2[0] = m->m11 * vec->x + m->m21 * vec->y + m->dx;
1209 vec2[1] = m->m12 * vec->x + m->m22 * vec->y + m->dy;
1211 /* snap */
1212 vec2[0] = floorf(vec2[0] + 0.5f);
1213 vec2[1] = floorf(vec2[1] + 0.5f);
1215 /* apply inverted transform, we don't care about X component at this point */
1216 vec->x = (m->m22 * vec2[0] - m->m21 * vec2[1] + m->m21 * m->dy - m->m22 * m->dx) / det;
1217 vec->x /= ppdip;
1219 vec->y = (-m->m12 * vec2[0] + m->m11 * vec2[1] - (m->m11 * m->dy - m->m12 * m->dx)) / det;
1220 vec->y /= ppdip;
1222 else {
1223 vec->x = floorf(vec->x * ppdip + 0.5f) / ppdip;
1224 vec->y = floorf(vec->y * ppdip + 0.5f) / ppdip;
1228 static void layout_apply_leading_alignment(struct dwrite_textlayout *layout)
1230 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1231 struct layout_effective_inline *inrun;
1232 struct layout_effective_run *erun;
1234 erun = layout_get_next_erun(layout, NULL);
1235 inrun = layout_get_next_inline_run(layout, NULL);
1237 while (erun) {
1238 erun->align_dx = 0.0f;
1239 erun = layout_get_next_erun(layout, erun);
1242 while (inrun) {
1243 inrun->align_dx = 0.0f;
1244 inrun = layout_get_next_inline_run(layout, inrun);
1247 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
1250 static void layout_apply_trailing_alignment(struct dwrite_textlayout *layout)
1252 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1253 struct layout_effective_inline *inrun;
1254 struct layout_effective_run *erun;
1255 UINT32 line;
1257 erun = layout_get_next_erun(layout, NULL);
1258 inrun = layout_get_next_inline_run(layout, NULL);
1260 for (line = 0; line < layout->metrics.lineCount; line++) {
1261 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1262 FLOAT shift = layout->metrics.layoutWidth - width;
1264 if (is_rtl)
1265 shift *= -1.0f;
1267 while (erun && erun->line == line) {
1268 erun->align_dx = shift;
1269 erun = layout_get_next_erun(layout, erun);
1272 while (inrun && inrun->line == line) {
1273 inrun->align_dx = shift;
1274 inrun = layout_get_next_inline_run(layout, inrun);
1278 layout->metrics.left = is_rtl ? 0.0f : layout->metrics.layoutWidth - layout->metrics.width;
1281 static inline FLOAT layout_get_centered_shift(struct dwrite_textlayout *layout, BOOL skiptransform,
1282 FLOAT width, FLOAT det)
1284 if (is_layout_gdi_compatible(layout)) {
1285 struct dwrite_vec vec = { layout->metrics.layoutWidth - width, 0.0f};
1286 layout_apply_snapping(&vec, skiptransform, layout->ppdip, &layout->transform, det);
1287 return floorf(vec.x / 2.0f);
1289 else
1290 return (layout->metrics.layoutWidth - width) / 2.0f;
1293 static void layout_apply_centered_alignment(struct dwrite_textlayout *layout)
1295 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1296 struct layout_effective_inline *inrun;
1297 struct layout_effective_run *erun;
1298 BOOL skiptransform;
1299 UINT32 line;
1300 FLOAT det;
1302 erun = layout_get_next_erun(layout, NULL);
1303 inrun = layout_get_next_inline_run(layout, NULL);
1305 skiptransform = should_skip_transform(&layout->transform, &det);
1307 for (line = 0; line < layout->metrics.lineCount; line++) {
1308 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1309 FLOAT shift = layout_get_centered_shift(layout, skiptransform, width, det);
1311 if (is_rtl)
1312 shift *= -1.0f;
1314 while (erun && erun->line == line) {
1315 erun->align_dx = shift;
1316 erun = layout_get_next_erun(layout, erun);
1319 while (inrun && inrun->line == line) {
1320 inrun->align_dx = shift;
1321 inrun = layout_get_next_inline_run(layout, inrun);
1325 layout->metrics.left = (layout->metrics.layoutWidth - layout->metrics.width) / 2.0f;
1328 static void layout_apply_text_alignment(struct dwrite_textlayout *layout)
1330 switch (layout->format.textalignment)
1332 case DWRITE_TEXT_ALIGNMENT_LEADING:
1333 layout_apply_leading_alignment(layout);
1334 break;
1335 case DWRITE_TEXT_ALIGNMENT_TRAILING:
1336 layout_apply_trailing_alignment(layout);
1337 break;
1338 case DWRITE_TEXT_ALIGNMENT_CENTER:
1339 layout_apply_centered_alignment(layout);
1340 break;
1341 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED:
1342 FIXME("alignment %d not implemented\n", layout->format.textalignment);
1343 break;
1344 default:
1349 static void layout_apply_par_alignment(struct dwrite_textlayout *layout)
1351 struct layout_effective_inline *inrun;
1352 struct layout_effective_run *erun;
1353 FLOAT origin_y = 0.0f;
1354 UINT32 line;
1356 /* alignment mode defines origin, after that all run origins are updated
1357 the same way */
1359 switch (layout->format.paralign)
1361 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR:
1362 origin_y = 0.0f;
1363 break;
1364 case DWRITE_PARAGRAPH_ALIGNMENT_FAR:
1365 origin_y = layout->metrics.layoutHeight - layout->metrics.height;
1366 break;
1367 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER:
1368 origin_y = (layout->metrics.layoutHeight - layout->metrics.height) / 2.0f;
1369 break;
1370 default:
1374 layout->metrics.top = origin_y;
1376 erun = layout_get_next_erun(layout, NULL);
1377 inrun = layout_get_next_inline_run(layout, NULL);
1378 for (line = 0; line < layout->metrics.lineCount; line++) {
1379 origin_y += layout->lines[line].baseline;
1381 while (erun && erun->line == line) {
1382 erun->origin_y = origin_y;
1383 erun = layout_get_next_erun(layout, erun);
1386 while (inrun && inrun->line == line) {
1387 inrun->origin_y = origin_y;
1388 inrun = layout_get_next_inline_run(layout, inrun);
1393 static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
1395 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1396 struct layout_effective_inline *inrun;
1397 struct layout_effective_run *erun;
1398 const struct layout_run *run;
1399 DWRITE_LINE_METRICS metrics;
1400 FLOAT width, origin_x, origin_y;
1401 UINT32 i, start, line, textpos;
1402 HRESULT hr;
1403 BOOL s[2];
1405 if (!(layout->recompute & RECOMPUTE_EFFECTIVE_RUNS))
1406 return S_OK;
1408 hr = layout_compute(layout);
1409 if (FAILED(hr))
1410 return hr;
1412 layout->metrics.lineCount = 0;
1413 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0f;
1414 line = 0;
1415 run = layout->clusters[0].run;
1416 memset(&metrics, 0, sizeof(metrics));
1417 s[0] = s[1] = layout_get_strikethrough_from_pos(layout, 0);
1419 for (i = 0, start = 0, textpos = 0, width = 0.0f; i < layout->cluster_count; i++) {
1420 BOOL overflow;
1422 s[1] = layout_get_strikethrough_from_pos(layout, textpos);
1424 /* switched to next nominal run, at this point all previous pending clusters are already
1425 checked for layout line overflow, so new effective run will fit in current line */
1426 if (run != layout->clusters[i].run || s[0] != s[1]) {
1427 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, s[0]);
1428 if (FAILED(hr))
1429 return hr;
1430 origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) :
1431 get_cluster_range_width(layout, start, i);
1432 run = layout->clusters[i].run;
1433 start = i;
1436 overflow = layout->clustermetrics[i].canWrapLineAfter &&
1437 (width + layout->clustermetrics[i].width > layout->metrics.layoutWidth);
1438 /* check if we got new */
1439 if (overflow ||
1440 layout->clustermetrics[i].isNewline || /* always wrap on new line */
1441 i == layout->cluster_count - 1) /* end of the text */ {
1443 UINT32 strlength, last_cluster, index;
1444 FLOAT descent, trailingspacewidth;
1446 if (!overflow) {
1447 width += layout->clustermetrics[i].width;
1448 metrics.length += layout->clustermetrics[i].length;
1449 last_cluster = i;
1451 else
1452 last_cluster = i ? i - 1 : i;
1454 if (i >= start) {
1455 hr = layout_add_effective_run(layout, run, start, last_cluster - start + 1, line, origin_x, s[0]);
1456 if (FAILED(hr))
1457 return hr;
1458 /* we don't need to update origin for next run as we're going to wrap */
1461 /* take a look at clusters we got for this line in reverse order to set
1462 trailing properties for current line */
1463 strlength = metrics.length;
1464 index = last_cluster;
1465 trailingspacewidth = 0.0f;
1466 while (strlength) {
1467 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1469 if (!cluster->isNewline && !cluster->isWhitespace)
1470 break;
1472 if (cluster->isNewline) {
1473 metrics.trailingWhitespaceLength += cluster->length;
1474 metrics.newlineLength += cluster->length;
1477 if (cluster->isWhitespace) {
1478 metrics.trailingWhitespaceLength += cluster->length;
1479 trailingspacewidth += cluster->width;
1482 strlength -= cluster->length;
1483 index--;
1486 /* look for max baseline and descent for this line */
1487 strlength = metrics.length;
1488 index = last_cluster;
1489 metrics.baseline = 0.0f;
1490 descent = 0.0f;
1491 while (strlength) {
1492 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1493 const struct layout_run *cur = layout->clusters[index].run;
1494 FLOAT cur_descent = cur->height - cur->baseline;
1496 if (cur->baseline > metrics.baseline)
1497 metrics.baseline = cur->baseline;
1499 if (cur_descent > descent)
1500 descent = cur_descent;
1502 strlength -= cluster->length;
1503 index--;
1505 metrics.height = descent + metrics.baseline;
1507 if (width > layout->metrics.widthIncludingTrailingWhitespace)
1508 layout->metrics.widthIncludingTrailingWhitespace = width;
1509 if (width - trailingspacewidth > layout->metrics.width)
1510 layout->metrics.width = width - trailingspacewidth;
1512 metrics.isTrimmed = width > layout->metrics.layoutWidth;
1513 hr = layout_set_line_metrics(layout, &metrics, &line);
1514 if (FAILED(hr))
1515 return hr;
1517 width = layout->clustermetrics[i].width;
1518 memset(&metrics, 0, sizeof(metrics));
1519 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0f;
1520 start = i;
1522 else {
1523 metrics.length += layout->clustermetrics[i].length;
1524 width += layout->clustermetrics[i].width;
1527 s[0] = s[1];
1528 textpos += layout->clustermetrics[i].length;
1531 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0;
1532 layout->metrics.top = 0.0f;
1533 layout->metrics.maxBidiReorderingDepth = 1; /* FIXME */
1534 layout->metrics.height = 0.0f;
1536 /* Now all line info is here, update effective runs positions in flow direction */
1537 erun = layout_get_next_erun(layout, NULL);
1538 inrun = layout_get_next_inline_run(layout, NULL);
1540 origin_y = 0.0f;
1541 for (line = 0; line < layout->metrics.lineCount; line++) {
1543 origin_y += layout->lines[line].baseline;
1545 /* For all runs on this line */
1546 while (erun && erun->line == line) {
1547 erun->origin_y = origin_y;
1548 erun = layout_get_next_erun(layout, erun);
1551 /* Same for inline runs */
1552 while (inrun && inrun->line == line) {
1553 inrun->origin_y = origin_y;
1554 inrun = layout_get_next_inline_run(layout, inrun);
1557 layout->metrics.height += layout->lines[line].height;
1560 /* initial alignment is always leading */
1561 if (layout->format.textalignment != DWRITE_TEXT_ALIGNMENT_LEADING)
1562 layout_apply_text_alignment(layout);
1564 /* initial paragraph alignment is always near */
1565 if (layout->format.paralign != DWRITE_PARAGRAPH_ALIGNMENT_NEAR)
1566 layout_apply_par_alignment(layout);
1568 layout->metrics.heightIncludingTrailingWhitespace = layout->metrics.height; /* FIXME: not true for vertical text */
1570 layout->recompute &= ~RECOMPUTE_EFFECTIVE_RUNS;
1571 return hr;
1574 static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
1576 struct layout_range_spacing const *range_spacing = (struct layout_range_spacing*)h;
1577 struct layout_range_iface const *range_iface = (struct layout_range_iface*)h;
1578 struct layout_range_bool const *range_bool = (struct layout_range_bool*)h;
1579 struct layout_range const *range = (struct layout_range*)h;
1581 switch (attr) {
1582 case LAYOUT_RANGE_ATTR_WEIGHT:
1583 return range->weight == value->u.weight;
1584 case LAYOUT_RANGE_ATTR_STYLE:
1585 return range->style == value->u.style;
1586 case LAYOUT_RANGE_ATTR_STRETCH:
1587 return range->stretch == value->u.stretch;
1588 case LAYOUT_RANGE_ATTR_FONTSIZE:
1589 return range->fontsize == value->u.fontsize;
1590 case LAYOUT_RANGE_ATTR_INLINE:
1591 return range->object == value->u.object;
1592 case LAYOUT_RANGE_ATTR_EFFECT:
1593 return range_iface->iface == value->u.effect;
1594 case LAYOUT_RANGE_ATTR_UNDERLINE:
1595 return range->underline == value->u.underline;
1596 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
1597 return range_bool->value == value->u.strikethrough;
1598 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
1599 return range->pair_kerning == value->u.pair_kerning;
1600 case LAYOUT_RANGE_ATTR_FONTCOLL:
1601 return range->collection == value->u.collection;
1602 case LAYOUT_RANGE_ATTR_LOCALE:
1603 return strcmpiW(range->locale, value->u.locale) == 0;
1604 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1605 return strcmpW(range->fontfamily, value->u.fontfamily) == 0;
1606 case LAYOUT_RANGE_ATTR_SPACING:
1607 return range_spacing->leading == value->u.spacing[0] &&
1608 range_spacing->trailing == value->u.spacing[1] &&
1609 range_spacing->min_advance == value->u.spacing[2];
1610 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
1611 return range_iface->iface == (IUnknown*)value->u.typography;
1612 default:
1616 return FALSE;
1619 static inline BOOL is_same_layout_attributes(struct layout_range_header const *hleft, struct layout_range_header const *hright)
1621 switch (hleft->kind)
1623 case LAYOUT_RANGE_REGULAR:
1625 struct layout_range const *left = (struct layout_range const*)hleft;
1626 struct layout_range const *right = (struct layout_range const*)hright;
1627 return left->weight == right->weight &&
1628 left->style == right->style &&
1629 left->stretch == right->stretch &&
1630 left->fontsize == right->fontsize &&
1631 left->object == right->object &&
1632 left->underline == right->underline &&
1633 left->pair_kerning == right->pair_kerning &&
1634 left->collection == right->collection &&
1635 !strcmpiW(left->locale, right->locale) &&
1636 !strcmpW(left->fontfamily, right->fontfamily);
1638 case LAYOUT_RANGE_STRIKETHROUGH:
1640 struct layout_range_bool const *left = (struct layout_range_bool const*)hleft;
1641 struct layout_range_bool const *right = (struct layout_range_bool const*)hright;
1642 return left->value == right->value;
1644 case LAYOUT_RANGE_EFFECT:
1645 case LAYOUT_RANGE_TYPOGRAPHY:
1647 struct layout_range_iface const *left = (struct layout_range_iface const*)hleft;
1648 struct layout_range_iface const *right = (struct layout_range_iface const*)hright;
1649 return left->iface == right->iface;
1651 case LAYOUT_RANGE_SPACING:
1653 struct layout_range_spacing const *left = (struct layout_range_spacing const*)hleft;
1654 struct layout_range_spacing const *right = (struct layout_range_spacing const*)hright;
1655 return left->leading == right->leading &&
1656 left->trailing == right->trailing &&
1657 left->min_advance == right->min_advance;
1659 default:
1660 FIXME("unknown range kind %d\n", hleft->kind);
1661 return FALSE;
1665 static inline BOOL is_same_text_range(const DWRITE_TEXT_RANGE *left, const DWRITE_TEXT_RANGE *right)
1667 return left->startPosition == right->startPosition && left->length == right->length;
1670 /* Allocates range and inits it with default values from text format. */
1671 static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout *layout, const DWRITE_TEXT_RANGE *r,
1672 enum layout_range_kind kind)
1674 struct layout_range_header *h;
1676 switch (kind)
1678 case LAYOUT_RANGE_REGULAR:
1680 struct layout_range *range;
1682 range = heap_alloc(sizeof(*range));
1683 if (!range) return NULL;
1685 range->weight = layout->format.weight;
1686 range->style = layout->format.style;
1687 range->stretch = layout->format.stretch;
1688 range->fontsize = layout->format.fontsize;
1689 range->object = NULL;
1690 range->underline = FALSE;
1691 range->pair_kerning = FALSE;
1693 range->fontfamily = heap_strdupW(layout->format.family_name);
1694 if (!range->fontfamily) {
1695 heap_free(range);
1696 return NULL;
1699 range->collection = layout->format.collection;
1700 if (range->collection)
1701 IDWriteFontCollection_AddRef(range->collection);
1702 strcpyW(range->locale, layout->format.locale);
1704 h = &range->h;
1705 break;
1707 case LAYOUT_RANGE_STRIKETHROUGH:
1709 struct layout_range_bool *range;
1711 range = heap_alloc(sizeof(*range));
1712 if (!range) return NULL;
1714 range->value = FALSE;
1715 h = &range->h;
1716 break;
1718 case LAYOUT_RANGE_EFFECT:
1719 case LAYOUT_RANGE_TYPOGRAPHY:
1721 struct layout_range_iface *range;
1723 range = heap_alloc(sizeof(*range));
1724 if (!range) return NULL;
1726 range->iface = NULL;
1727 h = &range->h;
1728 break;
1730 case LAYOUT_RANGE_SPACING:
1732 struct layout_range_spacing *range;
1734 range = heap_alloc(sizeof(*range));
1735 if (!range) return NULL;
1737 range->leading = 0.0f;
1738 range->trailing = 0.0f;
1739 range->min_advance = 0.0f;
1740 h = &range->h;
1741 break;
1743 default:
1744 FIXME("unknown range kind %d\n", kind);
1745 return NULL;
1748 h->kind = kind;
1749 h->range = *r;
1750 return h;
1753 static struct layout_range_header *alloc_layout_range_from(struct layout_range_header *h, const DWRITE_TEXT_RANGE *r)
1755 struct layout_range_header *ret;
1757 switch (h->kind)
1759 case LAYOUT_RANGE_REGULAR:
1761 struct layout_range *from = (struct layout_range*)h;
1763 struct layout_range *range = heap_alloc(sizeof(*range));
1764 if (!range) return NULL;
1766 *range = *from;
1767 range->fontfamily = heap_strdupW(from->fontfamily);
1768 if (!range->fontfamily) {
1769 heap_free(range);
1770 return NULL;
1773 /* update refcounts */
1774 if (range->object)
1775 IDWriteInlineObject_AddRef(range->object);
1776 if (range->collection)
1777 IDWriteFontCollection_AddRef(range->collection);
1778 ret = &range->h;
1779 break;
1781 case LAYOUT_RANGE_STRIKETHROUGH:
1783 struct layout_range_bool *strike = heap_alloc(sizeof(*strike));
1784 if (!strike) return NULL;
1786 *strike = *(struct layout_range_bool*)h;
1787 ret = &strike->h;
1788 break;
1790 case LAYOUT_RANGE_EFFECT:
1791 case LAYOUT_RANGE_TYPOGRAPHY:
1793 struct layout_range_iface *effect = heap_alloc(sizeof(*effect));
1794 if (!effect) return NULL;
1796 *effect = *(struct layout_range_iface*)h;
1797 if (effect->iface)
1798 IUnknown_AddRef(effect->iface);
1799 ret = &effect->h;
1800 break;
1802 case LAYOUT_RANGE_SPACING:
1804 struct layout_range_spacing *spacing = heap_alloc(sizeof(*spacing));
1805 if (!spacing) return NULL;
1807 *spacing = *(struct layout_range_spacing*)h;
1808 ret = &spacing->h;
1809 break;
1811 default:
1812 FIXME("unknown range kind %d\n", h->kind);
1813 return NULL;
1816 ret->range = *r;
1817 return ret;
1820 static void free_layout_range(struct layout_range_header *h)
1822 if (!h)
1823 return;
1825 switch (h->kind)
1827 case LAYOUT_RANGE_REGULAR:
1829 struct layout_range *range = (struct layout_range*)h;
1831 if (range->object)
1832 IDWriteInlineObject_Release(range->object);
1833 if (range->collection)
1834 IDWriteFontCollection_Release(range->collection);
1835 heap_free(range->fontfamily);
1836 break;
1838 case LAYOUT_RANGE_EFFECT:
1839 case LAYOUT_RANGE_TYPOGRAPHY:
1841 struct layout_range_iface *range = (struct layout_range_iface*)h;
1842 if (range->iface)
1843 IUnknown_Release(range->iface);
1844 break;
1846 default:
1850 heap_free(h);
1853 static void free_layout_ranges_list(struct dwrite_textlayout *layout)
1855 struct layout_range_header *cur, *cur2;
1857 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->ranges, struct layout_range_header, entry) {
1858 list_remove(&cur->entry);
1859 free_layout_range(cur);
1862 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->strike_ranges, struct layout_range_header, entry) {
1863 list_remove(&cur->entry);
1864 free_layout_range(cur);
1867 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->effects, struct layout_range_header, entry) {
1868 list_remove(&cur->entry);
1869 free_layout_range(cur);
1872 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->spacing, struct layout_range_header, entry) {
1873 list_remove(&cur->entry);
1874 free_layout_range(cur);
1877 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->typographies, struct layout_range_header, entry) {
1878 list_remove(&cur->entry);
1879 free_layout_range(cur);
1883 static struct layout_range_header *find_outer_range(struct list *ranges, const DWRITE_TEXT_RANGE *range)
1885 struct layout_range_header *cur;
1887 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
1889 if (cur->range.startPosition > range->startPosition)
1890 return NULL;
1892 if ((cur->range.startPosition + cur->range.length < range->startPosition + range->length) &&
1893 (range->startPosition < cur->range.startPosition + cur->range.length))
1894 return NULL;
1895 if (cur->range.startPosition + cur->range.length >= range->startPosition + range->length)
1896 return cur;
1899 return NULL;
1902 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos)
1904 struct layout_range *cur;
1906 LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, h.entry) {
1907 DWRITE_TEXT_RANGE *r = &cur->h.range;
1908 if (r->startPosition <= pos && pos < r->startPosition + r->length)
1909 return cur;
1912 return NULL;
1915 static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
1917 if (*dest == value) return FALSE;
1919 if (*dest)
1920 IUnknown_Release(*dest);
1921 *dest = value;
1922 if (*dest)
1923 IUnknown_AddRef(*dest);
1925 return TRUE;
1928 static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
1930 struct layout_range_spacing *dest_spacing = (struct layout_range_spacing*)h;
1931 struct layout_range_iface *dest_iface = (struct layout_range_iface*)h;
1932 struct layout_range_bool *dest_bool = (struct layout_range_bool*)h;
1933 struct layout_range *dest = (struct layout_range*)h;
1935 BOOL changed = FALSE;
1937 switch (attr) {
1938 case LAYOUT_RANGE_ATTR_WEIGHT:
1939 changed = dest->weight != value->u.weight;
1940 dest->weight = value->u.weight;
1941 break;
1942 case LAYOUT_RANGE_ATTR_STYLE:
1943 changed = dest->style != value->u.style;
1944 dest->style = value->u.style;
1945 break;
1946 case LAYOUT_RANGE_ATTR_STRETCH:
1947 changed = dest->stretch != value->u.stretch;
1948 dest->stretch = value->u.stretch;
1949 break;
1950 case LAYOUT_RANGE_ATTR_FONTSIZE:
1951 changed = dest->fontsize != value->u.fontsize;
1952 dest->fontsize = value->u.fontsize;
1953 break;
1954 case LAYOUT_RANGE_ATTR_INLINE:
1955 changed = set_layout_range_iface_attr((IUnknown**)&dest->object, (IUnknown*)value->u.object);
1956 break;
1957 case LAYOUT_RANGE_ATTR_EFFECT:
1958 changed = set_layout_range_iface_attr((IUnknown**)&dest_iface->iface, (IUnknown*)value->u.effect);
1959 break;
1960 case LAYOUT_RANGE_ATTR_UNDERLINE:
1961 changed = dest->underline != value->u.underline;
1962 dest->underline = value->u.underline;
1963 break;
1964 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
1965 changed = dest_bool->value != value->u.strikethrough;
1966 dest_bool->value = value->u.strikethrough;
1967 break;
1968 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
1969 changed = dest->pair_kerning != value->u.pair_kerning;
1970 dest->pair_kerning = value->u.pair_kerning;
1971 break;
1972 case LAYOUT_RANGE_ATTR_FONTCOLL:
1973 changed = set_layout_range_iface_attr((IUnknown**)&dest->collection, (IUnknown*)value->u.collection);
1974 break;
1975 case LAYOUT_RANGE_ATTR_LOCALE:
1976 changed = strcmpiW(dest->locale, value->u.locale) != 0;
1977 if (changed)
1978 strcpyW(dest->locale, value->u.locale);
1979 break;
1980 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1981 changed = strcmpW(dest->fontfamily, value->u.fontfamily) != 0;
1982 if (changed) {
1983 heap_free(dest->fontfamily);
1984 dest->fontfamily = heap_strdupW(value->u.fontfamily);
1986 break;
1987 case LAYOUT_RANGE_ATTR_SPACING:
1988 changed = dest_spacing->leading != value->u.spacing[0] ||
1989 dest_spacing->trailing != value->u.spacing[1] ||
1990 dest_spacing->min_advance != value->u.spacing[2];
1991 dest_spacing->leading = value->u.spacing[0];
1992 dest_spacing->trailing = value->u.spacing[1];
1993 dest_spacing->min_advance = value->u.spacing[2];
1994 break;
1995 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
1996 changed = set_layout_range_iface_attr((IUnknown**)&dest_iface->iface, (IUnknown*)value->u.typography);
1997 break;
1998 default:
2002 return changed;
2005 static inline BOOL is_in_layout_range(const DWRITE_TEXT_RANGE *outer, const DWRITE_TEXT_RANGE *inner)
2007 return (inner->startPosition >= outer->startPosition) &&
2008 (inner->startPosition + inner->length <= outer->startPosition + outer->length);
2011 static inline HRESULT return_range(const struct layout_range_header *h, DWRITE_TEXT_RANGE *r)
2013 if (r) *r = h->range;
2014 return S_OK;
2017 /* Set attribute value for given range, does all needed splitting/merging of existing ranges. */
2018 static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2020 struct layout_range_header *cur, *right, *left, *outer;
2021 BOOL changed = FALSE;
2022 struct list *ranges;
2023 DWRITE_TEXT_RANGE r;
2025 /* ignore zero length ranges */
2026 if (value->range.length == 0)
2027 return S_OK;
2029 /* select from ranges lists */
2030 switch (attr)
2032 case LAYOUT_RANGE_ATTR_WEIGHT:
2033 case LAYOUT_RANGE_ATTR_STYLE:
2034 case LAYOUT_RANGE_ATTR_STRETCH:
2035 case LAYOUT_RANGE_ATTR_FONTSIZE:
2036 case LAYOUT_RANGE_ATTR_INLINE:
2037 case LAYOUT_RANGE_ATTR_UNDERLINE:
2038 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2039 case LAYOUT_RANGE_ATTR_FONTCOLL:
2040 case LAYOUT_RANGE_ATTR_LOCALE:
2041 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2042 ranges = &layout->ranges;
2043 break;
2044 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2045 ranges = &layout->strike_ranges;
2046 break;
2047 case LAYOUT_RANGE_ATTR_EFFECT:
2048 ranges = &layout->effects;
2049 break;
2050 case LAYOUT_RANGE_ATTR_SPACING:
2051 ranges = &layout->spacing;
2052 break;
2053 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2054 ranges = &layout->typographies;
2055 break;
2056 default:
2057 FIXME("unknown attr kind %d\n", attr);
2058 return E_FAIL;
2061 /* If new range is completely within existing range, split existing range in two */
2062 if ((outer = find_outer_range(ranges, &value->range))) {
2064 /* no need to add same range */
2065 if (is_same_layout_attrvalue(outer, attr, value))
2066 return S_OK;
2068 /* for matching range bounds just replace data */
2069 if (is_same_text_range(&outer->range, &value->range)) {
2070 changed = set_layout_range_attrval(outer, attr, value);
2071 goto done;
2074 /* add new range to the left */
2075 if (value->range.startPosition == outer->range.startPosition) {
2076 left = alloc_layout_range_from(outer, &value->range);
2077 if (!left) return E_OUTOFMEMORY;
2079 changed = set_layout_range_attrval(left, attr, value);
2080 list_add_before(&outer->entry, &left->entry);
2081 outer->range.startPosition += value->range.length;
2082 outer->range.length -= value->range.length;
2083 goto done;
2086 /* add new range to the right */
2087 if (value->range.startPosition + value->range.length == outer->range.startPosition + outer->range.length) {
2088 right = alloc_layout_range_from(outer, &value->range);
2089 if (!right) return E_OUTOFMEMORY;
2091 changed = set_layout_range_attrval(right, attr, value);
2092 list_add_after(&outer->entry, &right->entry);
2093 outer->range.length -= value->range.length;
2094 goto done;
2097 r.startPosition = value->range.startPosition + value->range.length;
2098 r.length = outer->range.length + outer->range.startPosition - r.startPosition;
2100 /* right part */
2101 right = alloc_layout_range_from(outer, &r);
2102 /* new range in the middle */
2103 cur = alloc_layout_range_from(outer, &value->range);
2104 if (!right || !cur) {
2105 free_layout_range(right);
2106 free_layout_range(cur);
2107 return E_OUTOFMEMORY;
2110 /* reuse container range as a left part */
2111 outer->range.length = value->range.startPosition - outer->range.startPosition;
2113 /* new part */
2114 set_layout_range_attrval(cur, attr, value);
2116 list_add_after(&outer->entry, &cur->entry);
2117 list_add_after(&cur->entry, &right->entry);
2119 return S_OK;
2122 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2123 Update all of them. */
2124 left = get_layout_range_header_by_pos(ranges, value->range.startPosition);
2125 if (left->range.startPosition == value->range.startPosition)
2126 changed = set_layout_range_attrval(left, attr, value);
2127 else /* need to split */ {
2128 r.startPosition = value->range.startPosition;
2129 r.length = left->range.length - value->range.startPosition + left->range.startPosition;
2130 left->range.length -= r.length;
2131 cur = alloc_layout_range_from(left, &r);
2132 changed = set_layout_range_attrval(cur, attr, value);
2133 list_add_after(&left->entry, &cur->entry);
2135 cur = LIST_ENTRY(list_next(ranges, &left->entry), struct layout_range_header, entry);
2137 /* for all existing ranges covered by new one update value */
2138 while (cur && is_in_layout_range(&value->range, &cur->range)) {
2139 changed |= set_layout_range_attrval(cur, attr, value);
2140 cur = LIST_ENTRY(list_next(ranges, &cur->entry), struct layout_range_header, entry);
2143 /* it's possible rightmost range intersects */
2144 if (cur && (cur->range.startPosition < value->range.startPosition + value->range.length)) {
2145 r.startPosition = cur->range.startPosition;
2146 r.length = value->range.startPosition + value->range.length - cur->range.startPosition;
2147 left = alloc_layout_range_from(cur, &r);
2148 changed |= set_layout_range_attrval(left, attr, value);
2149 cur->range.startPosition += left->range.length;
2150 cur->range.length -= left->range.length;
2151 list_add_before(&cur->entry, &left->entry);
2154 done:
2155 if (changed) {
2156 struct list *next, *i;
2158 layout->recompute = RECOMPUTE_EVERYTHING;
2159 i = list_head(ranges);
2160 while ((next = list_next(ranges, i))) {
2161 struct layout_range_header *next_range = LIST_ENTRY(next, struct layout_range_header, entry);
2163 cur = LIST_ENTRY(i, struct layout_range_header, entry);
2164 if (is_same_layout_attributes(cur, next_range)) {
2165 /* remove similar range */
2166 cur->range.length += next_range->range.length;
2167 list_remove(next);
2168 free_layout_range(next_range);
2170 else
2171 i = list_next(ranges, i);
2175 return S_OK;
2178 static inline const WCHAR *get_string_attribute_ptr(struct layout_range *range, enum layout_range_attr_kind kind)
2180 const WCHAR *str;
2182 switch (kind) {
2183 case LAYOUT_RANGE_ATTR_LOCALE:
2184 str = range->locale;
2185 break;
2186 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2187 str = range->fontfamily;
2188 break;
2189 default:
2190 str = NULL;
2193 return str;
2196 static HRESULT get_string_attribute_length(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2197 UINT32 *length, DWRITE_TEXT_RANGE *r)
2199 struct layout_range *range;
2200 const WCHAR *str;
2202 range = get_layout_range_by_pos(layout, position);
2203 if (!range) {
2204 *length = 0;
2205 return S_OK;
2208 str = get_string_attribute_ptr(range, kind);
2209 *length = strlenW(str);
2210 return return_range(&range->h, r);
2213 static HRESULT get_string_attribute_value(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2214 WCHAR *ret, UINT32 length, DWRITE_TEXT_RANGE *r)
2216 struct layout_range *range;
2217 const WCHAR *str;
2219 if (length == 0)
2220 return E_INVALIDARG;
2222 ret[0] = 0;
2223 range = get_layout_range_by_pos(layout, position);
2224 if (!range)
2225 return E_INVALIDARG;
2227 str = get_string_attribute_ptr(range, kind);
2228 if (length < strlenW(str) + 1)
2229 return E_NOT_SUFFICIENT_BUFFER;
2231 strcpyW(ret, str);
2232 return return_range(&range->h, r);
2235 static HRESULT WINAPI dwritetextlayout_QueryInterface(IDWriteTextLayout2 *iface, REFIID riid, void **obj)
2237 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2239 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2241 *obj = NULL;
2243 if (IsEqualIID(riid, &IID_IDWriteTextLayout2) ||
2244 IsEqualIID(riid, &IID_IDWriteTextLayout1) ||
2245 IsEqualIID(riid, &IID_IDWriteTextLayout) ||
2246 IsEqualIID(riid, &IID_IUnknown))
2248 *obj = iface;
2250 else if (IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
2251 IsEqualIID(riid, &IID_IDWriteTextFormat))
2252 *obj = &This->IDWriteTextFormat1_iface;
2254 if (*obj) {
2255 IDWriteTextLayout2_AddRef(iface);
2256 return S_OK;
2259 return E_NOINTERFACE;
2262 static ULONG WINAPI dwritetextlayout_AddRef(IDWriteTextLayout2 *iface)
2264 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2265 ULONG ref = InterlockedIncrement(&This->ref);
2266 TRACE("(%p)->(%d)\n", This, ref);
2267 return ref;
2270 static ULONG WINAPI dwritetextlayout_Release(IDWriteTextLayout2 *iface)
2272 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2273 ULONG ref = InterlockedDecrement(&This->ref);
2275 TRACE("(%p)->(%d)\n", This, ref);
2277 if (!ref) {
2278 free_layout_ranges_list(This);
2279 free_layout_eruns(This);
2280 free_layout_runs(This);
2281 release_format_data(&This->format);
2282 heap_free(This->nominal_breakpoints);
2283 heap_free(This->actual_breakpoints);
2284 heap_free(This->clustermetrics);
2285 heap_free(This->clusters);
2286 heap_free(This->lines);
2287 heap_free(This->str);
2288 heap_free(This);
2291 return ref;
2294 static HRESULT WINAPI dwritetextlayout_SetTextAlignment(IDWriteTextLayout2 *iface, DWRITE_TEXT_ALIGNMENT alignment)
2296 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2297 return IDWriteTextFormat1_SetTextAlignment(&This->IDWriteTextFormat1_iface, alignment);
2300 static HRESULT WINAPI dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout2 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
2302 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2303 return IDWriteTextFormat1_SetParagraphAlignment(&This->IDWriteTextFormat1_iface, alignment);
2306 static HRESULT WINAPI dwritetextlayout_SetWordWrapping(IDWriteTextLayout2 *iface, DWRITE_WORD_WRAPPING wrapping)
2308 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2309 return IDWriteTextFormat1_SetWordWrapping(&This->IDWriteTextFormat1_iface, wrapping);
2312 static HRESULT WINAPI dwritetextlayout_SetReadingDirection(IDWriteTextLayout2 *iface, DWRITE_READING_DIRECTION direction)
2314 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2315 return IDWriteTextFormat1_SetReadingDirection(&This->IDWriteTextFormat1_iface, direction);
2318 static HRESULT WINAPI dwritetextlayout_SetFlowDirection(IDWriteTextLayout2 *iface, DWRITE_FLOW_DIRECTION direction)
2320 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2321 TRACE("(%p)->(%d)\n", This, direction);
2322 return IDWriteTextFormat1_SetFlowDirection(&This->IDWriteTextFormat1_iface, direction);
2325 static HRESULT WINAPI dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout2 *iface, FLOAT tabstop)
2327 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2328 TRACE("(%p)->(%.2f)\n", This, tabstop);
2329 return IDWriteTextFormat1_SetIncrementalTabStop(&This->IDWriteTextFormat1_iface, tabstop);
2332 static HRESULT WINAPI dwritetextlayout_SetTrimming(IDWriteTextLayout2 *iface, DWRITE_TRIMMING const *trimming,
2333 IDWriteInlineObject *trimming_sign)
2335 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2336 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
2337 return IDWriteTextFormat1_SetTrimming(&This->IDWriteTextFormat1_iface, trimming, trimming_sign);
2340 static HRESULT WINAPI dwritetextlayout_SetLineSpacing(IDWriteTextLayout2 *iface, DWRITE_LINE_SPACING_METHOD spacing,
2341 FLOAT line_spacing, FLOAT baseline)
2343 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2344 TRACE("(%p)->(%d %.2f %.2f)\n", This, spacing, line_spacing, baseline);
2345 return IDWriteTextFormat1_SetLineSpacing(&This->IDWriteTextFormat1_iface, spacing, line_spacing, baseline);
2348 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextlayout_GetTextAlignment(IDWriteTextLayout2 *iface)
2350 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2351 return IDWriteTextFormat1_GetTextAlignment(&This->IDWriteTextFormat1_iface);
2354 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout2 *iface)
2356 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2357 return IDWriteTextFormat1_GetParagraphAlignment(&This->IDWriteTextFormat1_iface);
2360 static DWRITE_WORD_WRAPPING WINAPI dwritetextlayout_GetWordWrapping(IDWriteTextLayout2 *iface)
2362 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2363 return IDWriteTextFormat1_GetWordWrapping(&This->IDWriteTextFormat1_iface);
2366 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_GetReadingDirection(IDWriteTextLayout2 *iface)
2368 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2369 return IDWriteTextFormat1_GetReadingDirection(&This->IDWriteTextFormat1_iface);
2372 static DWRITE_FLOW_DIRECTION WINAPI dwritetextlayout_GetFlowDirection(IDWriteTextLayout2 *iface)
2374 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2375 return IDWriteTextFormat1_GetFlowDirection(&This->IDWriteTextFormat1_iface);
2378 static FLOAT WINAPI dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout2 *iface)
2380 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2381 return IDWriteTextFormat1_GetIncrementalTabStop(&This->IDWriteTextFormat1_iface);
2384 static HRESULT WINAPI dwritetextlayout_GetTrimming(IDWriteTextLayout2 *iface, DWRITE_TRIMMING *options,
2385 IDWriteInlineObject **trimming_sign)
2387 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2388 return IDWriteTextFormat1_GetTrimming(&This->IDWriteTextFormat1_iface, options, trimming_sign);
2391 static HRESULT WINAPI dwritetextlayout_GetLineSpacing(IDWriteTextLayout2 *iface, DWRITE_LINE_SPACING_METHOD *method,
2392 FLOAT *spacing, FLOAT *baseline)
2394 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2395 return IDWriteTextFormat1_GetLineSpacing(&This->IDWriteTextFormat1_iface, method, spacing, baseline);
2398 static HRESULT WINAPI dwritetextlayout_GetFontCollection(IDWriteTextLayout2 *iface, IDWriteFontCollection **collection)
2400 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2401 return IDWriteTextFormat1_GetFontCollection(&This->IDWriteTextFormat1_iface, collection);
2404 static UINT32 WINAPI dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout2 *iface)
2406 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2407 return IDWriteTextFormat1_GetFontFamilyNameLength(&This->IDWriteTextFormat1_iface);
2410 static HRESULT WINAPI dwritetextlayout_GetFontFamilyName(IDWriteTextLayout2 *iface, WCHAR *name, UINT32 size)
2412 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2413 return IDWriteTextFormat1_GetFontFamilyName(&This->IDWriteTextFormat1_iface, name, size);
2416 static DWRITE_FONT_WEIGHT WINAPI dwritetextlayout_GetFontWeight(IDWriteTextLayout2 *iface)
2418 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2419 return IDWriteTextFormat1_GetFontWeight(&This->IDWriteTextFormat1_iface);
2422 static DWRITE_FONT_STYLE WINAPI dwritetextlayout_GetFontStyle(IDWriteTextLayout2 *iface)
2424 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2425 return IDWriteTextFormat1_GetFontStyle(&This->IDWriteTextFormat1_iface);
2428 static DWRITE_FONT_STRETCH WINAPI dwritetextlayout_GetFontStretch(IDWriteTextLayout2 *iface)
2430 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2431 return IDWriteTextFormat1_GetFontStretch(&This->IDWriteTextFormat1_iface);
2434 static FLOAT WINAPI dwritetextlayout_GetFontSize(IDWriteTextLayout2 *iface)
2436 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2437 return IDWriteTextFormat1_GetFontSize(&This->IDWriteTextFormat1_iface);
2440 static UINT32 WINAPI dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout2 *iface)
2442 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2443 return IDWriteTextFormat1_GetLocaleNameLength(&This->IDWriteTextFormat1_iface);
2446 static HRESULT WINAPI dwritetextlayout_GetLocaleName(IDWriteTextLayout2 *iface, WCHAR *name, UINT32 size)
2448 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2449 return IDWriteTextFormat1_GetLocaleName(&This->IDWriteTextFormat1_iface, name, size);
2452 static HRESULT WINAPI dwritetextlayout_SetMaxWidth(IDWriteTextLayout2 *iface, FLOAT maxWidth)
2454 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2456 TRACE("(%p)->(%.2f)\n", This, maxWidth);
2458 if (maxWidth < 0.0f)
2459 return E_INVALIDARG;
2461 This->metrics.layoutWidth = maxWidth;
2462 return S_OK;
2465 static HRESULT WINAPI dwritetextlayout_SetMaxHeight(IDWriteTextLayout2 *iface, FLOAT maxHeight)
2467 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2469 TRACE("(%p)->(%.2f)\n", This, maxHeight);
2471 if (maxHeight < 0.0f)
2472 return E_INVALIDARG;
2474 This->metrics.layoutHeight = maxHeight;
2475 return S_OK;
2478 static HRESULT WINAPI dwritetextlayout_SetFontCollection(IDWriteTextLayout2 *iface, IDWriteFontCollection* collection, DWRITE_TEXT_RANGE range)
2480 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2481 struct layout_range_attr_value value;
2483 TRACE("(%p)->(%p %s)\n", This, collection, debugstr_range(&range));
2485 value.range = range;
2486 value.u.collection = collection;
2487 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTCOLL, &value);
2490 static HRESULT WINAPI dwritetextlayout_SetFontFamilyName(IDWriteTextLayout2 *iface, WCHAR const *name, DWRITE_TEXT_RANGE range)
2492 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2493 struct layout_range_attr_value value;
2495 TRACE("(%p)->(%s %s)\n", This, debugstr_w(name), debugstr_range(&range));
2497 if (!name)
2498 return E_INVALIDARG;
2500 value.range = range;
2501 value.u.fontfamily = name;
2502 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTFAMILY, &value);
2505 static HRESULT WINAPI dwritetextlayout_SetFontWeight(IDWriteTextLayout2 *iface, DWRITE_FONT_WEIGHT weight, DWRITE_TEXT_RANGE range)
2507 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2508 struct layout_range_attr_value value;
2510 TRACE("(%p)->(%d %s)\n", This, weight, debugstr_range(&range));
2512 value.range = range;
2513 value.u.weight = weight;
2514 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_WEIGHT, &value);
2517 static HRESULT WINAPI dwritetextlayout_SetFontStyle(IDWriteTextLayout2 *iface, DWRITE_FONT_STYLE style, DWRITE_TEXT_RANGE range)
2519 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2520 struct layout_range_attr_value value;
2522 TRACE("(%p)->(%d %s)\n", This, style, debugstr_range(&range));
2524 if ((UINT32)style > DWRITE_FONT_STYLE_ITALIC)
2525 return E_INVALIDARG;
2527 value.range = range;
2528 value.u.style = style;
2529 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STYLE, &value);
2532 static HRESULT WINAPI dwritetextlayout_SetFontStretch(IDWriteTextLayout2 *iface, DWRITE_FONT_STRETCH stretch, DWRITE_TEXT_RANGE range)
2534 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2535 struct layout_range_attr_value value;
2537 TRACE("(%p)->(%d %s)\n", This, stretch, debugstr_range(&range));
2539 if (stretch == DWRITE_FONT_STRETCH_UNDEFINED || (UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
2540 return E_INVALIDARG;
2542 value.range = range;
2543 value.u.stretch = stretch;
2544 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRETCH, &value);
2547 static HRESULT WINAPI dwritetextlayout_SetFontSize(IDWriteTextLayout2 *iface, FLOAT size, DWRITE_TEXT_RANGE range)
2549 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2550 struct layout_range_attr_value value;
2552 TRACE("(%p)->(%.2f %s)\n", This, size, debugstr_range(&range));
2554 if (size <= 0.0f)
2555 return E_INVALIDARG;
2557 value.range = range;
2558 value.u.fontsize = size;
2559 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTSIZE, &value);
2562 static HRESULT WINAPI dwritetextlayout_SetUnderline(IDWriteTextLayout2 *iface, BOOL underline, DWRITE_TEXT_RANGE range)
2564 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2565 struct layout_range_attr_value value;
2567 TRACE("(%p)->(%d %s)\n", This, underline, debugstr_range(&range));
2569 value.range = range;
2570 value.u.underline = underline;
2571 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_UNDERLINE, &value);
2574 static HRESULT WINAPI dwritetextlayout_SetStrikethrough(IDWriteTextLayout2 *iface, BOOL strikethrough, DWRITE_TEXT_RANGE range)
2576 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2577 struct layout_range_attr_value value;
2579 TRACE("(%p)->(%d %s)\n", This, strikethrough, debugstr_range(&range));
2581 value.range = range;
2582 value.u.strikethrough = strikethrough;
2583 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRIKETHROUGH, &value);
2586 static HRESULT WINAPI dwritetextlayout_SetDrawingEffect(IDWriteTextLayout2 *iface, IUnknown* effect, DWRITE_TEXT_RANGE range)
2588 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2589 struct layout_range_attr_value value;
2591 TRACE("(%p)->(%p %s)\n", This, effect, debugstr_range(&range));
2593 value.range = range;
2594 value.u.effect = effect;
2595 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_EFFECT, &value);
2598 static HRESULT WINAPI dwritetextlayout_SetInlineObject(IDWriteTextLayout2 *iface, IDWriteInlineObject *object, DWRITE_TEXT_RANGE range)
2600 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2601 struct layout_range_attr_value value;
2603 TRACE("(%p)->(%p %s)\n", This, object, debugstr_range(&range));
2605 value.range = range;
2606 value.u.object = object;
2607 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_INLINE, &value);
2610 static HRESULT WINAPI dwritetextlayout_SetTypography(IDWriteTextLayout2 *iface, IDWriteTypography* typography, DWRITE_TEXT_RANGE range)
2612 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2613 struct layout_range_attr_value value;
2615 TRACE("(%p)->(%p %s)\n", This, typography, debugstr_range(&range));
2617 value.range = range;
2618 value.u.typography = typography;
2619 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_TYPOGRAPHY, &value);
2622 static HRESULT WINAPI dwritetextlayout_SetLocaleName(IDWriteTextLayout2 *iface, WCHAR const* locale, DWRITE_TEXT_RANGE range)
2624 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2625 struct layout_range_attr_value value;
2627 TRACE("(%p)->(%s %s)\n", This, debugstr_w(locale), debugstr_range(&range));
2629 if (!locale || strlenW(locale) > LOCALE_NAME_MAX_LENGTH-1)
2630 return E_INVALIDARG;
2632 value.range = range;
2633 value.u.locale = locale;
2634 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_LOCALE, &value);
2637 static FLOAT WINAPI dwritetextlayout_GetMaxWidth(IDWriteTextLayout2 *iface)
2639 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2640 TRACE("(%p)\n", This);
2641 return This->metrics.layoutWidth;
2644 static FLOAT WINAPI dwritetextlayout_GetMaxHeight(IDWriteTextLayout2 *iface)
2646 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2647 TRACE("(%p)\n", This);
2648 return This->metrics.layoutHeight;
2651 static HRESULT WINAPI dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout2 *iface, UINT32 position,
2652 IDWriteFontCollection** collection, DWRITE_TEXT_RANGE *r)
2654 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2655 struct layout_range *range;
2657 TRACE("(%p)->(%u %p %p)\n", This, position, collection, r);
2659 if (position >= This->len)
2660 return S_OK;
2662 range = get_layout_range_by_pos(This, position);
2663 *collection = range->collection;
2664 if (*collection)
2665 IDWriteFontCollection_AddRef(*collection);
2667 return return_range(&range->h, r);
2670 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout2 *iface,
2671 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
2673 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2674 TRACE("(%p)->(%d %p %p)\n", This, position, length, r);
2675 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, length, r);
2678 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout2 *iface,
2679 UINT32 position, WCHAR *name, UINT32 length, DWRITE_TEXT_RANGE *r)
2681 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2682 TRACE("(%p)->(%u %p %u %p)\n", This, position, name, length, r);
2683 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, name, length, r);
2686 static HRESULT WINAPI dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout2 *iface,
2687 UINT32 position, DWRITE_FONT_WEIGHT *weight, DWRITE_TEXT_RANGE *r)
2689 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2690 struct layout_range *range;
2692 TRACE("(%p)->(%u %p %p)\n", This, position, weight, r);
2694 if (position >= This->len)
2695 return S_OK;
2697 range = get_layout_range_by_pos(This, position);
2698 *weight = range->weight;
2700 return return_range(&range->h, r);
2703 static HRESULT WINAPI dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout2 *iface,
2704 UINT32 position, DWRITE_FONT_STYLE *style, DWRITE_TEXT_RANGE *r)
2706 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2707 struct layout_range *range;
2709 TRACE("(%p)->(%u %p %p)\n", This, position, style, r);
2711 range = get_layout_range_by_pos(This, position);
2712 *style = range->style;
2713 return return_range(&range->h, r);
2716 static HRESULT WINAPI dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout2 *iface,
2717 UINT32 position, DWRITE_FONT_STRETCH *stretch, DWRITE_TEXT_RANGE *r)
2719 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2720 struct layout_range *range;
2722 TRACE("(%p)->(%u %p %p)\n", This, position, stretch, r);
2724 range = get_layout_range_by_pos(This, position);
2725 *stretch = range->stretch;
2726 return return_range(&range->h, r);
2729 static HRESULT WINAPI dwritetextlayout_layout_GetFontSize(IDWriteTextLayout2 *iface,
2730 UINT32 position, FLOAT *size, DWRITE_TEXT_RANGE *r)
2732 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2733 struct layout_range *range;
2735 TRACE("(%p)->(%u %p %p)\n", This, position, size, r);
2737 range = get_layout_range_by_pos(This, position);
2738 *size = range->fontsize;
2739 return return_range(&range->h, r);
2742 static HRESULT WINAPI dwritetextlayout_GetUnderline(IDWriteTextLayout2 *iface,
2743 UINT32 position, BOOL *underline, DWRITE_TEXT_RANGE *r)
2745 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2746 struct layout_range *range;
2748 TRACE("(%p)->(%u %p %p)\n", This, position, underline, r);
2750 if (position >= This->len)
2751 return S_OK;
2753 range = get_layout_range_by_pos(This, position);
2754 *underline = range->underline;
2756 return return_range(&range->h, r);
2759 static HRESULT WINAPI dwritetextlayout_GetStrikethrough(IDWriteTextLayout2 *iface,
2760 UINT32 position, BOOL *strikethrough, DWRITE_TEXT_RANGE *r)
2762 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2763 struct layout_range_bool *range;
2765 TRACE("(%p)->(%u %p %p)\n", This, position, strikethrough, r);
2767 range = (struct layout_range_bool*)get_layout_range_header_by_pos(&This->strike_ranges, position);
2768 *strikethrough = range->value;
2770 return return_range(&range->h, r);
2773 static HRESULT WINAPI dwritetextlayout_GetDrawingEffect(IDWriteTextLayout2 *iface,
2774 UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r)
2776 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2777 struct layout_range_iface *range;
2779 TRACE("(%p)->(%u %p %p)\n", This, position, effect, r);
2781 range = (struct layout_range_iface*)get_layout_range_header_by_pos(&This->effects, position);
2782 *effect = range->iface;
2783 if (*effect)
2784 IUnknown_AddRef(*effect);
2786 return return_range(&range->h, r);
2789 static HRESULT WINAPI dwritetextlayout_GetInlineObject(IDWriteTextLayout2 *iface,
2790 UINT32 position, IDWriteInlineObject **object, DWRITE_TEXT_RANGE *r)
2792 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2793 struct layout_range *range;
2795 TRACE("(%p)->(%u %p %p)\n", This, position, object, r);
2797 if (position >= This->len)
2798 return S_OK;
2800 range = get_layout_range_by_pos(This, position);
2801 *object = range->object;
2802 if (*object)
2803 IDWriteInlineObject_AddRef(*object);
2805 return return_range(&range->h, r);
2808 static HRESULT WINAPI dwritetextlayout_GetTypography(IDWriteTextLayout2 *iface,
2809 UINT32 position, IDWriteTypography** typography, DWRITE_TEXT_RANGE *r)
2811 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2812 struct layout_range_iface *range;
2814 TRACE("(%p)->(%u %p %p)\n", This, position, typography, r);
2816 range = (struct layout_range_iface*)get_layout_range_header_by_pos(&This->typographies, position);
2817 *typography = (IDWriteTypography*)range->iface;
2818 if (*typography)
2819 IDWriteTypography_AddRef(*typography);
2821 return return_range(&range->h, r);
2824 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout2 *iface,
2825 UINT32 position, UINT32* length, DWRITE_TEXT_RANGE *r)
2827 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2828 TRACE("(%p)->(%u %p %p)\n", This, position, length, r);
2829 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_LOCALE, position, length, r);
2832 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout2 *iface,
2833 UINT32 position, WCHAR* locale, UINT32 length, DWRITE_TEXT_RANGE *r)
2835 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2836 TRACE("(%p)->(%u %p %u %p)\n", This, position, locale, length, r);
2837 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_LOCALE, position, locale, length, r);
2840 static inline FLOAT renderer_apply_snapping(FLOAT coord, BOOL skiptransform, FLOAT ppdip, FLOAT det,
2841 const DWRITE_MATRIX *m)
2843 FLOAT vec[2], vec2[2];
2845 if (!skiptransform) {
2846 /* apply transform */
2847 vec[0] = 0.0f;
2848 vec[1] = coord * ppdip;
2850 vec2[0] = m->m11 * vec[0] + m->m21 * vec[1] + m->dx;
2851 vec2[1] = m->m12 * vec[0] + m->m22 * vec[1] + m->dy;
2853 /* snap */
2854 vec2[0] = floorf(vec2[0] + 0.5f);
2855 vec2[1] = floorf(vec2[1] + 0.5f);
2857 /* apply inverted transform, we don't care about X component at this point */
2858 vec[1] = (-m->m12 * vec2[0] + m->m11 * vec2[1] - (m->m11 * m->dy - m->m12 * m->dx)) / det;
2859 vec[1] /= ppdip;
2861 else
2862 vec[1] = floorf(coord * ppdip + 0.5f) / ppdip;
2864 return vec[1];
2867 static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface,
2868 void *context, IDWriteTextRenderer* renderer, FLOAT origin_x, FLOAT origin_y)
2870 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2871 BOOL disabled = FALSE, skiptransform = FALSE;
2872 struct layout_effective_inline *inlineobject;
2873 struct layout_effective_run *run;
2874 struct layout_strikethrough *s;
2875 FLOAT det = 0.0f, ppdip = 0.0f;
2876 DWRITE_MATRIX m = { 0 };
2877 HRESULT hr;
2879 TRACE("(%p)->(%p %p %.2f %.2f)\n", This, context, renderer, origin_x, origin_y);
2881 hr = layout_compute_effective_runs(This);
2882 if (FAILED(hr))
2883 return hr;
2885 hr = IDWriteTextRenderer_IsPixelSnappingDisabled(renderer, context, &disabled);
2886 if (FAILED(hr))
2887 return hr;
2889 if (!disabled) {
2890 hr = IDWriteTextRenderer_GetPixelsPerDip(renderer, context, &ppdip);
2891 if (FAILED(hr))
2892 return hr;
2894 hr = IDWriteTextRenderer_GetCurrentTransform(renderer, context, &m);
2895 if (FAILED(hr))
2896 return hr;
2898 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
2899 if (ppdip <= 0.0f ||
2900 (m.m11 * m.m22 != 0.0f && (m.m12 != 0.0f || m.m21 != 0.0f)) ||
2901 (m.m12 * m.m21 != 0.0f && (m.m11 != 0.0f || m.m22 != 0.0f)))
2902 disabled = TRUE;
2903 else
2904 skiptransform = should_skip_transform(&m, &det);
2907 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
2908 /* 1. Regular runs */
2909 LIST_FOR_EACH_ENTRY(run, &This->eruns, struct layout_effective_run, entry) {
2910 const struct regular_layout_run *regular = &run->run->u.regular;
2911 UINT32 start_glyph = regular->clustermap[run->start];
2912 DWRITE_GLYPH_RUN_DESCRIPTION descr;
2913 DWRITE_GLYPH_RUN glyph_run;
2915 /* Everything but cluster map will be reused from nominal run, as we only need
2916 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
2917 it can't be reused because it has to start with 0 index for each reported run. */
2918 glyph_run = regular->run;
2919 glyph_run.glyphCount = run->glyphcount;
2921 /* fixup glyph data arrays */
2922 glyph_run.glyphIndices += start_glyph;
2923 glyph_run.glyphAdvances += start_glyph;
2924 glyph_run.glyphOffsets += start_glyph;
2926 /* description */
2927 descr = regular->descr;
2928 descr.stringLength = run->length;
2929 descr.string += run->start;
2930 descr.clusterMap = run->clustermap;
2931 descr.textPosition += run->start;
2933 /* return value is ignored */
2934 IDWriteTextRenderer_DrawGlyphRun(renderer,
2935 context,
2936 run->origin_x + run->align_dx + origin_x,
2937 SNAP_COORD(run->origin_y + origin_y),
2938 This->measuringmode,
2939 &glyph_run,
2940 &descr,
2941 NULL);
2944 /* 2. Inline objects */
2945 LIST_FOR_EACH_ENTRY(inlineobject, &This->inlineobjects, struct layout_effective_inline, entry) {
2946 IDWriteTextRenderer_DrawInlineObject(renderer,
2947 context,
2948 inlineobject->origin_x + inlineobject->align_dx + origin_x,
2949 SNAP_COORD(inlineobject->origin_y + origin_y),
2950 inlineobject->object,
2951 inlineobject->is_sideways,
2952 inlineobject->is_rtl,
2953 inlineobject->effect);
2956 /* TODO: 3. Underlines */
2958 /* 4. Strikethrough */
2959 LIST_FOR_EACH_ENTRY(s, &This->strikethrough, struct layout_strikethrough, entry) {
2960 IDWriteTextRenderer_DrawStrikethrough(renderer,
2961 context,
2962 s->run->origin_x,
2963 SNAP_COORD(s->run->origin_y),
2964 &s->s,
2965 NULL);
2967 #undef SNAP_COORD
2969 return S_OK;
2972 static HRESULT WINAPI dwritetextlayout_GetLineMetrics(IDWriteTextLayout2 *iface,
2973 DWRITE_LINE_METRICS *metrics, UINT32 max_count, UINT32 *count)
2975 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2976 HRESULT hr;
2978 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
2980 hr = layout_compute_effective_runs(This);
2981 if (FAILED(hr))
2982 return hr;
2984 if (metrics)
2985 memcpy(metrics, This->lines, sizeof(*metrics)*min(max_count, This->metrics.lineCount));
2987 *count = This->metrics.lineCount;
2988 return max_count >= This->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
2991 static HRESULT WINAPI dwritetextlayout_GetMetrics(IDWriteTextLayout2 *iface, DWRITE_TEXT_METRICS *metrics)
2993 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2994 DWRITE_TEXT_METRICS1 metrics1;
2995 HRESULT hr;
2997 TRACE("(%p)->(%p)\n", This, metrics);
2999 hr = IDWriteTextLayout2_GetMetrics(iface, &metrics1);
3000 if (hr == S_OK)
3001 memcpy(metrics, &metrics1, sizeof(*metrics));
3003 return hr;
3006 static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout2 *iface, DWRITE_OVERHANG_METRICS *overhangs)
3008 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3009 FIXME("(%p)->(%p): stub\n", This, overhangs);
3010 return E_NOTIMPL;
3013 static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout2 *iface,
3014 DWRITE_CLUSTER_METRICS *metrics, UINT32 max_count, UINT32 *count)
3016 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3017 HRESULT hr;
3019 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
3021 hr = layout_compute(This);
3022 if (FAILED(hr))
3023 return hr;
3025 if (metrics)
3026 memcpy(metrics, This->clustermetrics, sizeof(DWRITE_CLUSTER_METRICS)*min(max_count, This->cluster_count));
3028 *count = This->cluster_count;
3029 return max_count >= This->cluster_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3032 /* Only to be used with DetermineMinWidth() to find the longest cluster sequence that we don't want to try
3033 too hard to break. */
3034 static inline BOOL is_terminal_cluster(struct dwrite_textlayout *layout, UINT32 index)
3036 if (layout->clustermetrics[index].isWhitespace || layout->clustermetrics[index].isNewline ||
3037 (index == layout->cluster_count - 1))
3038 return TRUE;
3039 /* check next one */
3040 return (index < layout->cluster_count - 1) && layout->clustermetrics[index+1].isWhitespace;
3043 static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout2 *iface, FLOAT* min_width)
3045 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3046 FLOAT width;
3047 HRESULT hr;
3048 UINT32 i;
3050 TRACE("(%p)->(%p)\n", This, min_width);
3052 if (!min_width)
3053 return E_INVALIDARG;
3055 if (!(This->recompute & RECOMPUTE_MINIMAL_WIDTH))
3056 goto width_done;
3058 *min_width = 0.0f;
3059 hr = layout_compute(This);
3060 if (FAILED(hr))
3061 return hr;
3063 for (i = 0; i < This->cluster_count;) {
3064 if (is_terminal_cluster(This, i)) {
3065 width = This->clustermetrics[i].width;
3066 i++;
3068 else {
3069 width = 0.0f;
3070 while (!is_terminal_cluster(This, i)) {
3071 width += This->clustermetrics[i].width;
3072 i++;
3074 /* count last one too */
3075 width += This->clustermetrics[i].width;
3078 if (width > This->minwidth)
3079 This->minwidth = width;
3081 This->recompute &= ~RECOMPUTE_MINIMAL_WIDTH;
3083 width_done:
3084 *min_width = This->minwidth;
3085 return S_OK;
3088 static HRESULT WINAPI dwritetextlayout_HitTestPoint(IDWriteTextLayout2 *iface,
3089 FLOAT pointX, FLOAT pointY, BOOL* is_trailinghit, BOOL* is_inside, DWRITE_HIT_TEST_METRICS *metrics)
3091 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3092 FIXME("(%p)->(%f %f %p %p %p): stub\n", This, pointX, pointY, is_trailinghit, is_inside, metrics);
3093 return E_NOTIMPL;
3096 static HRESULT WINAPI dwritetextlayout_HitTestTextPosition(IDWriteTextLayout2 *iface,
3097 UINT32 textPosition, BOOL is_trailinghit, FLOAT* pointX, FLOAT* pointY, DWRITE_HIT_TEST_METRICS *metrics)
3099 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3100 FIXME("(%p)->(%u %d %p %p %p): stub\n", This, textPosition, is_trailinghit, pointX, pointY, metrics);
3101 return E_NOTIMPL;
3104 static HRESULT WINAPI dwritetextlayout_HitTestTextRange(IDWriteTextLayout2 *iface,
3105 UINT32 textPosition, UINT32 textLength, FLOAT originX, FLOAT originY,
3106 DWRITE_HIT_TEST_METRICS *metrics, UINT32 max_metricscount, UINT32* actual_metricscount)
3108 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3109 FIXME("(%p)->(%u %u %f %f %p %u %p): stub\n", This, textPosition, textLength, originX, originY, metrics,
3110 max_metricscount, actual_metricscount);
3111 return E_NOTIMPL;
3114 static HRESULT WINAPI dwritetextlayout1_SetPairKerning(IDWriteTextLayout2 *iface, BOOL is_pairkerning_enabled,
3115 DWRITE_TEXT_RANGE range)
3117 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3118 struct layout_range_attr_value value;
3120 TRACE("(%p)->(%d %s)\n", This, is_pairkerning_enabled, debugstr_range(&range));
3122 value.range = range;
3123 value.u.pair_kerning = !!is_pairkerning_enabled;
3124 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_PAIR_KERNING, &value);
3127 static HRESULT WINAPI dwritetextlayout1_GetPairKerning(IDWriteTextLayout2 *iface, UINT32 position, BOOL *is_pairkerning_enabled,
3128 DWRITE_TEXT_RANGE *r)
3130 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3131 struct layout_range *range;
3133 TRACE("(%p)->(%u %p %p)\n", This, position, is_pairkerning_enabled, r);
3135 if (position >= This->len)
3136 return S_OK;
3138 range = get_layout_range_by_pos(This, position);
3139 *is_pairkerning_enabled = range->pair_kerning;
3141 return return_range(&range->h, r);
3144 static HRESULT WINAPI dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout2 *iface, FLOAT leading, FLOAT trailing,
3145 FLOAT min_advance, DWRITE_TEXT_RANGE range)
3147 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3148 struct layout_range_attr_value value;
3150 TRACE("(%p)->(%.2f %.2f %.2f %s)\n", This, leading, trailing, min_advance, debugstr_range(&range));
3152 if (min_advance < 0.0f)
3153 return E_INVALIDARG;
3155 value.range = range;
3156 value.u.spacing[0] = leading;
3157 value.u.spacing[1] = trailing;
3158 value.u.spacing[2] = min_advance;
3159 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_SPACING, &value);
3162 static HRESULT WINAPI dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout2 *iface, UINT32 position, FLOAT *leading,
3163 FLOAT *trailing, FLOAT *min_advance, DWRITE_TEXT_RANGE *r)
3165 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3166 struct layout_range_spacing *range;
3168 TRACE("(%p)->(%u %p %p %p %p)\n", This, position, leading, trailing, min_advance, r);
3170 range = (struct layout_range_spacing*)get_layout_range_header_by_pos(&This->spacing, position);
3171 *leading = range->leading;
3172 *trailing = range->trailing;
3173 *min_advance = range->min_advance;
3175 return return_range(&range->h, r);
3178 static HRESULT WINAPI dwritetextlayout2_GetMetrics(IDWriteTextLayout2 *iface, DWRITE_TEXT_METRICS1 *metrics)
3180 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3181 HRESULT hr;
3183 TRACE("(%p)->(%p)\n", This, metrics);
3185 hr = layout_compute_effective_runs(This);
3186 if (FAILED(hr))
3187 return hr;
3189 *metrics = This->metrics;
3190 return S_OK;
3193 static HRESULT WINAPI dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout2 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
3195 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3197 TRACE("(%p)->(%d)\n", This, orientation);
3199 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
3200 return E_INVALIDARG;
3202 This->format.vertical_orientation = orientation;
3203 return S_OK;
3206 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout2 *iface)
3208 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3209 TRACE("(%p)\n", This);
3210 return This->format.vertical_orientation;
3213 static HRESULT WINAPI dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout2 *iface, BOOL lastline_wrapping_enabled)
3215 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3216 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
3217 return IDWriteTextFormat1_SetLastLineWrapping(&This->IDWriteTextFormat1_iface, lastline_wrapping_enabled);
3220 static BOOL WINAPI dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout2 *iface)
3222 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3223 TRACE("(%p)\n", This);
3224 return IDWriteTextFormat1_GetLastLineWrapping(&This->IDWriteTextFormat1_iface);
3227 static HRESULT WINAPI dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout2 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
3229 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3230 TRACE("(%p)->(%d)\n", This, alignment);
3231 return IDWriteTextFormat1_SetOpticalAlignment(&This->IDWriteTextFormat1_iface, alignment);
3234 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout2 *iface)
3236 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3237 TRACE("(%p)\n", This);
3238 return IDWriteTextFormat1_GetOpticalAlignment(&This->IDWriteTextFormat1_iface);
3241 static HRESULT WINAPI dwritetextlayout2_SetFontFallback(IDWriteTextLayout2 *iface, IDWriteFontFallback *fallback)
3243 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3244 TRACE("(%p)->(%p)\n", This, fallback);
3245 return set_fontfallback_for_format(&This->format, fallback);
3248 static HRESULT WINAPI dwritetextlayout2_GetFontFallback(IDWriteTextLayout2 *iface, IDWriteFontFallback **fallback)
3250 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3251 TRACE("(%p)->(%p)\n", This, fallback);
3252 return get_fontfallback_from_format(&This->format, fallback);
3255 static const IDWriteTextLayout2Vtbl dwritetextlayoutvtbl = {
3256 dwritetextlayout_QueryInterface,
3257 dwritetextlayout_AddRef,
3258 dwritetextlayout_Release,
3259 dwritetextlayout_SetTextAlignment,
3260 dwritetextlayout_SetParagraphAlignment,
3261 dwritetextlayout_SetWordWrapping,
3262 dwritetextlayout_SetReadingDirection,
3263 dwritetextlayout_SetFlowDirection,
3264 dwritetextlayout_SetIncrementalTabStop,
3265 dwritetextlayout_SetTrimming,
3266 dwritetextlayout_SetLineSpacing,
3267 dwritetextlayout_GetTextAlignment,
3268 dwritetextlayout_GetParagraphAlignment,
3269 dwritetextlayout_GetWordWrapping,
3270 dwritetextlayout_GetReadingDirection,
3271 dwritetextlayout_GetFlowDirection,
3272 dwritetextlayout_GetIncrementalTabStop,
3273 dwritetextlayout_GetTrimming,
3274 dwritetextlayout_GetLineSpacing,
3275 dwritetextlayout_GetFontCollection,
3276 dwritetextlayout_GetFontFamilyNameLength,
3277 dwritetextlayout_GetFontFamilyName,
3278 dwritetextlayout_GetFontWeight,
3279 dwritetextlayout_GetFontStyle,
3280 dwritetextlayout_GetFontStretch,
3281 dwritetextlayout_GetFontSize,
3282 dwritetextlayout_GetLocaleNameLength,
3283 dwritetextlayout_GetLocaleName,
3284 dwritetextlayout_SetMaxWidth,
3285 dwritetextlayout_SetMaxHeight,
3286 dwritetextlayout_SetFontCollection,
3287 dwritetextlayout_SetFontFamilyName,
3288 dwritetextlayout_SetFontWeight,
3289 dwritetextlayout_SetFontStyle,
3290 dwritetextlayout_SetFontStretch,
3291 dwritetextlayout_SetFontSize,
3292 dwritetextlayout_SetUnderline,
3293 dwritetextlayout_SetStrikethrough,
3294 dwritetextlayout_SetDrawingEffect,
3295 dwritetextlayout_SetInlineObject,
3296 dwritetextlayout_SetTypography,
3297 dwritetextlayout_SetLocaleName,
3298 dwritetextlayout_GetMaxWidth,
3299 dwritetextlayout_GetMaxHeight,
3300 dwritetextlayout_layout_GetFontCollection,
3301 dwritetextlayout_layout_GetFontFamilyNameLength,
3302 dwritetextlayout_layout_GetFontFamilyName,
3303 dwritetextlayout_layout_GetFontWeight,
3304 dwritetextlayout_layout_GetFontStyle,
3305 dwritetextlayout_layout_GetFontStretch,
3306 dwritetextlayout_layout_GetFontSize,
3307 dwritetextlayout_GetUnderline,
3308 dwritetextlayout_GetStrikethrough,
3309 dwritetextlayout_GetDrawingEffect,
3310 dwritetextlayout_GetInlineObject,
3311 dwritetextlayout_GetTypography,
3312 dwritetextlayout_layout_GetLocaleNameLength,
3313 dwritetextlayout_layout_GetLocaleName,
3314 dwritetextlayout_Draw,
3315 dwritetextlayout_GetLineMetrics,
3316 dwritetextlayout_GetMetrics,
3317 dwritetextlayout_GetOverhangMetrics,
3318 dwritetextlayout_GetClusterMetrics,
3319 dwritetextlayout_DetermineMinWidth,
3320 dwritetextlayout_HitTestPoint,
3321 dwritetextlayout_HitTestTextPosition,
3322 dwritetextlayout_HitTestTextRange,
3323 dwritetextlayout1_SetPairKerning,
3324 dwritetextlayout1_GetPairKerning,
3325 dwritetextlayout1_SetCharacterSpacing,
3326 dwritetextlayout1_GetCharacterSpacing,
3327 dwritetextlayout2_GetMetrics,
3328 dwritetextlayout2_SetVerticalGlyphOrientation,
3329 dwritetextlayout2_GetVerticalGlyphOrientation,
3330 dwritetextlayout2_SetLastLineWrapping,
3331 dwritetextlayout2_GetLastLineWrapping,
3332 dwritetextlayout2_SetOpticalAlignment,
3333 dwritetextlayout2_GetOpticalAlignment,
3334 dwritetextlayout2_SetFontFallback,
3335 dwritetextlayout2_GetFontFallback
3338 static HRESULT WINAPI dwritetextformat1_layout_QueryInterface(IDWriteTextFormat1 *iface, REFIID riid, void **obj)
3340 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3341 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3342 return IDWriteTextLayout2_QueryInterface(&This->IDWriteTextLayout2_iface, riid, obj);
3345 static ULONG WINAPI dwritetextformat1_layout_AddRef(IDWriteTextFormat1 *iface)
3347 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3348 return IDWriteTextLayout2_AddRef(&This->IDWriteTextLayout2_iface);
3351 static ULONG WINAPI dwritetextformat1_layout_Release(IDWriteTextFormat1 *iface)
3353 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3354 return IDWriteTextLayout2_Release(&This->IDWriteTextLayout2_iface);
3357 static HRESULT WINAPI dwritetextformat1_layout_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
3359 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3360 BOOL changed;
3361 HRESULT hr;
3363 TRACE("(%p)->(%d)\n", This, alignment);
3365 hr = format_set_textalignment(&This->format, alignment, &changed);
3366 if (FAILED(hr))
3367 return hr;
3369 /* if layout is not ready there's nothing to align */
3370 if (changed && !(This->recompute & RECOMPUTE_EFFECTIVE_RUNS))
3371 layout_apply_text_alignment(This);
3373 return S_OK;
3376 static HRESULT WINAPI dwritetextformat1_layout_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
3378 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3379 BOOL changed;
3380 HRESULT hr;
3382 TRACE("(%p)->(%d)\n", This, alignment);
3384 hr = format_set_paralignment(&This->format, alignment, &changed);
3385 if (FAILED(hr))
3386 return hr;
3388 /* if layout is not ready there's nothing to align */
3389 if (changed && !(This->recompute & RECOMPUTE_EFFECTIVE_RUNS))
3390 layout_apply_par_alignment(This);
3392 return S_OK;
3395 static HRESULT WINAPI dwritetextformat1_layout_SetWordWrapping(IDWriteTextFormat1 *iface, DWRITE_WORD_WRAPPING wrapping)
3397 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3398 BOOL changed;
3399 HRESULT hr;
3401 TRACE("(%p)->(%d)\n", This, wrapping);
3403 hr = format_set_wordwrapping(&This->format, wrapping, &changed);
3404 if (FAILED(hr))
3405 return hr;
3407 if (changed)
3408 This->recompute |= RECOMPUTE_EFFECTIVE_RUNS;
3410 return S_OK;
3413 static HRESULT WINAPI dwritetextformat1_layout_SetReadingDirection(IDWriteTextFormat1 *iface, DWRITE_READING_DIRECTION direction)
3415 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3416 BOOL changed;
3417 HRESULT hr;
3419 TRACE("(%p)->(%d)\n", This, direction);
3421 hr = format_set_readingdirection(&This->format, direction, &changed);
3422 if (FAILED(hr))
3423 return hr;
3425 if (changed)
3426 This->recompute = RECOMPUTE_EVERYTHING;
3428 return S_OK;
3431 static HRESULT WINAPI dwritetextformat1_layout_SetFlowDirection(IDWriteTextFormat1 *iface, DWRITE_FLOW_DIRECTION direction)
3433 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3434 FIXME("(%p)->(%d): stub\n", This, direction);
3435 return E_NOTIMPL;
3438 static HRESULT WINAPI dwritetextformat1_layout_SetIncrementalTabStop(IDWriteTextFormat1 *iface, FLOAT tabstop)
3440 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3441 FIXME("(%p)->(%f): stub\n", This, tabstop);
3442 return E_NOTIMPL;
3445 static HRESULT WINAPI dwritetextformat1_layout_SetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING const *trimming,
3446 IDWriteInlineObject *trimming_sign)
3448 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3449 FIXME("(%p)->(%p %p): stub\n", This, trimming, trimming_sign);
3450 return E_NOTIMPL;
3453 static HRESULT WINAPI dwritetextformat1_layout_SetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD spacing,
3454 FLOAT line_spacing, FLOAT baseline)
3456 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3457 FIXME("(%p)->(%d %f %f): stub\n", This, spacing, line_spacing, baseline);
3458 return E_NOTIMPL;
3461 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat1_layout_GetTextAlignment(IDWriteTextFormat1 *iface)
3463 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3464 TRACE("(%p)\n", This);
3465 return This->format.textalignment;
3468 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat1_layout_GetParagraphAlignment(IDWriteTextFormat1 *iface)
3470 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3471 TRACE("(%p)\n", This);
3472 return This->format.paralign;
3475 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat1_layout_GetWordWrapping(IDWriteTextFormat1 *iface)
3477 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3478 TRACE("(%p)\n", This);
3479 return This->format.wrapping;
3482 static DWRITE_READING_DIRECTION WINAPI dwritetextformat1_layout_GetReadingDirection(IDWriteTextFormat1 *iface)
3484 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3485 TRACE("(%p)\n", This);
3486 return This->format.readingdir;
3489 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat1_layout_GetFlowDirection(IDWriteTextFormat1 *iface)
3491 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3492 TRACE("(%p)\n", This);
3493 return This->format.flow;
3496 static FLOAT WINAPI dwritetextformat1_layout_GetIncrementalTabStop(IDWriteTextFormat1 *iface)
3498 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3499 FIXME("(%p): stub\n", This);
3500 return 0.0f;
3503 static HRESULT WINAPI dwritetextformat1_layout_GetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING *options,
3504 IDWriteInlineObject **trimming_sign)
3506 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3508 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
3510 *options = This->format.trimming;
3511 *trimming_sign = This->format.trimmingsign;
3512 if (*trimming_sign)
3513 IDWriteInlineObject_AddRef(*trimming_sign);
3514 return S_OK;
3517 static HRESULT WINAPI dwritetextformat1_layout_GetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD *method,
3518 FLOAT *spacing, FLOAT *baseline)
3520 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3522 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
3524 *method = This->format.spacingmethod;
3525 *spacing = This->format.spacing;
3526 *baseline = This->format.baseline;
3527 return S_OK;
3530 static HRESULT WINAPI dwritetextformat1_layout_GetFontCollection(IDWriteTextFormat1 *iface, IDWriteFontCollection **collection)
3532 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3534 TRACE("(%p)->(%p)\n", This, collection);
3536 *collection = This->format.collection;
3537 if (*collection)
3538 IDWriteFontCollection_AddRef(*collection);
3539 return S_OK;
3542 static UINT32 WINAPI dwritetextformat1_layout_GetFontFamilyNameLength(IDWriteTextFormat1 *iface)
3544 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3545 TRACE("(%p)\n", This);
3546 return This->format.family_len;
3549 static HRESULT WINAPI dwritetextformat1_layout_GetFontFamilyName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
3551 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3553 TRACE("(%p)->(%p %u)\n", This, name, size);
3555 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
3556 strcpyW(name, This->format.family_name);
3557 return S_OK;
3560 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat1_layout_GetFontWeight(IDWriteTextFormat1 *iface)
3562 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3563 TRACE("(%p)\n", This);
3564 return This->format.weight;
3567 static DWRITE_FONT_STYLE WINAPI dwritetextformat1_layout_GetFontStyle(IDWriteTextFormat1 *iface)
3569 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3570 TRACE("(%p)\n", This);
3571 return This->format.style;
3574 static DWRITE_FONT_STRETCH WINAPI dwritetextformat1_layout_GetFontStretch(IDWriteTextFormat1 *iface)
3576 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3577 TRACE("(%p)\n", This);
3578 return This->format.stretch;
3581 static FLOAT WINAPI dwritetextformat1_layout_GetFontSize(IDWriteTextFormat1 *iface)
3583 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3584 TRACE("(%p)\n", This);
3585 return This->format.fontsize;
3588 static UINT32 WINAPI dwritetextformat1_layout_GetLocaleNameLength(IDWriteTextFormat1 *iface)
3590 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3591 TRACE("(%p)\n", This);
3592 return This->format.locale_len;
3595 static HRESULT WINAPI dwritetextformat1_layout_GetLocaleName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
3597 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3599 TRACE("(%p)->(%p %u)\n", This, name, size);
3601 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
3602 strcpyW(name, This->format.locale);
3603 return S_OK;
3606 static HRESULT WINAPI dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat1 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
3608 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3609 FIXME("(%p)->(%d): stub\n", This, orientation);
3610 return E_NOTIMPL;
3613 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat1 *iface)
3615 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3616 FIXME("(%p): stub\n", This);
3617 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
3620 static HRESULT WINAPI dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat1 *iface, BOOL lastline_wrapping_enabled)
3622 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3624 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
3626 This->format.last_line_wrapping = !!lastline_wrapping_enabled;
3627 return S_OK;
3630 static BOOL WINAPI dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat1 *iface)
3632 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3633 TRACE("(%p)\n", This);
3634 return This->format.last_line_wrapping;
3637 static HRESULT WINAPI dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat1 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
3639 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3640 TRACE("(%p)->(%d)\n", This, alignment);
3641 return format_set_optical_alignment(&This->format, alignment);
3644 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat1 *iface)
3646 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3647 TRACE("(%p)\n", This);
3648 return This->format.optical_alignment;
3651 static HRESULT WINAPI dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback *fallback)
3653 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3654 TRACE("(%p)->(%p)\n", This, fallback);
3655 return IDWriteTextLayout2_SetFontFallback(&This->IDWriteTextLayout2_iface, fallback);
3658 static HRESULT WINAPI dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback **fallback)
3660 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3661 TRACE("(%p)->(%p)\n", This, fallback);
3662 return IDWriteTextLayout2_GetFontFallback(&This->IDWriteTextLayout2_iface, fallback);
3665 static const IDWriteTextFormat1Vtbl dwritetextformat1_layout_vtbl = {
3666 dwritetextformat1_layout_QueryInterface,
3667 dwritetextformat1_layout_AddRef,
3668 dwritetextformat1_layout_Release,
3669 dwritetextformat1_layout_SetTextAlignment,
3670 dwritetextformat1_layout_SetParagraphAlignment,
3671 dwritetextformat1_layout_SetWordWrapping,
3672 dwritetextformat1_layout_SetReadingDirection,
3673 dwritetextformat1_layout_SetFlowDirection,
3674 dwritetextformat1_layout_SetIncrementalTabStop,
3675 dwritetextformat1_layout_SetTrimming,
3676 dwritetextformat1_layout_SetLineSpacing,
3677 dwritetextformat1_layout_GetTextAlignment,
3678 dwritetextformat1_layout_GetParagraphAlignment,
3679 dwritetextformat1_layout_GetWordWrapping,
3680 dwritetextformat1_layout_GetReadingDirection,
3681 dwritetextformat1_layout_GetFlowDirection,
3682 dwritetextformat1_layout_GetIncrementalTabStop,
3683 dwritetextformat1_layout_GetTrimming,
3684 dwritetextformat1_layout_GetLineSpacing,
3685 dwritetextformat1_layout_GetFontCollection,
3686 dwritetextformat1_layout_GetFontFamilyNameLength,
3687 dwritetextformat1_layout_GetFontFamilyName,
3688 dwritetextformat1_layout_GetFontWeight,
3689 dwritetextformat1_layout_GetFontStyle,
3690 dwritetextformat1_layout_GetFontStretch,
3691 dwritetextformat1_layout_GetFontSize,
3692 dwritetextformat1_layout_GetLocaleNameLength,
3693 dwritetextformat1_layout_GetLocaleName,
3694 dwritetextformat1_layout_SetVerticalGlyphOrientation,
3695 dwritetextformat1_layout_GetVerticalGlyphOrientation,
3696 dwritetextformat1_layout_SetLastLineWrapping,
3697 dwritetextformat1_layout_GetLastLineWrapping,
3698 dwritetextformat1_layout_SetOpticalAlignment,
3699 dwritetextformat1_layout_GetOpticalAlignment,
3700 dwritetextformat1_layout_SetFontFallback,
3701 dwritetextformat1_layout_GetFontFallback
3704 static HRESULT WINAPI dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink *iface,
3705 REFIID riid, void **obj)
3707 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) || IsEqualIID(riid, &IID_IUnknown)) {
3708 *obj = iface;
3709 IDWriteTextAnalysisSink_AddRef(iface);
3710 return S_OK;
3713 *obj = NULL;
3714 return E_NOINTERFACE;
3717 static ULONG WINAPI dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink *iface)
3719 return 2;
3722 static ULONG WINAPI dwritetextlayout_sink_Release(IDWriteTextAnalysisSink *iface)
3724 return 1;
3727 static HRESULT WINAPI dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink *iface,
3728 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
3730 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
3731 struct layout_run *run;
3733 TRACE("%u %u script=%d\n", position, length, sa->script);
3735 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
3736 if (!run)
3737 return E_OUTOFMEMORY;
3739 run->u.regular.descr.string = &layout->str[position];
3740 run->u.regular.descr.stringLength = length;
3741 run->u.regular.descr.textPosition = position;
3742 run->u.regular.sa = *sa;
3743 list_add_tail(&layout->runs, &run->entry);
3744 return S_OK;
3747 static HRESULT WINAPI dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink *iface,
3748 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
3750 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
3752 if (position + length > layout->len)
3753 return E_FAIL;
3755 memcpy(&layout->nominal_breakpoints[position], breakpoints, length*sizeof(DWRITE_LINE_BREAKPOINT));
3756 return S_OK;
3759 static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink *iface, UINT32 position,
3760 UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
3762 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
3763 struct layout_run *cur_run;
3765 TRACE("%u %u %u %u\n", position, length, explicitLevel, resolvedLevel);
3767 LIST_FOR_EACH_ENTRY(cur_run, &layout->runs, struct layout_run, entry) {
3768 struct regular_layout_run *cur = &cur_run->u.regular;
3769 struct layout_run *run;
3771 if (cur_run->kind == LAYOUT_RUN_INLINE)
3772 continue;
3774 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
3775 if (position < cur->descr.textPosition || position >= cur->descr.textPosition + cur->descr.stringLength)
3776 continue;
3778 /* full hit - just set run level */
3779 if (cur->descr.textPosition == position && cur->descr.stringLength == length) {
3780 cur->run.bidiLevel = resolvedLevel;
3781 break;
3784 /* current run is fully covered, move to next one */
3785 if (cur->descr.textPosition == position && cur->descr.stringLength < length) {
3786 cur->run.bidiLevel = resolvedLevel;
3787 position += cur->descr.stringLength;
3788 length -= cur->descr.stringLength;
3789 continue;
3792 /* all fully covered runs are processed at this point, reuse existing run for remaining
3793 reported bidi range and add another run for the rest of original one */
3795 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
3796 if (!run)
3797 return E_OUTOFMEMORY;
3799 *run = *cur_run;
3800 run->u.regular.descr.textPosition = position + length;
3801 run->u.regular.descr.stringLength = cur->descr.stringLength - length;
3802 run->u.regular.descr.string = &layout->str[position + length];
3804 /* reduce existing run */
3805 cur->run.bidiLevel = resolvedLevel;
3806 cur->descr.stringLength = length;
3808 list_add_after(&cur_run->entry, &run->entry);
3809 break;
3812 return S_OK;
3815 static HRESULT WINAPI dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink *iface,
3816 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
3818 return E_NOTIMPL;
3821 static const IDWriteTextAnalysisSinkVtbl dwritetextlayoutsinkvtbl = {
3822 dwritetextlayout_sink_QueryInterface,
3823 dwritetextlayout_sink_AddRef,
3824 dwritetextlayout_sink_Release,
3825 dwritetextlayout_sink_SetScriptAnalysis,
3826 dwritetextlayout_sink_SetLineBreakpoints,
3827 dwritetextlayout_sink_SetBidiLevel,
3828 dwritetextlayout_sink_SetNumberSubstitution
3831 static HRESULT WINAPI dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource *iface,
3832 REFIID riid, void **obj)
3834 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) ||
3835 IsEqualIID(riid, &IID_IUnknown))
3837 *obj = iface;
3838 IDWriteTextAnalysisSource_AddRef(iface);
3839 return S_OK;
3842 *obj = NULL;
3843 return E_NOINTERFACE;
3846 static ULONG WINAPI dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource *iface)
3848 return 2;
3851 static ULONG WINAPI dwritetextlayout_source_Release(IDWriteTextAnalysisSource *iface)
3853 return 1;
3856 static HRESULT WINAPI dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource *iface,
3857 UINT32 position, WCHAR const** text, UINT32* text_len)
3859 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource(iface);
3861 TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
3863 if (position < layout->len) {
3864 *text = &layout->str[position];
3865 *text_len = layout->len - position;
3867 else {
3868 *text = NULL;
3869 *text_len = 0;
3872 return S_OK;
3875 static HRESULT WINAPI dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource *iface,
3876 UINT32 position, WCHAR const** text, UINT32* text_len)
3878 FIXME("%u %p %p: stub\n", position, text, text_len);
3879 return E_NOTIMPL;
3882 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource *iface)
3884 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource(iface);
3885 return IDWriteTextLayout2_GetReadingDirection(&layout->IDWriteTextLayout2_iface);
3888 static HRESULT WINAPI dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource *iface,
3889 UINT32 position, UINT32* text_len, WCHAR const** locale)
3891 FIXME("%u %p %p: stub\n", position, text_len, locale);
3892 return E_NOTIMPL;
3895 static HRESULT WINAPI dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource *iface,
3896 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
3898 FIXME("%u %p %p: stub\n", position, text_len, substitution);
3899 return E_NOTIMPL;
3902 static const IDWriteTextAnalysisSourceVtbl dwritetextlayoutsourcevtbl = {
3903 dwritetextlayout_source_QueryInterface,
3904 dwritetextlayout_source_AddRef,
3905 dwritetextlayout_source_Release,
3906 dwritetextlayout_source_GetTextAtPosition,
3907 dwritetextlayout_source_GetTextBeforePosition,
3908 dwritetextlayout_source_GetParagraphReadingDirection,
3909 dwritetextlayout_source_GetLocaleName,
3910 dwritetextlayout_source_GetNumberSubstitution
3913 static HRESULT layout_format_from_textformat(struct dwrite_textlayout *layout, IDWriteTextFormat *format)
3915 struct dwrite_textformat *textformat;
3916 IDWriteTextFormat1 *format1;
3917 UINT32 len;
3918 HRESULT hr;
3920 if ((textformat = unsafe_impl_from_IDWriteTextFormat(format))) {
3921 layout->format = textformat->format;
3923 layout->format.locale = heap_strdupW(textformat->format.locale);
3924 layout->format.family_name = heap_strdupW(textformat->format.family_name);
3925 if (!layout->format.locale || !layout->format.family_name)
3927 heap_free(layout->format.locale);
3928 heap_free(layout->format.family_name);
3929 return E_OUTOFMEMORY;
3932 if (layout->format.trimmingsign)
3933 IDWriteInlineObject_AddRef(layout->format.trimmingsign);
3934 if (layout->format.collection)
3935 IDWriteFontCollection_AddRef(layout->format.collection);
3936 if (layout->format.fallback)
3937 IDWriteFontFallback_AddRef(layout->format.fallback);
3939 return S_OK;
3942 layout->format.weight = IDWriteTextFormat_GetFontWeight(format);
3943 layout->format.style = IDWriteTextFormat_GetFontStyle(format);
3944 layout->format.stretch = IDWriteTextFormat_GetFontStretch(format);
3945 layout->format.fontsize= IDWriteTextFormat_GetFontSize(format);
3946 layout->format.textalignment = IDWriteTextFormat_GetTextAlignment(format);
3947 layout->format.paralign = IDWriteTextFormat_GetParagraphAlignment(format);
3948 layout->format.wrapping = IDWriteTextFormat_GetWordWrapping(format);
3949 layout->format.readingdir = IDWriteTextFormat_GetReadingDirection(format);
3950 layout->format.flow = IDWriteTextFormat_GetFlowDirection(format);
3951 layout->format.fallback = NULL;
3952 hr = IDWriteTextFormat_GetLineSpacing(format, &layout->format.spacingmethod,
3953 &layout->format.spacing, &layout->format.baseline);
3954 if (FAILED(hr))
3955 return hr;
3957 hr = IDWriteTextFormat_GetTrimming(format, &layout->format.trimming, &layout->format.trimmingsign);
3958 if (FAILED(hr))
3959 return hr;
3961 /* locale name and length */
3962 len = IDWriteTextFormat_GetLocaleNameLength(format);
3963 layout->format.locale = heap_alloc((len+1)*sizeof(WCHAR));
3964 if (!layout->format.locale)
3965 return E_OUTOFMEMORY;
3967 hr = IDWriteTextFormat_GetLocaleName(format, layout->format.locale, len+1);
3968 if (FAILED(hr))
3969 return hr;
3970 layout->format.locale_len = len;
3972 /* font family name and length */
3973 len = IDWriteTextFormat_GetFontFamilyNameLength(format);
3974 layout->format.family_name = heap_alloc((len+1)*sizeof(WCHAR));
3975 if (!layout->format.family_name)
3976 return E_OUTOFMEMORY;
3978 hr = IDWriteTextFormat_GetFontFamilyName(format, layout->format.family_name, len+1);
3979 if (FAILED(hr))
3980 return hr;
3981 layout->format.family_len = len;
3983 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
3984 if (hr == S_OK) {
3985 layout->format.vertical_orientation = IDWriteTextFormat1_GetVerticalGlyphOrientation(format1);
3986 layout->format.optical_alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
3987 IDWriteTextFormat1_GetFontFallback(format1, &layout->format.fallback);
3988 IDWriteTextFormat1_Release(format1);
3990 else {
3991 layout->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
3992 layout->format.optical_alignment = DWRITE_OPTICAL_ALIGNMENT_NONE;
3995 return IDWriteTextFormat_GetFontCollection(format, &layout->format.collection);
3998 static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, struct dwrite_textlayout *layout)
4000 struct layout_range_header *range, *strike, *effect, *spacing, *typography;
4001 static const DWRITE_TEXT_RANGE r = { 0, ~0u };
4002 HRESULT hr;
4004 layout->IDWriteTextLayout2_iface.lpVtbl = &dwritetextlayoutvtbl;
4005 layout->IDWriteTextFormat1_iface.lpVtbl = &dwritetextformat1_layout_vtbl;
4006 layout->IDWriteTextAnalysisSink_iface.lpVtbl = &dwritetextlayoutsinkvtbl;
4007 layout->IDWriteTextAnalysisSource_iface.lpVtbl = &dwritetextlayoutsourcevtbl;
4008 layout->ref = 1;
4009 layout->len = len;
4010 layout->recompute = RECOMPUTE_EVERYTHING;
4011 layout->nominal_breakpoints = NULL;
4012 layout->actual_breakpoints = NULL;
4013 layout->cluster_count = 0;
4014 layout->clustermetrics = NULL;
4015 layout->clusters = NULL;
4016 layout->lines = NULL;
4017 layout->line_alloc = 0;
4018 layout->minwidth = 0.0f;
4019 list_init(&layout->eruns);
4020 list_init(&layout->inlineobjects);
4021 list_init(&layout->strikethrough);
4022 list_init(&layout->runs);
4023 list_init(&layout->ranges);
4024 list_init(&layout->strike_ranges);
4025 list_init(&layout->effects);
4026 list_init(&layout->spacing);
4027 list_init(&layout->typographies);
4028 memset(&layout->format, 0, sizeof(layout->format));
4029 memset(&layout->metrics, 0, sizeof(layout->metrics));
4030 layout->metrics.layoutWidth = maxwidth;
4031 layout->metrics.layoutHeight = maxheight;
4032 layout->measuringmode = DWRITE_MEASURING_MODE_NATURAL;
4034 layout->ppdip = 0.0f;
4035 memset(&layout->transform, 0, sizeof(layout->transform));
4037 layout->str = heap_strdupnW(str, len);
4038 if (len && !layout->str) {
4039 hr = E_OUTOFMEMORY;
4040 goto fail;
4043 hr = layout_format_from_textformat(layout, format);
4044 if (FAILED(hr))
4045 goto fail;
4047 range = alloc_layout_range(layout, &r, LAYOUT_RANGE_REGULAR);
4048 strike = alloc_layout_range(layout, &r, LAYOUT_RANGE_STRIKETHROUGH);
4049 effect = alloc_layout_range(layout, &r, LAYOUT_RANGE_EFFECT);
4050 spacing = alloc_layout_range(layout, &r, LAYOUT_RANGE_SPACING);
4051 typography = alloc_layout_range(layout, &r, LAYOUT_RANGE_TYPOGRAPHY);
4052 if (!range || !strike || !effect || !spacing || !typography) {
4053 free_layout_range(range);
4054 free_layout_range(strike);
4055 free_layout_range(effect);
4056 free_layout_range(spacing);
4057 free_layout_range(typography);
4058 hr = E_OUTOFMEMORY;
4059 goto fail;
4062 list_add_head(&layout->ranges, &range->entry);
4063 list_add_head(&layout->strike_ranges, &strike->entry);
4064 list_add_head(&layout->effects, &effect->entry);
4065 list_add_head(&layout->spacing, &spacing->entry);
4066 list_add_head(&layout->typographies, &typography->entry);
4067 return S_OK;
4069 fail:
4070 IDWriteTextLayout2_Release(&layout->IDWriteTextLayout2_iface);
4071 return hr;
4074 HRESULT create_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, IDWriteTextLayout **ret)
4076 struct dwrite_textlayout *layout;
4077 HRESULT hr;
4079 *ret = NULL;
4081 layout = heap_alloc(sizeof(struct dwrite_textlayout));
4082 if (!layout) return E_OUTOFMEMORY;
4084 hr = init_textlayout(str, len, format, maxwidth, maxheight, layout);
4085 if (hr == S_OK)
4086 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout2_iface;
4088 return hr;
4091 HRESULT create_gdicompat_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight,
4092 FLOAT ppdip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural, IDWriteTextLayout **ret)
4094 struct dwrite_textlayout *layout;
4095 HRESULT hr;
4097 *ret = NULL;
4099 layout = heap_alloc(sizeof(struct dwrite_textlayout));
4100 if (!layout) return E_OUTOFMEMORY;
4102 hr = init_textlayout(str, len, format, maxwidth, maxheight, layout);
4103 if (hr == S_OK) {
4104 layout->measuringmode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
4106 /* set gdi-specific properties */
4107 layout->ppdip = ppdip;
4108 layout->transform = transform ? *transform : identity;
4110 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout2_iface;
4113 return hr;
4116 static HRESULT WINAPI dwritetrimmingsign_QueryInterface(IDWriteInlineObject *iface, REFIID riid, void **obj)
4118 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4120 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4122 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteInlineObject)) {
4123 *obj = iface;
4124 IDWriteInlineObject_AddRef(iface);
4125 return S_OK;
4128 *obj = NULL;
4129 return E_NOINTERFACE;
4132 static ULONG WINAPI dwritetrimmingsign_AddRef(IDWriteInlineObject *iface)
4134 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4135 ULONG ref = InterlockedIncrement(&This->ref);
4136 TRACE("(%p)->(%d)\n", This, ref);
4137 return ref;
4140 static ULONG WINAPI dwritetrimmingsign_Release(IDWriteInlineObject *iface)
4142 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4143 ULONG ref = InterlockedDecrement(&This->ref);
4145 TRACE("(%p)->(%d)\n", This, ref);
4147 if (!ref) {
4148 IDWriteTextLayout_Release(This->layout);
4149 heap_free(This);
4152 return ref;
4155 static HRESULT WINAPI dwritetrimmingsign_Draw(IDWriteInlineObject *iface, void *context, IDWriteTextRenderer *renderer,
4156 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *effect)
4158 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4159 DWRITE_TEXT_RANGE range = { 0, ~0u };
4161 TRACE("(%p)->(%p %p %.2f %.2f %d %d %p)\n", This, context, renderer, originX, originY, is_sideways, is_rtl, effect);
4163 IDWriteTextLayout_SetDrawingEffect(This->layout, effect, range);
4164 return IDWriteTextLayout_Draw(This->layout, context, renderer, originX, originY);
4167 static HRESULT WINAPI dwritetrimmingsign_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *ret)
4169 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4170 DWRITE_TEXT_METRICS metrics;
4171 HRESULT hr;
4173 TRACE("(%p)->(%p)\n", This, ret);
4175 hr = IDWriteTextLayout_GetMetrics(This->layout, &metrics);
4176 if (FAILED(hr)) {
4177 memset(ret, 0, sizeof(*ret));
4178 return hr;
4181 ret->width = metrics.width;
4182 ret->height = 0.0f;
4183 ret->baseline = 0.0f;
4184 ret->supportsSideways = FALSE;
4185 return S_OK;
4188 static HRESULT WINAPI dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
4190 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4191 FIXME("(%p)->(%p): stub\n", This, overhangs);
4192 return E_NOTIMPL;
4195 static HRESULT WINAPI dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
4196 DWRITE_BREAK_CONDITION *after)
4198 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4200 TRACE("(%p)->(%p %p)\n", This, before, after);
4202 *before = *after = DWRITE_BREAK_CONDITION_NEUTRAL;
4203 return S_OK;
4206 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl = {
4207 dwritetrimmingsign_QueryInterface,
4208 dwritetrimmingsign_AddRef,
4209 dwritetrimmingsign_Release,
4210 dwritetrimmingsign_Draw,
4211 dwritetrimmingsign_GetMetrics,
4212 dwritetrimmingsign_GetOverhangMetrics,
4213 dwritetrimmingsign_GetBreakConditions
4216 static inline BOOL is_reading_direction_horz(DWRITE_READING_DIRECTION direction)
4218 return (direction == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT) ||
4219 (direction == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
4222 static inline BOOL is_reading_direction_vert(DWRITE_READING_DIRECTION direction)
4224 return (direction == DWRITE_READING_DIRECTION_TOP_TO_BOTTOM) ||
4225 (direction == DWRITE_READING_DIRECTION_BOTTOM_TO_TOP);
4228 static inline BOOL is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction)
4230 return (direction == DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT) ||
4231 (direction == DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT);
4234 static inline BOOL is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction)
4236 return (direction == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM) ||
4237 (direction == DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP);
4240 HRESULT create_trimmingsign(IDWriteFactory2 *factory, IDWriteTextFormat *format, IDWriteInlineObject **sign)
4242 static const WCHAR ellipsisW = 0x2026;
4243 struct dwrite_trimmingsign *This;
4244 DWRITE_READING_DIRECTION reading;
4245 DWRITE_FLOW_DIRECTION flow;
4246 HRESULT hr;
4248 *sign = NULL;
4250 /* Validate reading/flow direction here, layout creation won't complain about
4251 invalid combinations. */
4252 reading = IDWriteTextFormat_GetReadingDirection(format);
4253 flow = IDWriteTextFormat_GetFlowDirection(format);
4255 if ((is_reading_direction_horz(reading) && is_flow_direction_horz(flow)) ||
4256 (is_reading_direction_vert(reading) && is_flow_direction_vert(flow)))
4257 return DWRITE_E_FLOWDIRECTIONCONFLICTS;
4259 This = heap_alloc(sizeof(*This));
4260 if (!This)
4261 return E_OUTOFMEMORY;
4263 This->IDWriteInlineObject_iface.lpVtbl = &dwritetrimmingsignvtbl;
4264 This->ref = 1;
4266 hr = IDWriteFactory2_CreateTextLayout(factory, &ellipsisW, 1, format, 0.0f, 0.0f, &This->layout);
4267 if (FAILED(hr)) {
4268 heap_free(This);
4269 return hr;
4272 IDWriteTextLayout_SetWordWrapping(This->layout, DWRITE_WORD_WRAPPING_NO_WRAP);
4273 *sign = &This->IDWriteInlineObject_iface;
4275 return S_OK;
4278 static HRESULT WINAPI dwritetextformat_QueryInterface(IDWriteTextFormat1 *iface, REFIID riid, void **obj)
4280 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4282 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4284 if (IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
4285 IsEqualIID(riid, &IID_IDWriteTextFormat) ||
4286 IsEqualIID(riid, &IID_IUnknown))
4288 *obj = iface;
4289 IDWriteTextFormat1_AddRef(iface);
4290 return S_OK;
4293 *obj = NULL;
4295 return E_NOINTERFACE;
4298 static ULONG WINAPI dwritetextformat_AddRef(IDWriteTextFormat1 *iface)
4300 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4301 ULONG ref = InterlockedIncrement(&This->ref);
4302 TRACE("(%p)->(%d)\n", This, ref);
4303 return ref;
4306 static ULONG WINAPI dwritetextformat_Release(IDWriteTextFormat1 *iface)
4308 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4309 ULONG ref = InterlockedDecrement(&This->ref);
4311 TRACE("(%p)->(%d)\n", This, ref);
4313 if (!ref)
4315 release_format_data(&This->format);
4316 heap_free(This);
4319 return ref;
4322 static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
4324 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4325 TRACE("(%p)->(%d)\n", This, alignment);
4326 return format_set_textalignment(&This->format, alignment, NULL);
4329 static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
4331 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4332 TRACE("(%p)->(%d)\n", This, alignment);
4333 return format_set_paralignment(&This->format, alignment, NULL);
4336 static HRESULT WINAPI dwritetextformat_SetWordWrapping(IDWriteTextFormat1 *iface, DWRITE_WORD_WRAPPING wrapping)
4338 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4339 TRACE("(%p)->(%d)\n", This, wrapping);
4340 return format_set_wordwrapping(&This->format, wrapping, NULL);
4343 static HRESULT WINAPI dwritetextformat_SetReadingDirection(IDWriteTextFormat1 *iface, DWRITE_READING_DIRECTION direction)
4345 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4346 TRACE("(%p)->(%d)\n", This, direction);
4347 return format_set_readingdirection(&This->format, direction, NULL);
4350 static HRESULT WINAPI dwritetextformat_SetFlowDirection(IDWriteTextFormat1 *iface, DWRITE_FLOW_DIRECTION direction)
4352 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4354 TRACE("(%p)->(%d)\n", This, direction);
4356 if ((UINT32)direction > DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT)
4357 return E_INVALIDARG;
4359 This->format.flow = direction;
4360 return S_OK;
4363 static HRESULT WINAPI dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat1 *iface, FLOAT tabstop)
4365 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4366 FIXME("(%p)->(%f): stub\n", This, tabstop);
4367 return E_NOTIMPL;
4370 static HRESULT WINAPI dwritetextformat_SetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING const *trimming,
4371 IDWriteInlineObject *trimming_sign)
4373 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4374 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
4376 This->format.trimming = *trimming;
4377 if (This->format.trimmingsign)
4378 IDWriteInlineObject_Release(This->format.trimmingsign);
4379 This->format.trimmingsign = trimming_sign;
4380 if (This->format.trimmingsign)
4381 IDWriteInlineObject_AddRef(This->format.trimmingsign);
4382 return S_OK;
4385 static HRESULT WINAPI dwritetextformat_SetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD method,
4386 FLOAT spacing, FLOAT baseline)
4388 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4390 TRACE("(%p)->(%d %f %f)\n", This, method, spacing, baseline);
4392 if (spacing < 0.0f || (UINT32)method > DWRITE_LINE_SPACING_METHOD_UNIFORM)
4393 return E_INVALIDARG;
4395 This->format.spacingmethod = method;
4396 This->format.spacing = spacing;
4397 This->format.baseline = baseline;
4398 return S_OK;
4401 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_GetTextAlignment(IDWriteTextFormat1 *iface)
4403 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4404 TRACE("(%p)\n", This);
4405 return This->format.textalignment;
4408 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_GetParagraphAlignment(IDWriteTextFormat1 *iface)
4410 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4411 TRACE("(%p)\n", This);
4412 return This->format.paralign;
4415 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_GetWordWrapping(IDWriteTextFormat1 *iface)
4417 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4418 TRACE("(%p)\n", This);
4419 return This->format.wrapping;
4422 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_GetReadingDirection(IDWriteTextFormat1 *iface)
4424 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4425 TRACE("(%p)\n", This);
4426 return This->format.readingdir;
4429 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_GetFlowDirection(IDWriteTextFormat1 *iface)
4431 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4432 TRACE("(%p)\n", This);
4433 return This->format.flow;
4436 static FLOAT WINAPI dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat1 *iface)
4438 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4439 FIXME("(%p): stub\n", This);
4440 return 0.0f;
4443 static HRESULT WINAPI dwritetextformat_GetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING *options,
4444 IDWriteInlineObject **trimming_sign)
4446 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4447 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
4449 *options = This->format.trimming;
4450 if ((*trimming_sign = This->format.trimmingsign))
4451 IDWriteInlineObject_AddRef(*trimming_sign);
4453 return S_OK;
4456 static HRESULT WINAPI dwritetextformat_GetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD *method,
4457 FLOAT *spacing, FLOAT *baseline)
4459 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4460 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
4462 *method = This->format.spacingmethod;
4463 *spacing = This->format.spacing;
4464 *baseline = This->format.baseline;
4465 return S_OK;
4468 static HRESULT WINAPI dwritetextformat_GetFontCollection(IDWriteTextFormat1 *iface, IDWriteFontCollection **collection)
4470 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4472 TRACE("(%p)->(%p)\n", This, collection);
4474 *collection = This->format.collection;
4475 IDWriteFontCollection_AddRef(*collection);
4477 return S_OK;
4480 static UINT32 WINAPI dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat1 *iface)
4482 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4483 TRACE("(%p)\n", This);
4484 return This->format.family_len;
4487 static HRESULT WINAPI dwritetextformat_GetFontFamilyName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
4489 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4491 TRACE("(%p)->(%p %u)\n", This, name, size);
4493 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
4494 strcpyW(name, This->format.family_name);
4495 return S_OK;
4498 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_GetFontWeight(IDWriteTextFormat1 *iface)
4500 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4501 TRACE("(%p)\n", This);
4502 return This->format.weight;
4505 static DWRITE_FONT_STYLE WINAPI dwritetextformat_GetFontStyle(IDWriteTextFormat1 *iface)
4507 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4508 TRACE("(%p)\n", This);
4509 return This->format.style;
4512 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_GetFontStretch(IDWriteTextFormat1 *iface)
4514 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4515 TRACE("(%p)\n", This);
4516 return This->format.stretch;
4519 static FLOAT WINAPI dwritetextformat_GetFontSize(IDWriteTextFormat1 *iface)
4521 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4522 TRACE("(%p)\n", This);
4523 return This->format.fontsize;
4526 static UINT32 WINAPI dwritetextformat_GetLocaleNameLength(IDWriteTextFormat1 *iface)
4528 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4529 TRACE("(%p)\n", This);
4530 return This->format.locale_len;
4533 static HRESULT WINAPI dwritetextformat_GetLocaleName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
4535 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4537 TRACE("(%p)->(%p %u)\n", This, name, size);
4539 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
4540 strcpyW(name, This->format.locale);
4541 return S_OK;
4544 static HRESULT WINAPI dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat1 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4546 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4548 TRACE("(%p)->(%d)\n", This, orientation);
4550 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
4551 return E_INVALIDARG;
4553 This->format.vertical_orientation = orientation;
4554 return S_OK;
4557 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat1 *iface)
4559 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4560 TRACE("(%p)\n", This);
4561 return This->format.vertical_orientation;
4564 static HRESULT WINAPI dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat1 *iface, BOOL lastline_wrapping_enabled)
4566 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4568 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
4570 This->format.last_line_wrapping = !!lastline_wrapping_enabled;
4571 return S_OK;
4574 static BOOL WINAPI dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat1 *iface)
4576 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4577 TRACE("(%p)\n", This);
4578 return This->format.last_line_wrapping;
4581 static HRESULT WINAPI dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat1 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
4583 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4584 TRACE("(%p)->(%d)\n", This, alignment);
4585 return format_set_optical_alignment(&This->format, alignment);
4588 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat1 *iface)
4590 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4591 TRACE("(%p)\n", This);
4592 return This->format.optical_alignment;
4595 static HRESULT WINAPI dwritetextformat1_SetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback *fallback)
4597 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4598 TRACE("(%p)->(%p)\n", This, fallback);
4599 return set_fontfallback_for_format(&This->format, fallback);
4602 static HRESULT WINAPI dwritetextformat1_GetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback **fallback)
4604 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4605 TRACE("(%p)->(%p)\n", This, fallback);
4606 return get_fontfallback_from_format(&This->format, fallback);
4609 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl = {
4610 dwritetextformat_QueryInterface,
4611 dwritetextformat_AddRef,
4612 dwritetextformat_Release,
4613 dwritetextformat_SetTextAlignment,
4614 dwritetextformat_SetParagraphAlignment,
4615 dwritetextformat_SetWordWrapping,
4616 dwritetextformat_SetReadingDirection,
4617 dwritetextformat_SetFlowDirection,
4618 dwritetextformat_SetIncrementalTabStop,
4619 dwritetextformat_SetTrimming,
4620 dwritetextformat_SetLineSpacing,
4621 dwritetextformat_GetTextAlignment,
4622 dwritetextformat_GetParagraphAlignment,
4623 dwritetextformat_GetWordWrapping,
4624 dwritetextformat_GetReadingDirection,
4625 dwritetextformat_GetFlowDirection,
4626 dwritetextformat_GetIncrementalTabStop,
4627 dwritetextformat_GetTrimming,
4628 dwritetextformat_GetLineSpacing,
4629 dwritetextformat_GetFontCollection,
4630 dwritetextformat_GetFontFamilyNameLength,
4631 dwritetextformat_GetFontFamilyName,
4632 dwritetextformat_GetFontWeight,
4633 dwritetextformat_GetFontStyle,
4634 dwritetextformat_GetFontStretch,
4635 dwritetextformat_GetFontSize,
4636 dwritetextformat_GetLocaleNameLength,
4637 dwritetextformat_GetLocaleName,
4638 dwritetextformat1_SetVerticalGlyphOrientation,
4639 dwritetextformat1_GetVerticalGlyphOrientation,
4640 dwritetextformat1_SetLastLineWrapping,
4641 dwritetextformat1_GetLastLineWrapping,
4642 dwritetextformat1_SetOpticalAlignment,
4643 dwritetextformat1_GetOpticalAlignment,
4644 dwritetextformat1_SetFontFallback,
4645 dwritetextformat1_GetFontFallback
4648 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat *iface)
4650 return (iface->lpVtbl == (IDWriteTextFormatVtbl*)&dwritetextformatvtbl) ?
4651 CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat1_iface) : NULL;
4654 HRESULT create_textformat(const WCHAR *family_name, IDWriteFontCollection *collection, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style,
4655 DWRITE_FONT_STRETCH stretch, FLOAT size, const WCHAR *locale, IDWriteTextFormat **format)
4657 struct dwrite_textformat *This;
4659 *format = NULL;
4661 This = heap_alloc(sizeof(struct dwrite_textformat));
4662 if (!This) return E_OUTOFMEMORY;
4664 This->IDWriteTextFormat1_iface.lpVtbl = &dwritetextformatvtbl;
4665 This->ref = 1;
4666 This->format.family_name = heap_strdupW(family_name);
4667 This->format.family_len = strlenW(family_name);
4668 This->format.locale = heap_strdupW(locale);
4669 This->format.locale_len = strlenW(locale);
4670 /* force locale name to lower case, layout will inherit this modified value */
4671 strlwrW(This->format.locale);
4672 This->format.weight = weight;
4673 This->format.style = style;
4674 This->format.fontsize = size;
4675 This->format.stretch = stretch;
4676 This->format.textalignment = DWRITE_TEXT_ALIGNMENT_LEADING;
4677 This->format.optical_alignment = DWRITE_OPTICAL_ALIGNMENT_NONE;
4678 This->format.paralign = DWRITE_PARAGRAPH_ALIGNMENT_NEAR;
4679 This->format.wrapping = DWRITE_WORD_WRAPPING_WRAP;
4680 This->format.last_line_wrapping = TRUE;
4681 This->format.readingdir = DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
4682 This->format.flow = DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM;
4683 This->format.spacingmethod = DWRITE_LINE_SPACING_METHOD_DEFAULT;
4684 This->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
4685 This->format.spacing = 0.0f;
4686 This->format.baseline = 0.0f;
4687 This->format.trimming.granularity = DWRITE_TRIMMING_GRANULARITY_NONE;
4688 This->format.trimming.delimiter = 0;
4689 This->format.trimming.delimiterCount = 0;
4690 This->format.trimmingsign = NULL;
4691 This->format.collection = collection;
4692 This->format.fallback = NULL;
4693 IDWriteFontCollection_AddRef(collection);
4695 *format = (IDWriteTextFormat*)&This->IDWriteTextFormat1_iface;
4697 return S_OK;
4700 static HRESULT WINAPI dwritetypography_QueryInterface(IDWriteTypography *iface, REFIID riid, void **obj)
4702 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4704 TRACE("(%p)->(%s %p)\n", typography, debugstr_guid(riid), obj);
4706 if (IsEqualIID(riid, &IID_IDWriteTypography) || IsEqualIID(riid, &IID_IUnknown)) {
4707 *obj = iface;
4708 IDWriteTypography_AddRef(iface);
4709 return S_OK;
4712 *obj = NULL;
4714 return E_NOINTERFACE;
4717 static ULONG WINAPI dwritetypography_AddRef(IDWriteTypography *iface)
4719 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4720 ULONG ref = InterlockedIncrement(&typography->ref);
4721 TRACE("(%p)->(%d)\n", typography, ref);
4722 return ref;
4725 static ULONG WINAPI dwritetypography_Release(IDWriteTypography *iface)
4727 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4728 ULONG ref = InterlockedDecrement(&typography->ref);
4730 TRACE("(%p)->(%d)\n", typography, ref);
4732 if (!ref) {
4733 heap_free(typography->features);
4734 heap_free(typography);
4737 return ref;
4740 static HRESULT WINAPI dwritetypography_AddFontFeature(IDWriteTypography *iface, DWRITE_FONT_FEATURE feature)
4742 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4744 TRACE("(%p)->(%x %u)\n", typography, feature.nameTag, feature.parameter);
4746 if (typography->count == typography->allocated) {
4747 DWRITE_FONT_FEATURE *ptr = heap_realloc(typography->features, 2*typography->allocated*sizeof(DWRITE_FONT_FEATURE));
4748 if (!ptr)
4749 return E_OUTOFMEMORY;
4751 typography->features = ptr;
4752 typography->allocated *= 2;
4755 typography->features[typography->count++] = feature;
4756 return S_OK;
4759 static UINT32 WINAPI dwritetypography_GetFontFeatureCount(IDWriteTypography *iface)
4761 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4762 TRACE("(%p)\n", typography);
4763 return typography->count;
4766 static HRESULT WINAPI dwritetypography_GetFontFeature(IDWriteTypography *iface, UINT32 index, DWRITE_FONT_FEATURE *feature)
4768 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4770 TRACE("(%p)->(%u %p)\n", typography, index, feature);
4772 if (index >= typography->count)
4773 return E_INVALIDARG;
4775 *feature = typography->features[index];
4776 return S_OK;
4779 static const IDWriteTypographyVtbl dwritetypographyvtbl = {
4780 dwritetypography_QueryInterface,
4781 dwritetypography_AddRef,
4782 dwritetypography_Release,
4783 dwritetypography_AddFontFeature,
4784 dwritetypography_GetFontFeatureCount,
4785 dwritetypography_GetFontFeature
4788 HRESULT create_typography(IDWriteTypography **ret)
4790 struct dwrite_typography *typography;
4792 *ret = NULL;
4794 typography = heap_alloc(sizeof(*typography));
4795 if (!typography)
4796 return E_OUTOFMEMORY;
4798 typography->IDWriteTypography_iface.lpVtbl = &dwritetypographyvtbl;
4799 typography->ref = 1;
4800 typography->allocated = 2;
4801 typography->count = 0;
4803 typography->features = heap_alloc(typography->allocated*sizeof(DWRITE_FONT_FEATURE));
4804 if (!typography->features) {
4805 heap_free(typography);
4806 return E_OUTOFMEMORY;
4809 *ret = &typography->IDWriteTypography_iface;
4810 return S_OK;