winebuild: Use strarray objects instead of pointers where possible.
[wine.git] / dlls / dwrite / layout.c
blob38b5e32de5769a65a6de10629f194d2a5b34353a
1 /*
2 * Text format and layout
4 * Copyright 2012, 2014-2016 Nikolay Sivov for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include <stdarg.h>
24 #include <math.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "dwrite_private.h"
30 #include "scripts.h"
31 #include "wine/list.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
35 struct dwrite_textformat_data {
36 WCHAR *family_name;
37 UINT32 family_len;
38 WCHAR *locale;
39 UINT32 locale_len;
41 DWRITE_FONT_WEIGHT weight;
42 DWRITE_FONT_STYLE style;
43 DWRITE_FONT_STRETCH stretch;
45 DWRITE_PARAGRAPH_ALIGNMENT paralign;
46 DWRITE_READING_DIRECTION readingdir;
47 DWRITE_WORD_WRAPPING wrapping;
48 BOOL last_line_wrapping;
49 DWRITE_TEXT_ALIGNMENT textalignment;
50 DWRITE_FLOW_DIRECTION flow;
51 DWRITE_LINE_SPACING_METHOD spacingmethod;
52 DWRITE_VERTICAL_GLYPH_ORIENTATION vertical_orientation;
53 DWRITE_OPTICAL_ALIGNMENT optical_alignment;
55 FLOAT spacing;
56 FLOAT baseline;
57 FLOAT fontsize;
59 DWRITE_TRIMMING trimming;
60 IDWriteInlineObject *trimmingsign;
62 IDWriteFontCollection *collection;
63 IDWriteFontFallback *fallback;
66 enum layout_range_attr_kind {
67 LAYOUT_RANGE_ATTR_WEIGHT,
68 LAYOUT_RANGE_ATTR_STYLE,
69 LAYOUT_RANGE_ATTR_STRETCH,
70 LAYOUT_RANGE_ATTR_FONTSIZE,
71 LAYOUT_RANGE_ATTR_EFFECT,
72 LAYOUT_RANGE_ATTR_INLINE,
73 LAYOUT_RANGE_ATTR_UNDERLINE,
74 LAYOUT_RANGE_ATTR_STRIKETHROUGH,
75 LAYOUT_RANGE_ATTR_PAIR_KERNING,
76 LAYOUT_RANGE_ATTR_FONTCOLL,
77 LAYOUT_RANGE_ATTR_LOCALE,
78 LAYOUT_RANGE_ATTR_FONTFAMILY,
79 LAYOUT_RANGE_ATTR_SPACING,
80 LAYOUT_RANGE_ATTR_TYPOGRAPHY
83 struct layout_range_attr_value {
84 DWRITE_TEXT_RANGE range;
85 union {
86 DWRITE_FONT_WEIGHT weight;
87 DWRITE_FONT_STYLE style;
88 DWRITE_FONT_STRETCH stretch;
89 FLOAT fontsize;
90 IDWriteInlineObject *object;
91 IUnknown *effect;
92 BOOL underline;
93 BOOL strikethrough;
94 BOOL pair_kerning;
95 IDWriteFontCollection *collection;
96 const WCHAR *locale;
97 const WCHAR *fontfamily;
98 FLOAT spacing[3]; /* in arguments order - leading, trailing, advance */
99 IDWriteTypography *typography;
100 } u;
103 enum layout_range_kind {
104 LAYOUT_RANGE_REGULAR,
105 LAYOUT_RANGE_UNDERLINE,
106 LAYOUT_RANGE_STRIKETHROUGH,
107 LAYOUT_RANGE_EFFECT,
108 LAYOUT_RANGE_SPACING,
109 LAYOUT_RANGE_TYPOGRAPHY
112 struct layout_range_header {
113 struct list entry;
114 enum layout_range_kind kind;
115 DWRITE_TEXT_RANGE range;
118 struct layout_range {
119 struct layout_range_header h;
120 DWRITE_FONT_WEIGHT weight;
121 DWRITE_FONT_STYLE style;
122 FLOAT fontsize;
123 DWRITE_FONT_STRETCH stretch;
124 IDWriteInlineObject *object;
125 BOOL pair_kerning;
126 IDWriteFontCollection *collection;
127 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
128 WCHAR *fontfamily;
131 struct layout_range_bool {
132 struct layout_range_header h;
133 BOOL value;
136 struct layout_range_iface {
137 struct layout_range_header h;
138 IUnknown *iface;
141 struct layout_range_spacing {
142 struct layout_range_header h;
143 FLOAT leading;
144 FLOAT trailing;
145 FLOAT min_advance;
148 enum layout_run_kind {
149 LAYOUT_RUN_REGULAR,
150 LAYOUT_RUN_INLINE
153 struct inline_object_run {
154 IDWriteInlineObject *object;
155 UINT16 length;
158 struct regular_layout_run {
159 DWRITE_GLYPH_RUN_DESCRIPTION descr;
160 DWRITE_GLYPH_RUN run;
161 DWRITE_SCRIPT_ANALYSIS sa;
162 UINT16 *glyphs;
163 UINT16 *clustermap;
164 FLOAT *advances;
165 DWRITE_GLYPH_OFFSET *offsets;
166 /* this is actual glyph count after shaping, it's not necessary the same as reported to Draw() */
167 UINT32 glyphcount;
170 struct layout_run {
171 struct list entry;
172 enum layout_run_kind kind;
173 union {
174 struct inline_object_run object;
175 struct regular_layout_run regular;
176 } u;
177 FLOAT baseline;
178 FLOAT height;
181 struct layout_effective_run {
182 struct list entry;
183 const struct layout_run *run; /* nominal run this one is based on */
184 UINT32 start; /* relative text position, 0 means first text position of a nominal run */
185 UINT32 length; /* length in codepoints that this run covers */
186 UINT32 glyphcount; /* total glyph count in this run */
187 IUnknown *effect; /* original reference is kept only at range level */
188 FLOAT origin_x; /* baseline X position */
189 FLOAT origin_y; /* baseline Y position */
190 FLOAT align_dx; /* adjustment from text alignment */
191 FLOAT width; /* run width */
192 UINT16 *clustermap; /* effective clustermap, allocated separately, is not reused from nominal map */
193 UINT32 line; /* 0-based line index in line metrics array */
194 BOOL underlined; /* set if this run is underlined */
197 struct layout_effective_inline {
198 struct list entry;
199 const struct layout_run *run; /* nominal run this one is based on */
200 IUnknown *effect; /* original reference is kept only at range level */
201 FLOAT origin_x; /* left X position */
202 FLOAT origin_y; /* left top corner Y position */
203 FLOAT align_dx; /* adjustment from text alignment */
204 FLOAT width; /* object width as it's reported it */
205 BOOL is_sideways; /* vertical flow direction flag passed to Draw */
206 BOOL is_rtl; /* bidi flag passed to Draw */
207 UINT32 line; /* 0-based line index in line metrics array */
210 struct layout_underline {
211 struct list entry;
212 const struct layout_effective_run *run;
213 DWRITE_UNDERLINE u;
216 struct layout_strikethrough {
217 struct list entry;
218 const struct layout_effective_run *run;
219 DWRITE_STRIKETHROUGH s;
222 struct layout_cluster {
223 const struct layout_run *run; /* link to nominal run this cluster belongs to */
224 UINT32 position; /* relative to run, first cluster has 0 position */
227 enum layout_recompute_mask {
228 RECOMPUTE_NOMINAL_RUNS = 1 << 0,
229 RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
230 RECOMPUTE_EFFECTIVE_RUNS = 1 << 2,
231 RECOMPUTE_EVERYTHING = 0xffff
234 struct dwrite_textlayout {
235 IDWriteTextLayout3 IDWriteTextLayout3_iface;
236 IDWriteTextFormat1 IDWriteTextFormat1_iface;
237 IDWriteTextAnalysisSink1 IDWriteTextAnalysisSink1_iface;
238 IDWriteTextAnalysisSource1 IDWriteTextAnalysisSource1_iface;
239 LONG ref;
241 IDWriteFactory2 *factory;
243 WCHAR *str;
244 UINT32 len;
245 struct dwrite_textformat_data format;
246 struct list strike_ranges;
247 struct list underline_ranges;
248 struct list typographies;
249 struct list effects;
250 struct list spacing;
251 struct list ranges;
252 struct list runs;
253 /* lists ready to use by Draw() */
254 struct list eruns;
255 struct list inlineobjects;
256 struct list underlines;
257 struct list strikethrough;
258 USHORT recompute;
260 DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
261 DWRITE_LINE_BREAKPOINT *actual_breakpoints;
263 struct layout_cluster *clusters;
264 DWRITE_CLUSTER_METRICS *clustermetrics;
265 UINT32 cluster_count;
266 FLOAT minwidth;
268 DWRITE_LINE_METRICS *lines;
269 UINT32 line_alloc;
271 DWRITE_TEXT_METRICS1 metrics;
273 DWRITE_MEASURING_MODE measuringmode;
275 /* gdi-compatible layout specifics */
276 FLOAT ppdip;
277 DWRITE_MATRIX transform;
280 struct dwrite_textformat {
281 IDWriteTextFormat2 IDWriteTextFormat2_iface;
282 LONG ref;
283 struct dwrite_textformat_data format;
286 struct dwrite_trimmingsign {
287 IDWriteInlineObject IDWriteInlineObject_iface;
288 LONG ref;
290 IDWriteTextLayout *layout;
293 struct dwrite_typography {
294 IDWriteTypography IDWriteTypography_iface;
295 LONG ref;
297 DWRITE_FONT_FEATURE *features;
298 UINT32 allocated;
299 UINT32 count;
302 struct dwrite_vec {
303 FLOAT x;
304 FLOAT y;
307 static const IDWriteTextFormat2Vtbl dwritetextformatvtbl;
309 static void release_format_data(struct dwrite_textformat_data *data)
311 if (data->collection) IDWriteFontCollection_Release(data->collection);
312 if (data->fallback) IDWriteFontFallback_Release(data->fallback);
313 if (data->trimmingsign) IDWriteInlineObject_Release(data->trimmingsign);
314 heap_free(data->family_name);
315 heap_free(data->locale);
318 static inline struct dwrite_textlayout *impl_from_IDWriteTextLayout3(IDWriteTextLayout3 *iface)
320 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextLayout3_iface);
323 static inline struct dwrite_textlayout *impl_layout_from_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
325 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextFormat1_iface);
328 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSink1(IDWriteTextAnalysisSink1 *iface)
330 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSink1_iface);
333 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSource1(IDWriteTextAnalysisSource1 *iface)
335 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSource1_iface);
338 static inline struct dwrite_textformat *impl_from_IDWriteTextFormat2(IDWriteTextFormat2 *iface)
340 return CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat2_iface);
343 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat*);
345 static inline struct dwrite_trimmingsign *impl_from_IDWriteInlineObject(IDWriteInlineObject *iface)
347 return CONTAINING_RECORD(iface, struct dwrite_trimmingsign, IDWriteInlineObject_iface);
350 static inline struct dwrite_typography *impl_from_IDWriteTypography(IDWriteTypography *iface)
352 return CONTAINING_RECORD(iface, struct dwrite_typography, IDWriteTypography_iface);
355 static inline const char *debugstr_rundescr(const DWRITE_GLYPH_RUN_DESCRIPTION *descr)
357 return wine_dbg_sprintf("[%u,%u)", descr->textPosition, descr->textPosition + descr->stringLength);
360 static inline BOOL is_layout_gdi_compatible(struct dwrite_textlayout *layout)
362 return layout->measuringmode != DWRITE_MEASURING_MODE_NATURAL;
365 static inline HRESULT format_set_textalignment(struct dwrite_textformat_data *format, DWRITE_TEXT_ALIGNMENT alignment,
366 BOOL *changed)
368 if ((UINT32)alignment > DWRITE_TEXT_ALIGNMENT_JUSTIFIED)
369 return E_INVALIDARG;
370 if (changed) *changed = format->textalignment != alignment;
371 format->textalignment = alignment;
372 return S_OK;
375 static inline HRESULT format_set_paralignment(struct dwrite_textformat_data *format,
376 DWRITE_PARAGRAPH_ALIGNMENT alignment, BOOL *changed)
378 if ((UINT32)alignment > DWRITE_PARAGRAPH_ALIGNMENT_CENTER)
379 return E_INVALIDARG;
380 if (changed) *changed = format->paralign != alignment;
381 format->paralign = alignment;
382 return S_OK;
385 static inline HRESULT format_set_readingdirection(struct dwrite_textformat_data *format,
386 DWRITE_READING_DIRECTION direction, BOOL *changed)
388 if ((UINT32)direction > DWRITE_READING_DIRECTION_BOTTOM_TO_TOP)
389 return E_INVALIDARG;
390 if (changed) *changed = format->readingdir != direction;
391 format->readingdir = direction;
392 return S_OK;
395 static inline HRESULT format_set_wordwrapping(struct dwrite_textformat_data *format,
396 DWRITE_WORD_WRAPPING wrapping, BOOL *changed)
398 if ((UINT32)wrapping > DWRITE_WORD_WRAPPING_CHARACTER)
399 return E_INVALIDARG;
400 if (changed) *changed = format->wrapping != wrapping;
401 format->wrapping = wrapping;
402 return S_OK;
405 static inline HRESULT format_set_flowdirection(struct dwrite_textformat_data *format,
406 DWRITE_FLOW_DIRECTION direction, BOOL *changed)
408 if ((UINT32)direction > DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT)
409 return E_INVALIDARG;
410 if (changed) *changed = format->flow != direction;
411 format->flow = direction;
412 return S_OK;
415 static inline HRESULT format_set_linespacing(struct dwrite_textformat_data *format,
416 DWRITE_LINE_SPACING_METHOD method, FLOAT spacing, FLOAT baseline, BOOL *changed)
418 if (spacing < 0.0f || (UINT32)method > DWRITE_LINE_SPACING_METHOD_UNIFORM)
419 return E_INVALIDARG;
421 if (changed) *changed = format->spacingmethod != method ||
422 format->spacing != spacing || format->baseline != baseline;
424 format->spacingmethod = method;
425 format->spacing = spacing;
426 format->baseline = baseline;
427 return S_OK;
430 static HRESULT get_fontfallback_from_format(const struct dwrite_textformat_data *format, IDWriteFontFallback **fallback)
432 *fallback = format->fallback;
433 if (*fallback)
434 IDWriteFontFallback_AddRef(*fallback);
435 return S_OK;
438 static HRESULT set_fontfallback_for_format(struct dwrite_textformat_data *format, IDWriteFontFallback *fallback)
440 if (format->fallback)
441 IDWriteFontFallback_Release(format->fallback);
442 format->fallback = fallback;
443 if (fallback)
444 IDWriteFontFallback_AddRef(fallback);
445 return S_OK;
448 static HRESULT format_set_optical_alignment(struct dwrite_textformat_data *format,
449 DWRITE_OPTICAL_ALIGNMENT alignment)
451 if ((UINT32)alignment > DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS)
452 return E_INVALIDARG;
453 format->optical_alignment = alignment;
454 return S_OK;
457 static BOOL is_run_rtl(const struct layout_effective_run *run)
459 return run->run->u.regular.run.bidiLevel & 1;
462 static struct layout_run *alloc_layout_run(enum layout_run_kind kind)
464 struct layout_run *ret;
466 ret = heap_alloc(sizeof(*ret));
467 if (!ret) return NULL;
469 memset(ret, 0, sizeof(*ret));
470 ret->kind = kind;
471 if (kind == LAYOUT_RUN_REGULAR) {
472 ret->u.regular.sa.script = Script_Unknown;
473 ret->u.regular.sa.shapes = DWRITE_SCRIPT_SHAPES_DEFAULT;
476 return ret;
479 static void free_layout_runs(struct dwrite_textlayout *layout)
481 struct layout_run *cur, *cur2;
482 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->runs, struct layout_run, entry) {
483 list_remove(&cur->entry);
484 if (cur->kind == LAYOUT_RUN_REGULAR) {
485 if (cur->u.regular.run.fontFace)
486 IDWriteFontFace_Release(cur->u.regular.run.fontFace);
487 heap_free(cur->u.regular.glyphs);
488 heap_free(cur->u.regular.clustermap);
489 heap_free(cur->u.regular.advances);
490 heap_free(cur->u.regular.offsets);
492 heap_free(cur);
496 static void free_layout_eruns(struct dwrite_textlayout *layout)
498 struct layout_effective_inline *in, *in2;
499 struct layout_effective_run *cur, *cur2;
500 struct layout_strikethrough *s, *s2;
501 struct layout_underline *u, *u2;
503 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->eruns, struct layout_effective_run, entry) {
504 list_remove(&cur->entry);
505 heap_free(cur->clustermap);
506 heap_free(cur);
509 LIST_FOR_EACH_ENTRY_SAFE(in, in2, &layout->inlineobjects, struct layout_effective_inline, entry) {
510 list_remove(&in->entry);
511 heap_free(in);
514 LIST_FOR_EACH_ENTRY_SAFE(u, u2, &layout->underlines, struct layout_underline, entry) {
515 list_remove(&u->entry);
516 heap_free(u);
519 LIST_FOR_EACH_ENTRY_SAFE(s, s2, &layout->strikethrough, struct layout_strikethrough, entry) {
520 list_remove(&s->entry);
521 heap_free(s);
525 /* Used to resolve break condition by forcing stronger condition over weaker. */
526 static inline DWRITE_BREAK_CONDITION override_break_condition(DWRITE_BREAK_CONDITION existingbreak, DWRITE_BREAK_CONDITION newbreak)
528 switch (existingbreak) {
529 case DWRITE_BREAK_CONDITION_NEUTRAL:
530 return newbreak;
531 case DWRITE_BREAK_CONDITION_CAN_BREAK:
532 return newbreak == DWRITE_BREAK_CONDITION_NEUTRAL ? existingbreak : newbreak;
533 /* let's keep stronger conditions as is */
534 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK:
535 case DWRITE_BREAK_CONDITION_MUST_BREAK:
536 break;
537 default:
538 ERR("unknown break condition %d\n", existingbreak);
541 return existingbreak;
544 /* This helper should be used to get effective range length, in other words it returns number of text
545 positions from range starting point to the end of the range, limited by layout text length */
546 static inline UINT32 get_clipped_range_length(const struct dwrite_textlayout *layout, const struct layout_range *range)
548 if (range->h.range.startPosition + range->h.range.length <= layout->len)
549 return range->h.range.length;
550 return layout->len - range->h.range.startPosition;
553 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
554 static HRESULT layout_update_breakpoints_range(struct dwrite_textlayout *layout, const struct layout_range *cur)
556 DWRITE_BREAK_CONDITION before, after;
557 UINT32 i, length;
558 HRESULT hr;
560 /* ignore returned conditions if failed */
561 hr = IDWriteInlineObject_GetBreakConditions(cur->object, &before, &after);
562 if (FAILED(hr))
563 after = before = DWRITE_BREAK_CONDITION_NEUTRAL;
565 if (!layout->actual_breakpoints) {
566 layout->actual_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
567 if (!layout->actual_breakpoints)
568 return E_OUTOFMEMORY;
569 memcpy(layout->actual_breakpoints, layout->nominal_breakpoints, sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
572 length = get_clipped_range_length(layout, cur);
573 for (i = cur->h.range.startPosition; i < length + cur->h.range.startPosition; i++) {
574 /* for first codepoint check if there's anything before it and update accordingly */
575 if (i == cur->h.range.startPosition) {
576 if (i > 0)
577 layout->actual_breakpoints[i].breakConditionBefore = layout->actual_breakpoints[i-1].breakConditionAfter =
578 override_break_condition(layout->actual_breakpoints[i-1].breakConditionAfter, before);
579 else
580 layout->actual_breakpoints[i].breakConditionBefore = before;
581 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
583 /* similar check for last codepoint */
584 else if (i == cur->h.range.startPosition + length - 1) {
585 if (i == layout->len - 1)
586 layout->actual_breakpoints[i].breakConditionAfter = after;
587 else
588 layout->actual_breakpoints[i].breakConditionAfter = layout->actual_breakpoints[i+1].breakConditionBefore =
589 override_break_condition(layout->actual_breakpoints[i+1].breakConditionBefore, after);
590 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
592 /* for all positions within a range disable breaks */
593 else {
594 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
595 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
598 layout->actual_breakpoints[i].isWhitespace = 0;
599 layout->actual_breakpoints[i].isSoftHyphen = 0;
602 return S_OK;
605 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos);
607 static inline DWRITE_LINE_BREAKPOINT get_effective_breakpoint(const struct dwrite_textlayout *layout, UINT32 pos)
609 if (layout->actual_breakpoints)
610 return layout->actual_breakpoints[pos];
611 return layout->nominal_breakpoints[pos];
614 static inline void init_cluster_metrics(const struct dwrite_textlayout *layout, const struct regular_layout_run *run,
615 UINT16 start_glyph, UINT16 stop_glyph, UINT32 stop_position, UINT16 length, DWRITE_CLUSTER_METRICS *metrics)
617 UINT8 breakcondition;
618 UINT32 position;
619 UINT16 j;
621 /* For clusters made of control chars we report zero glyphs, and we need zero cluster
622 width as well; advances are already computed at this point and are not necessary zero. */
623 metrics->width = 0.0f;
624 if (run->run.glyphCount) {
625 for (j = start_glyph; j < stop_glyph; j++)
626 metrics->width += run->run.glyphAdvances[j];
628 metrics->length = length;
630 position = run->descr.textPosition + stop_position;
631 if (stop_glyph == run->glyphcount)
632 breakcondition = get_effective_breakpoint(layout, position).breakConditionAfter;
633 else {
634 breakcondition = get_effective_breakpoint(layout, position).breakConditionBefore;
635 if (stop_position) position -= 1;
638 metrics->canWrapLineAfter = breakcondition == DWRITE_BREAK_CONDITION_CAN_BREAK ||
639 breakcondition == DWRITE_BREAK_CONDITION_MUST_BREAK;
640 if (metrics->length == 1) {
641 DWRITE_LINE_BREAKPOINT bp = get_effective_breakpoint(layout, position);
642 metrics->isWhitespace = bp.isWhitespace;
643 metrics->isNewline = metrics->canWrapLineAfter && lb_is_newline_char(layout->str[position]);
644 metrics->isSoftHyphen = bp.isSoftHyphen;
646 else {
647 metrics->isWhitespace = 0;
648 metrics->isNewline = 0;
649 metrics->isSoftHyphen = 0;
651 metrics->isRightToLeft = run->run.bidiLevel & 1;
652 metrics->padding = 0;
657 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
658 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
659 Note that there's no need to reallocate anything at this point as we allocate one cluster per
660 codepoint initially.
663 static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 *cluster)
665 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[*cluster];
666 struct layout_cluster *c = &layout->clusters[*cluster];
667 const struct regular_layout_run *run = &r->u.regular;
668 UINT32 i, start = 0;
670 for (i = 0; i < run->descr.stringLength; i++) {
671 BOOL end = i == run->descr.stringLength - 1;
673 if (run->descr.clusterMap[start] != run->descr.clusterMap[i]) {
674 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->descr.clusterMap[i], i,
675 i - start, metrics);
676 c->position = start;
677 c->run = r;
679 *cluster += 1;
680 metrics++;
681 c++;
682 start = i;
685 if (end) {
686 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->glyphcount, i,
687 i - start + 1, metrics);
688 c->position = start;
689 c->run = r;
691 *cluster += 1;
692 return;
697 #define SCALE_FONT_METRIC(metric, emSize, metrics) ((FLOAT)(metric) * (emSize) / (FLOAT)(metrics)->designUnitsPerEm)
699 static void layout_get_font_metrics(struct dwrite_textlayout *layout, IDWriteFontFace *fontface, FLOAT emsize,
700 DWRITE_FONT_METRICS *fontmetrics)
702 if (is_layout_gdi_compatible(layout)) {
703 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(fontface, emsize, layout->ppdip, &layout->transform, fontmetrics);
704 if (FAILED(hr))
705 WARN("failed to get compat metrics, 0x%08x\n", hr);
707 else
708 IDWriteFontFace_GetMetrics(fontface, fontmetrics);
711 static void layout_get_font_height(FLOAT emsize, DWRITE_FONT_METRICS *fontmetrics, FLOAT *baseline, FLOAT *height)
713 *baseline = SCALE_FONT_METRIC(fontmetrics->ascent + fontmetrics->lineGap, emsize, fontmetrics);
714 *height = SCALE_FONT_METRIC(fontmetrics->ascent + fontmetrics->descent + fontmetrics->lineGap, emsize, fontmetrics);
717 static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
719 IDWriteFontFallback *fallback;
720 IDWriteTextAnalyzer *analyzer;
721 struct layout_range *range;
722 struct layout_run *r;
723 UINT32 cluster = 0;
724 HRESULT hr;
726 free_layout_eruns(layout);
727 free_layout_runs(layout);
729 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
730 if (!layout->clustermetrics) {
731 layout->clustermetrics = heap_alloc(layout->len*sizeof(*layout->clustermetrics));
732 layout->clusters = heap_alloc(layout->len*sizeof(*layout->clusters));
733 if (!layout->clustermetrics || !layout->clusters) {
734 heap_free(layout->clustermetrics);
735 heap_free(layout->clusters);
736 return E_OUTOFMEMORY;
739 layout->cluster_count = 0;
741 hr = get_textanalyzer(&analyzer);
742 if (FAILED(hr))
743 return hr;
745 LIST_FOR_EACH_ENTRY(range, &layout->ranges, struct layout_range, h.entry) {
746 /* we don't care about ranges that don't contain any text */
747 if (range->h.range.startPosition >= layout->len)
748 break;
750 /* inline objects override actual text in a range */
751 if (range->object) {
752 hr = layout_update_breakpoints_range(layout, range);
753 if (FAILED(hr))
754 return hr;
756 r = alloc_layout_run(LAYOUT_RUN_INLINE);
757 if (!r)
758 return E_OUTOFMEMORY;
760 r->u.object.object = range->object;
761 r->u.object.length = get_clipped_range_length(layout, range);
762 list_add_tail(&layout->runs, &r->entry);
763 continue;
766 /* initial splitting by script */
767 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, (IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
768 range->h.range.startPosition, get_clipped_range_length(layout, range), (IDWriteTextAnalysisSink*)&layout->IDWriteTextAnalysisSink1_iface);
769 if (FAILED(hr))
770 break;
772 /* this splits it further */
773 hr = IDWriteTextAnalyzer_AnalyzeBidi(analyzer, (IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
774 range->h.range.startPosition, get_clipped_range_length(layout, range), (IDWriteTextAnalysisSink*)&layout->IDWriteTextAnalysisSink1_iface);
775 if (FAILED(hr))
776 break;
779 if (layout->format.fallback) {
780 fallback = layout->format.fallback;
781 IDWriteFontFallback_AddRef(fallback);
783 else {
784 hr = IDWriteFactory2_GetSystemFontFallback(layout->factory, &fallback);
785 if (FAILED(hr))
786 return hr;
789 /* resolve run fonts */
790 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
791 struct regular_layout_run *run = &r->u.regular;
792 UINT32 length;
794 if (r->kind == LAYOUT_RUN_INLINE)
795 continue;
797 range = get_layout_range_by_pos(layout, run->descr.textPosition);
798 length = run->descr.stringLength;
800 while (length) {
801 UINT32 mapped_length;
802 IDWriteFont *font;
803 FLOAT scale;
805 run = &r->u.regular;
807 hr = IDWriteFontFallback_MapCharacters(fallback,
808 (IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
809 run->descr.textPosition,
810 run->descr.stringLength,
811 range->collection,
812 range->fontfamily,
813 range->weight,
814 range->style,
815 range->stretch,
816 &mapped_length,
817 &font,
818 &scale);
819 if (FAILED(hr)) {
820 WARN("%s: failed to map family %s, collection %p\n", debugstr_rundescr(&run->descr), debugstr_w(range->fontfamily), range->collection);
821 return hr;
824 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
825 IDWriteFont_Release(font);
826 if (FAILED(hr))
827 return hr;
828 run->run.fontEmSize = range->fontsize * scale;
830 if (mapped_length < length) {
831 struct regular_layout_run *nextrun = &r->u.regular;
832 struct layout_run *nextr;
834 /* keep mapped part for current run, add another run for the rest */
835 nextr = alloc_layout_run(LAYOUT_RUN_REGULAR);
836 if (!nextr)
837 return E_OUTOFMEMORY;
839 *nextr = *r;
840 nextrun = &nextr->u.regular;
841 nextrun->descr.textPosition = run->descr.textPosition + mapped_length;
842 nextrun->descr.stringLength = run->descr.stringLength - mapped_length;
843 nextrun->descr.string = &layout->str[nextrun->descr.textPosition];
844 run->descr.stringLength = mapped_length;
845 list_add_after(&r->entry, &nextr->entry);
846 r = nextr;
849 length -= mapped_length;
853 IDWriteFontFallback_Release(fallback);
855 /* fill run info */
856 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
857 DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props = NULL;
858 DWRITE_SHAPING_TEXT_PROPERTIES *text_props = NULL;
859 struct regular_layout_run *run = &r->u.regular;
860 DWRITE_FONT_METRICS fontmetrics = { 0 };
861 UINT32 max_count;
863 /* we need to do very little in case of inline objects */
864 if (r->kind == LAYOUT_RUN_INLINE) {
865 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[cluster];
866 struct layout_cluster *c = &layout->clusters[cluster];
867 DWRITE_INLINE_OBJECT_METRICS inlinemetrics;
869 metrics->width = 0.0f;
870 metrics->length = r->u.object.length;
871 metrics->canWrapLineAfter = 0;
872 metrics->isWhitespace = 0;
873 metrics->isNewline = 0;
874 metrics->isSoftHyphen = 0;
875 metrics->isRightToLeft = 0;
876 metrics->padding = 0;
877 c->run = r;
878 c->position = 0; /* there's always one cluster per inline object, so 0 is valid value */
879 cluster++;
881 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
882 hr = IDWriteInlineObject_GetMetrics(r->u.object.object, &inlinemetrics);
883 if (FAILED(hr)) {
884 memset(&inlinemetrics, 0, sizeof(inlinemetrics));
885 hr = S_OK;
887 metrics->width = inlinemetrics.width;
888 r->baseline = inlinemetrics.baseline;
889 r->height = inlinemetrics.height;
891 /* FIXME: use resolved breakpoints in this case too */
893 continue;
896 range = get_layout_range_by_pos(layout, run->descr.textPosition);
897 run->descr.localeName = range->locale;
898 run->clustermap = heap_alloc(run->descr.stringLength*sizeof(UINT16));
900 max_count = 3*run->descr.stringLength/2 + 16;
901 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
902 if (!run->clustermap || !run->glyphs)
903 goto memerr;
905 text_props = heap_alloc(run->descr.stringLength*sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
906 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
907 if (!text_props || !glyph_props)
908 goto memerr;
910 while (1) {
911 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, run->descr.string, run->descr.stringLength,
912 run->run.fontFace, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
913 NULL /* FIXME */, NULL, NULL, 0, max_count, run->clustermap, text_props, run->glyphs, glyph_props,
914 &run->glyphcount);
915 if (hr == E_NOT_SUFFICIENT_BUFFER) {
916 heap_free(run->glyphs);
917 heap_free(glyph_props);
919 max_count = run->glyphcount;
921 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
922 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
923 if (!run->glyphs || !glyph_props)
924 goto memerr;
926 continue;
929 break;
932 if (FAILED(hr)) {
933 heap_free(text_props);
934 heap_free(glyph_props);
935 WARN("%s: shaping failed 0x%08x\n", debugstr_rundescr(&run->descr), hr);
936 continue;
939 run->run.glyphIndices = run->glyphs;
940 run->descr.clusterMap = run->clustermap;
942 run->advances = heap_alloc(run->glyphcount*sizeof(FLOAT));
943 run->offsets = heap_alloc(run->glyphcount*sizeof(DWRITE_GLYPH_OFFSET));
944 if (!run->advances || !run->offsets)
945 goto memerr;
947 /* now set advances and offsets */
948 if (is_layout_gdi_compatible(layout))
949 hr = IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap,
950 text_props, run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount,
951 run->run.fontFace, run->run.fontEmSize, layout->ppdip, &layout->transform,
952 layout->measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->run.isSideways,
953 run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL, NULL, 0, run->advances, run->offsets);
954 else
955 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap, text_props,
956 run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount, run->run.fontFace,
957 run->run.fontEmSize, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
958 NULL, NULL, 0, run->advances, run->offsets);
960 heap_free(text_props);
961 heap_free(glyph_props);
962 if (FAILED(hr))
963 WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_rundescr(&run->descr), hr);
965 run->run.glyphAdvances = run->advances;
966 run->run.glyphOffsets = run->offsets;
968 /* Special treatment for runs that don't produce visual output, shaping code adds normal glyphs for them,
969 with valid cluster map and potentially with non-zero advances; layout code exposes those as zero width clusters. */
970 if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL)
971 run->run.glyphCount = 0;
972 else
973 run->run.glyphCount = run->glyphcount;
975 /* baseline derived from font metrics */
976 layout_get_font_metrics(layout, run->run.fontFace, run->run.fontEmSize, &fontmetrics);
977 layout_get_font_height(run->run.fontEmSize, &fontmetrics, &r->baseline, &r->height);
979 layout_set_cluster_metrics(layout, r, &cluster);
980 continue;
982 memerr:
983 heap_free(text_props);
984 heap_free(glyph_props);
985 heap_free(run->clustermap);
986 heap_free(run->glyphs);
987 heap_free(run->advances);
988 heap_free(run->offsets);
989 run->advances = NULL;
990 run->offsets = NULL;
991 run->clustermap = run->glyphs = NULL;
992 hr = E_OUTOFMEMORY;
993 break;
996 if (hr == S_OK) {
997 layout->cluster_count = cluster;
998 if (cluster)
999 layout->clustermetrics[cluster-1].canWrapLineAfter = 1;
1002 IDWriteTextAnalyzer_Release(analyzer);
1003 return hr;
1006 static HRESULT layout_compute(struct dwrite_textlayout *layout)
1008 HRESULT hr;
1010 if (!(layout->recompute & RECOMPUTE_NOMINAL_RUNS))
1011 return S_OK;
1013 /* nominal breakpoints are evaluated only once, because string never changes */
1014 if (!layout->nominal_breakpoints) {
1015 IDWriteTextAnalyzer *analyzer;
1016 HRESULT hr;
1018 layout->nominal_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
1019 if (!layout->nominal_breakpoints)
1020 return E_OUTOFMEMORY;
1022 hr = get_textanalyzer(&analyzer);
1023 if (FAILED(hr))
1024 return hr;
1026 hr = IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer, (IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
1027 0, layout->len, (IDWriteTextAnalysisSink*)&layout->IDWriteTextAnalysisSink1_iface);
1028 IDWriteTextAnalyzer_Release(analyzer);
1030 if (layout->actual_breakpoints) {
1031 heap_free(layout->actual_breakpoints);
1032 layout->actual_breakpoints = NULL;
1035 hr = layout_compute_runs(layout);
1037 if (TRACE_ON(dwrite)) {
1038 struct layout_run *cur;
1040 LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
1041 if (cur->kind == LAYOUT_RUN_INLINE)
1042 TRACE("run inline object %p, len %u\n", cur->u.object.object, cur->u.object.length);
1043 else
1044 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur->u.regular.descr.textPosition, cur->u.regular.descr.textPosition +
1045 cur->u.regular.descr.stringLength-1, cur->u.regular.descr.stringLength, cur->u.regular.run.bidiLevel);
1049 layout->recompute &= ~RECOMPUTE_NOMINAL_RUNS;
1050 return hr;
1053 static inline FLOAT get_cluster_range_width(struct dwrite_textlayout *layout, UINT32 start, UINT32 end)
1055 FLOAT width = 0.0f;
1056 for (; start < end; start++)
1057 width += layout->clustermetrics[start].width;
1058 return width;
1061 static struct layout_range_header *get_layout_range_header_by_pos(struct list *ranges, UINT32 pos)
1063 struct layout_range_header *cur;
1065 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
1066 DWRITE_TEXT_RANGE *r = &cur->range;
1067 if (r->startPosition <= pos && pos < r->startPosition + r->length)
1068 return cur;
1071 return NULL;
1074 static inline IUnknown *layout_get_effect_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1076 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->effects, pos);
1077 return ((struct layout_range_iface*)h)->iface;
1080 static inline BOOL layout_is_erun_rtl(const struct layout_effective_run *erun)
1082 return erun->run->u.regular.run.bidiLevel & 1;
1085 /* A set of parameters that additionally splits resulting runs. It happens after shaping and all text processing,
1086 no glyph changes are possible. It's understandable for drawing effects, because DrawGlyphRun() reports them as
1087 one of the arguments, but it also happens for decorations, so every effective run has uniform
1088 underline/strikethough/effect tuple. */
1089 struct layout_final_splitting_params {
1090 BOOL strikethrough;
1091 BOOL underline;
1092 IUnknown *effect;
1095 static inline BOOL layout_get_strikethrough_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1097 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->strike_ranges, pos);
1098 return ((struct layout_range_bool*)h)->value;
1101 static inline BOOL layout_get_underline_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1103 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->underline_ranges, pos);
1104 return ((struct layout_range_bool*)h)->value;
1107 static void layout_splitting_params_from_pos(struct dwrite_textlayout *layout, UINT32 pos,
1108 struct layout_final_splitting_params *params)
1110 params->strikethrough = layout_get_strikethrough_from_pos(layout, pos);
1111 params->underline = layout_get_underline_from_pos(layout, pos);
1112 params->effect = layout_get_effect_from_pos(layout, pos);
1115 static BOOL is_same_splitting_params(const struct layout_final_splitting_params *left,
1116 const struct layout_final_splitting_params *right)
1118 return left->strikethrough == right->strikethrough &&
1119 left->underline == right->underline &&
1120 left->effect == right->effect;
1123 static void layout_get_erun_font_metrics(struct dwrite_textlayout *layout, struct layout_effective_run *erun,
1124 DWRITE_FONT_METRICS *metrics)
1126 memset(metrics, 0, sizeof(*metrics));
1127 if (is_layout_gdi_compatible(layout)) {
1128 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(
1129 erun->run->u.regular.run.fontFace,
1130 erun->run->u.regular.run.fontEmSize,
1131 layout->ppdip,
1132 &layout->transform,
1133 metrics);
1134 if (FAILED(hr))
1135 WARN("failed to get font metrics, 0x%08x\n", hr);
1137 else
1138 IDWriteFontFace_GetMetrics(erun->run->u.regular.run.fontFace, metrics);
1141 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
1142 'cluster_count' indicates how many clusters to add, including first one. */
1143 static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 first_cluster,
1144 UINT32 cluster_count, UINT32 line, FLOAT origin_x, struct layout_final_splitting_params *params)
1146 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1147 UINT32 i, start, length, last_cluster;
1148 struct layout_effective_run *run;
1150 if (r->kind == LAYOUT_RUN_INLINE) {
1151 struct layout_effective_inline *inlineobject;
1153 inlineobject = heap_alloc(sizeof(*inlineobject));
1154 if (!inlineobject)
1155 return E_OUTOFMEMORY;
1157 inlineobject->run = r;
1158 inlineobject->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1159 inlineobject->origin_x = is_rtl ? origin_x - inlineobject->width : origin_x;
1160 inlineobject->origin_y = 0.0f; /* set after line is built */
1161 inlineobject->align_dx = 0.0f;
1163 /* It's not clear how these two are set, possibly directionality
1164 is derived from surrounding text (replaced text could have
1165 different ranges which differ in reading direction). */
1166 inlineobject->is_sideways = FALSE;
1167 inlineobject->is_rtl = FALSE;
1168 inlineobject->line = line;
1170 /* effect assigned from start position and on is used for inline objects */
1171 inlineobject->effect = layout_get_effect_from_pos(layout, layout->clusters[first_cluster].position);
1173 list_add_tail(&layout->inlineobjects, &inlineobject->entry);
1174 return S_OK;
1177 run = heap_alloc(sizeof(*run));
1178 if (!run)
1179 return E_OUTOFMEMORY;
1181 /* No need to iterate for that, use simple fact that:
1182 <last cluster position> = first cluster position> + <sum of cluster lengths not including last one> */
1183 last_cluster = first_cluster + cluster_count - 1;
1184 length = layout->clusters[last_cluster].position - layout->clusters[first_cluster].position +
1185 layout->clustermetrics[last_cluster].length;
1187 run->clustermap = heap_alloc(sizeof(UINT16)*length);
1188 if (!run->clustermap) {
1189 heap_free(run);
1190 return E_OUTOFMEMORY;
1193 run->run = r;
1194 run->start = start = layout->clusters[first_cluster].position;
1195 run->length = length;
1196 run->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1198 /* Check if run direction matches paragraph direction, if it doesn't adjust by
1199 run width */
1200 if (layout_is_erun_rtl(run) ^ is_rtl)
1201 run->origin_x = is_rtl ? origin_x - run->width : origin_x + run->width;
1202 else
1203 run->origin_x = origin_x;
1205 run->origin_y = 0.0f; /* set after line is built */
1206 run->align_dx = 0.0f;
1207 run->line = line;
1209 if (r->u.regular.run.glyphCount) {
1210 /* trim from the left */
1211 run->glyphcount = r->u.regular.run.glyphCount - r->u.regular.clustermap[start];
1212 /* trim from the right */
1213 if (start + length < r->u.regular.descr.stringLength - 1)
1214 run->glyphcount -= r->u.regular.run.glyphCount - r->u.regular.clustermap[start + length];
1216 else
1217 run->glyphcount = 0;
1219 /* cluster map needs to be shifted */
1220 for (i = 0; i < length; i++)
1221 run->clustermap[i] = r->u.regular.clustermap[start + i] - r->u.regular.clustermap[start];
1223 run->effect = params->effect;
1224 run->underlined = params->underline;
1225 list_add_tail(&layout->eruns, &run->entry);
1227 /* Strikethrough style is guaranteed to be consistent within effective run,
1228 its width equals to run width, thickness and offset are derived from
1229 font metrics, rest of the values are from layout or run itself */
1230 if (params->strikethrough) {
1231 struct layout_strikethrough *s;
1232 DWRITE_FONT_METRICS metrics;
1234 s = heap_alloc(sizeof(*s));
1235 if (!s)
1236 return E_OUTOFMEMORY;
1238 layout_get_erun_font_metrics(layout, run, &metrics);
1239 s->s.width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1240 s->s.thickness = SCALE_FONT_METRIC(metrics.strikethroughThickness, r->u.regular.run.fontEmSize, &metrics);
1241 /* Negative offset moves it above baseline as Y coordinate grows downward. */
1242 s->s.offset = -SCALE_FONT_METRIC(metrics.strikethroughPosition, r->u.regular.run.fontEmSize, &metrics);
1243 s->s.readingDirection = layout->format.readingdir;
1244 s->s.flowDirection = layout->format.flow;
1245 s->s.localeName = r->u.regular.descr.localeName;
1246 s->s.measuringMode = layout->measuringmode;
1247 s->run = run;
1249 list_add_tail(&layout->strikethrough, &s->entry);
1252 return S_OK;
1255 static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_LINE_METRICS *metrics, UINT32 *line)
1257 if (!layout->line_alloc) {
1258 layout->line_alloc = 5;
1259 layout->lines = heap_alloc(layout->line_alloc*sizeof(*layout->lines));
1260 if (!layout->lines)
1261 return E_OUTOFMEMORY;
1264 if (layout->metrics.lineCount == layout->line_alloc) {
1265 DWRITE_LINE_METRICS *l = heap_realloc(layout->lines, layout->line_alloc*2*sizeof(*layout->lines));
1266 if (!l)
1267 return E_OUTOFMEMORY;
1268 layout->lines = l;
1269 layout->line_alloc *= 2;
1272 layout->lines[*line] = *metrics;
1273 layout->metrics.lineCount += 1;
1274 *line += 1;
1275 return S_OK;
1279 static inline struct layout_effective_run *layout_get_next_erun(struct dwrite_textlayout *layout,
1280 const struct layout_effective_run *cur)
1282 struct list *e;
1284 if (!cur)
1285 e = list_head(&layout->eruns);
1286 else
1287 e = list_next(&layout->eruns, &cur->entry);
1288 if (!e)
1289 return NULL;
1290 return LIST_ENTRY(e, struct layout_effective_run, entry);
1293 static inline struct layout_effective_run *layout_get_prev_erun(struct dwrite_textlayout *layout,
1294 const struct layout_effective_run *cur)
1296 struct list *e;
1298 if (!cur)
1299 e = list_tail(&layout->eruns);
1300 else
1301 e = list_prev(&layout->eruns, &cur->entry);
1302 if (!e)
1303 return NULL;
1304 return LIST_ENTRY(e, struct layout_effective_run, entry);
1307 static inline struct layout_effective_inline *layout_get_next_inline_run(struct dwrite_textlayout *layout,
1308 const struct layout_effective_inline *cur)
1310 struct list *e;
1312 if (!cur)
1313 e = list_head(&layout->inlineobjects);
1314 else
1315 e = list_next(&layout->inlineobjects, &cur->entry);
1316 if (!e)
1317 return NULL;
1318 return LIST_ENTRY(e, struct layout_effective_inline, entry);
1321 static FLOAT layout_get_line_width(struct dwrite_textlayout *layout,
1322 struct layout_effective_run *erun, struct layout_effective_inline *inrun, UINT32 line)
1324 FLOAT width = 0.0f;
1326 while (erun && erun->line == line) {
1327 width += erun->width;
1328 erun = layout_get_next_erun(layout, erun);
1329 if (!erun)
1330 break;
1333 while (inrun && inrun->line == line) {
1334 width += inrun->width;
1335 inrun = layout_get_next_inline_run(layout, inrun);
1336 if (!inrun)
1337 break;
1340 return width;
1343 static inline BOOL should_skip_transform(const DWRITE_MATRIX *m, FLOAT *det)
1345 *det = m->m11 * m->m22 - m->m12 * m->m21;
1346 /* on certain conditions we can skip transform */
1347 return (!memcmp(m, &identity, sizeof(*m)) || fabsf(*det) <= 1e-10f);
1350 static inline void layout_apply_snapping(struct dwrite_vec *vec, BOOL skiptransform, FLOAT ppdip,
1351 const DWRITE_MATRIX *m, FLOAT det)
1353 if (!skiptransform) {
1354 FLOAT vec2[2];
1356 /* apply transform */
1357 vec->x *= ppdip;
1358 vec->y *= ppdip;
1360 vec2[0] = m->m11 * vec->x + m->m21 * vec->y + m->dx;
1361 vec2[1] = m->m12 * vec->x + m->m22 * vec->y + m->dy;
1363 /* snap */
1364 vec2[0] = floorf(vec2[0] + 0.5f);
1365 vec2[1] = floorf(vec2[1] + 0.5f);
1367 /* apply inverted transform, we don't care about X component at this point */
1368 vec->x = (m->m22 * vec2[0] - m->m21 * vec2[1] + m->m21 * m->dy - m->m22 * m->dx) / det;
1369 vec->x /= ppdip;
1371 vec->y = (-m->m12 * vec2[0] + m->m11 * vec2[1] - (m->m11 * m->dy - m->m12 * m->dx)) / det;
1372 vec->y /= ppdip;
1374 else {
1375 vec->x = floorf(vec->x * ppdip + 0.5f) / ppdip;
1376 vec->y = floorf(vec->y * ppdip + 0.5f) / ppdip;
1380 static void layout_apply_leading_alignment(struct dwrite_textlayout *layout)
1382 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1383 struct layout_effective_inline *inrun;
1384 struct layout_effective_run *erun;
1386 erun = layout_get_next_erun(layout, NULL);
1387 inrun = layout_get_next_inline_run(layout, NULL);
1389 while (erun) {
1390 erun->align_dx = 0.0f;
1391 erun = layout_get_next_erun(layout, erun);
1394 while (inrun) {
1395 inrun->align_dx = 0.0f;
1396 inrun = layout_get_next_inline_run(layout, inrun);
1399 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
1402 static void layout_apply_trailing_alignment(struct dwrite_textlayout *layout)
1404 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1405 struct layout_effective_inline *inrun;
1406 struct layout_effective_run *erun;
1407 UINT32 line;
1409 erun = layout_get_next_erun(layout, NULL);
1410 inrun = layout_get_next_inline_run(layout, NULL);
1412 for (line = 0; line < layout->metrics.lineCount; line++) {
1413 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1414 FLOAT shift = layout->metrics.layoutWidth - width;
1416 if (is_rtl)
1417 shift *= -1.0f;
1419 while (erun && erun->line == line) {
1420 erun->align_dx = shift;
1421 erun = layout_get_next_erun(layout, erun);
1424 while (inrun && inrun->line == line) {
1425 inrun->align_dx = shift;
1426 inrun = layout_get_next_inline_run(layout, inrun);
1430 layout->metrics.left = is_rtl ? 0.0f : layout->metrics.layoutWidth - layout->metrics.width;
1433 static inline FLOAT layout_get_centered_shift(struct dwrite_textlayout *layout, BOOL skiptransform,
1434 FLOAT width, FLOAT det)
1436 if (is_layout_gdi_compatible(layout)) {
1437 struct dwrite_vec vec = { layout->metrics.layoutWidth - width, 0.0f};
1438 layout_apply_snapping(&vec, skiptransform, layout->ppdip, &layout->transform, det);
1439 return floorf(vec.x / 2.0f);
1441 else
1442 return (layout->metrics.layoutWidth - width) / 2.0f;
1445 static void layout_apply_centered_alignment(struct dwrite_textlayout *layout)
1447 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1448 struct layout_effective_inline *inrun;
1449 struct layout_effective_run *erun;
1450 BOOL skiptransform;
1451 UINT32 line;
1452 FLOAT det;
1454 erun = layout_get_next_erun(layout, NULL);
1455 inrun = layout_get_next_inline_run(layout, NULL);
1457 skiptransform = should_skip_transform(&layout->transform, &det);
1459 for (line = 0; line < layout->metrics.lineCount; line++) {
1460 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1461 FLOAT shift = layout_get_centered_shift(layout, skiptransform, width, det);
1463 if (is_rtl)
1464 shift *= -1.0f;
1466 while (erun && erun->line == line) {
1467 erun->align_dx = shift;
1468 erun = layout_get_next_erun(layout, erun);
1471 while (inrun && inrun->line == line) {
1472 inrun->align_dx = shift;
1473 inrun = layout_get_next_inline_run(layout, inrun);
1477 layout->metrics.left = (layout->metrics.layoutWidth - layout->metrics.width) / 2.0f;
1480 static void layout_apply_text_alignment(struct dwrite_textlayout *layout)
1482 switch (layout->format.textalignment)
1484 case DWRITE_TEXT_ALIGNMENT_LEADING:
1485 layout_apply_leading_alignment(layout);
1486 break;
1487 case DWRITE_TEXT_ALIGNMENT_TRAILING:
1488 layout_apply_trailing_alignment(layout);
1489 break;
1490 case DWRITE_TEXT_ALIGNMENT_CENTER:
1491 layout_apply_centered_alignment(layout);
1492 break;
1493 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED:
1494 FIXME("alignment %d not implemented\n", layout->format.textalignment);
1495 break;
1496 default:
1501 static void layout_apply_par_alignment(struct dwrite_textlayout *layout)
1503 struct layout_effective_inline *inrun;
1504 struct layout_effective_run *erun;
1505 FLOAT origin_y = 0.0f;
1506 UINT32 line;
1508 /* alignment mode defines origin, after that all run origins are updated
1509 the same way */
1511 switch (layout->format.paralign)
1513 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR:
1514 origin_y = 0.0f;
1515 break;
1516 case DWRITE_PARAGRAPH_ALIGNMENT_FAR:
1517 origin_y = layout->metrics.layoutHeight - layout->metrics.height;
1518 break;
1519 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER:
1520 origin_y = (layout->metrics.layoutHeight - layout->metrics.height) / 2.0f;
1521 break;
1522 default:
1526 layout->metrics.top = origin_y;
1528 erun = layout_get_next_erun(layout, NULL);
1529 inrun = layout_get_next_inline_run(layout, NULL);
1530 for (line = 0; line < layout->metrics.lineCount; line++) {
1531 origin_y += layout->lines[line].baseline;
1533 while (erun && erun->line == line) {
1534 erun->origin_y = origin_y;
1535 erun = layout_get_next_erun(layout, erun);
1538 while (inrun && inrun->line == line) {
1539 inrun->origin_y = origin_y - inrun->run->baseline;
1540 inrun = layout_get_next_inline_run(layout, inrun);
1545 struct layout_underline_splitting_params {
1546 const WCHAR *locale; /* points to range data, no additional allocation */
1547 IUnknown *effect; /* does not hold another reference */
1550 static void init_u_splitting_params_from_erun(struct layout_effective_run *erun,
1551 struct layout_underline_splitting_params *params)
1553 params->locale = erun->run->u.regular.descr.localeName;
1554 params->effect = erun->effect;
1557 static BOOL is_same_u_splitting(struct layout_underline_splitting_params *left,
1558 struct layout_underline_splitting_params *right)
1560 return left->effect == right->effect && !strcmpiW(left->locale, right->locale);
1563 static HRESULT layout_add_underline(struct dwrite_textlayout *layout, struct layout_effective_run *first,
1564 struct layout_effective_run *last)
1566 struct layout_effective_run *cur;
1567 DWRITE_FONT_METRICS metrics;
1568 FLOAT thickness, offset;
1570 if (first == layout_get_prev_erun(layout, last)) {
1571 layout_get_erun_font_metrics(layout, first, &metrics);
1572 thickness = SCALE_FONT_METRIC(metrics.underlineThickness, first->run->u.regular.run.fontEmSize, &metrics);
1573 offset = SCALE_FONT_METRIC(metrics.underlinePosition, first->run->u.regular.run.fontEmSize, &metrics);
1575 else {
1576 FLOAT width = 0.0f;
1578 /* Single underline is added for consecutive underlined runs. In this case underline parameters are
1579 calculated as weighted average, where run width acts as a weight. */
1580 thickness = offset = 0.0f;
1581 cur = first;
1582 do {
1583 layout_get_erun_font_metrics(layout, cur, &metrics);
1585 thickness += SCALE_FONT_METRIC(metrics.underlineThickness, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
1586 offset += SCALE_FONT_METRIC(metrics.underlinePosition, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
1587 width += cur->width;
1589 cur = layout_get_next_erun(layout, cur);
1590 } while (cur != last);
1592 thickness /= width;
1593 offset /= width;
1596 cur = first;
1597 do {
1598 struct layout_underline_splitting_params params, prev_params;
1599 struct layout_effective_run *next, *w;
1600 struct layout_underline *u;
1602 init_u_splitting_params_from_erun(cur, &prev_params);
1603 while ((next = layout_get_next_erun(layout, cur)) != last) {
1604 init_u_splitting_params_from_erun(next, &params);
1605 if (!is_same_u_splitting(&prev_params, &params))
1606 break;
1607 cur = next;
1610 u = heap_alloc(sizeof(*u));
1611 if (!u)
1612 return E_OUTOFMEMORY;
1614 w = cur;
1615 u->u.width = 0.0f;
1616 while (w != next) {
1617 u->u.width += w->width;
1618 w = layout_get_next_erun(layout, w);
1621 u->u.thickness = thickness;
1622 /* Font metrics convention is to have it negative when below baseline, for rendering
1623 however Y grows from baseline down for horizontal baseline. */
1624 u->u.offset = -offset;
1625 u->u.runHeight = 0.0f; /* FIXME */
1626 u->u.readingDirection = is_run_rtl(cur) ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
1627 DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
1628 u->u.flowDirection = layout->format.flow;
1629 u->u.localeName = cur->run->u.regular.descr.localeName;
1630 u->u.measuringMode = layout->measuringmode;
1631 u->run = cur;
1632 list_add_tail(&layout->underlines, &u->entry);
1634 cur = next;
1635 } while (cur != last);
1637 return S_OK;
1640 /* Adds zero width line, metrics are derived from font at specified text position. */
1641 static HRESULT layout_set_dummy_line_metrics(struct dwrite_textlayout *layout, UINT32 pos, UINT32 *line)
1643 DWRITE_FONT_METRICS fontmetrics;
1644 DWRITE_LINE_METRICS metrics;
1645 struct layout_range *range;
1646 IDWriteFontFace *fontface;
1647 IDWriteFont *font;
1648 HRESULT hr;
1650 range = get_layout_range_by_pos(layout, pos);
1651 hr = create_matching_font(range->collection,
1652 range->fontfamily,
1653 range->weight,
1654 range->style,
1655 range->stretch,
1656 &font);
1657 if (FAILED(hr))
1658 return hr;
1659 hr = IDWriteFont_CreateFontFace(font, &fontface);
1660 IDWriteFont_Release(font);
1661 if (FAILED(hr))
1662 return hr;
1664 layout_get_font_metrics(layout, fontface, range->fontsize, &fontmetrics);
1665 layout_get_font_height(range->fontsize, &fontmetrics, &metrics.baseline, &metrics.height);
1666 IDWriteFontFace_Release(fontface);
1668 metrics.length = 0;
1669 metrics.trailingWhitespaceLength = 0;
1670 metrics.newlineLength = 0;
1671 metrics.isTrimmed = FALSE;
1672 return layout_set_line_metrics(layout, &metrics, line);
1675 static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
1677 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1678 struct layout_final_splitting_params prev_params, params;
1679 struct layout_effective_run *erun, *first_underlined;
1680 struct layout_effective_inline *inrun;
1681 const struct layout_run *run;
1682 DWRITE_LINE_METRICS metrics;
1683 FLOAT width, origin_x, origin_y;
1684 UINT32 i, start, line, textpos;
1685 HRESULT hr;
1687 if (!(layout->recompute & RECOMPUTE_EFFECTIVE_RUNS))
1688 return S_OK;
1690 hr = layout_compute(layout);
1691 if (FAILED(hr))
1692 return hr;
1694 layout->metrics.lineCount = 0;
1695 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0f;
1696 line = 0;
1697 run = layout->clusters[0].run;
1698 memset(&metrics, 0, sizeof(metrics));
1700 layout_splitting_params_from_pos(layout, 0, &params);
1701 prev_params = params;
1703 for (i = 0, start = 0, textpos = 0, width = 0.0f; i < layout->cluster_count; i++) {
1704 BOOL overflow;
1706 layout_splitting_params_from_pos(layout, textpos, &params);
1708 /* switched to next nominal run, at this point all previous pending clusters are already
1709 checked for layout line overflow, so new effective run will fit in current line */
1710 if (run != layout->clusters[i].run || !is_same_splitting_params(&prev_params, &params)) {
1711 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, &prev_params);
1712 if (FAILED(hr))
1713 return hr;
1714 origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) :
1715 get_cluster_range_width(layout, start, i);
1716 run = layout->clusters[i].run;
1717 start = i;
1720 overflow = layout->clustermetrics[i].canWrapLineAfter &&
1721 (width + layout->clustermetrics[i].width > layout->metrics.layoutWidth) &&
1722 (layout->format.wrapping != DWRITE_WORD_WRAPPING_NO_WRAP);
1723 /* check if we got new */
1724 if (overflow ||
1725 layout->clustermetrics[i].isNewline || /* always wrap on new line */
1726 i == layout->cluster_count - 1) /* end of the text */ {
1728 UINT32 strlength, last_cluster, index;
1729 FLOAT descent, trailingspacewidth;
1730 struct layout_final_splitting_params *p;
1732 if (!overflow) {
1733 width += layout->clustermetrics[i].width;
1734 metrics.length += layout->clustermetrics[i].length;
1735 last_cluster = i;
1736 p = &params;
1738 else {
1739 last_cluster = i ? i - 1 : i;
1740 p = &prev_params;
1743 if (i >= start) {
1744 hr = layout_add_effective_run(layout, run, start, last_cluster - start + 1, line, origin_x, p);
1745 if (FAILED(hr))
1746 return hr;
1747 /* we don't need to update origin for next run as we're going to wrap */
1750 /* take a look at clusters we got for this line in reverse order to set
1751 trailing properties for current line */
1752 strlength = metrics.length;
1753 index = last_cluster;
1754 trailingspacewidth = 0.0f;
1755 while (strlength) {
1756 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1757 struct layout_cluster *lc = &layout->clusters[index];
1758 WCHAR ch;
1760 /* This also filters out clusters added from inline objects, those are never
1761 treated as a white space. */
1762 if (!cluster->isWhitespace)
1763 break;
1765 /* Every isNewline cluster is also isWhitespace, but not every
1766 newline character cluster has isNewline set, so go back to original string. */
1767 ch = lc->run->u.regular.descr.string[lc->position];
1768 if (cluster->length == 1 && lb_is_newline_char(ch))
1769 metrics.newlineLength += cluster->length;
1771 metrics.trailingWhitespaceLength += cluster->length;
1772 trailingspacewidth += cluster->width;
1774 strlength -= cluster->length;
1775 index--;
1778 /* look for max baseline and descent for this line */
1779 strlength = metrics.length;
1780 index = last_cluster;
1781 metrics.baseline = 0.0f;
1782 descent = 0.0f;
1783 while (strlength) {
1784 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1785 const struct layout_run *cur = layout->clusters[index].run;
1786 FLOAT cur_descent = cur->height - cur->baseline;
1788 if (cur->baseline > metrics.baseline)
1789 metrics.baseline = cur->baseline;
1791 if (cur_descent > descent)
1792 descent = cur_descent;
1794 strlength -= cluster->length;
1795 index--;
1797 metrics.height = descent + metrics.baseline;
1799 if (width > layout->metrics.widthIncludingTrailingWhitespace)
1800 layout->metrics.widthIncludingTrailingWhitespace = width;
1801 if (width - trailingspacewidth > layout->metrics.width)
1802 layout->metrics.width = width - trailingspacewidth;
1804 metrics.isTrimmed = width > layout->metrics.layoutWidth;
1805 hr = layout_set_line_metrics(layout, &metrics, &line);
1806 if (FAILED(hr))
1807 return hr;
1809 width = layout->clustermetrics[i].width;
1810 memset(&metrics, 0, sizeof(metrics));
1811 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0f;
1812 start = i;
1814 else {
1815 metrics.length += layout->clustermetrics[i].length;
1816 width += layout->clustermetrics[i].width;
1819 prev_params = params;
1820 textpos += layout->clustermetrics[i].length;
1823 /* Add dummy line if:
1824 - there's no text, metrics come from first range in this case;
1825 - last ended with a mandatory break, metrics come from last text position.
1827 if (layout->len == 0)
1828 hr = layout_set_dummy_line_metrics(layout, 0, &line);
1829 else if (layout->clustermetrics[layout->cluster_count-1].isNewline)
1830 hr = layout_set_dummy_line_metrics(layout, layout->len-1, &line);
1831 if (FAILED(hr))
1832 return hr;
1834 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
1835 layout->metrics.top = 0.0f;
1836 layout->metrics.maxBidiReorderingDepth = 1; /* FIXME */
1837 layout->metrics.height = 0.0f;
1839 /* Now all line info is here, update effective runs positions in flow direction */
1840 erun = layout_get_next_erun(layout, NULL);
1841 first_underlined = erun && erun->underlined ? erun : NULL;
1843 inrun = layout_get_next_inline_run(layout, NULL);
1845 origin_y = 0.0f;
1846 for (line = 0; line < layout->metrics.lineCount; line++) {
1848 origin_y += layout->lines[line].baseline;
1850 /* For all runs on this line */
1851 while (erun && erun->line == line) {
1852 erun->origin_y = origin_y;
1853 erun = layout_get_next_erun(layout, erun);
1855 if (first_underlined && (!erun || !erun->underlined)) {
1856 layout_add_underline(layout, first_underlined, erun);
1857 first_underlined = NULL;
1859 else if (!first_underlined && erun && erun->underlined)
1860 first_underlined = erun;
1863 /* Same for inline runs */
1864 while (inrun && inrun->line == line) {
1865 inrun->origin_y = origin_y - inrun->run->baseline;
1866 inrun = layout_get_next_inline_run(layout, inrun);
1869 layout->metrics.height += layout->lines[line].height;
1872 /* initial alignment is always leading */
1873 if (layout->format.textalignment != DWRITE_TEXT_ALIGNMENT_LEADING)
1874 layout_apply_text_alignment(layout);
1876 /* initial paragraph alignment is always near */
1877 if (layout->format.paralign != DWRITE_PARAGRAPH_ALIGNMENT_NEAR)
1878 layout_apply_par_alignment(layout);
1880 layout->metrics.heightIncludingTrailingWhitespace = layout->metrics.height; /* FIXME: not true for vertical text */
1882 layout->recompute &= ~RECOMPUTE_EFFECTIVE_RUNS;
1883 return hr;
1886 static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
1888 struct layout_range_spacing const *range_spacing = (struct layout_range_spacing*)h;
1889 struct layout_range_iface const *range_iface = (struct layout_range_iface*)h;
1890 struct layout_range_bool const *range_bool = (struct layout_range_bool*)h;
1891 struct layout_range const *range = (struct layout_range*)h;
1893 switch (attr) {
1894 case LAYOUT_RANGE_ATTR_WEIGHT:
1895 return range->weight == value->u.weight;
1896 case LAYOUT_RANGE_ATTR_STYLE:
1897 return range->style == value->u.style;
1898 case LAYOUT_RANGE_ATTR_STRETCH:
1899 return range->stretch == value->u.stretch;
1900 case LAYOUT_RANGE_ATTR_FONTSIZE:
1901 return range->fontsize == value->u.fontsize;
1902 case LAYOUT_RANGE_ATTR_INLINE:
1903 return range->object == value->u.object;
1904 case LAYOUT_RANGE_ATTR_EFFECT:
1905 return range_iface->iface == value->u.effect;
1906 case LAYOUT_RANGE_ATTR_UNDERLINE:
1907 return range_bool->value == value->u.underline;
1908 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
1909 return range_bool->value == value->u.strikethrough;
1910 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
1911 return range->pair_kerning == value->u.pair_kerning;
1912 case LAYOUT_RANGE_ATTR_FONTCOLL:
1913 return range->collection == value->u.collection;
1914 case LAYOUT_RANGE_ATTR_LOCALE:
1915 return strcmpiW(range->locale, value->u.locale) == 0;
1916 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1917 return strcmpW(range->fontfamily, value->u.fontfamily) == 0;
1918 case LAYOUT_RANGE_ATTR_SPACING:
1919 return range_spacing->leading == value->u.spacing[0] &&
1920 range_spacing->trailing == value->u.spacing[1] &&
1921 range_spacing->min_advance == value->u.spacing[2];
1922 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
1923 return range_iface->iface == (IUnknown*)value->u.typography;
1924 default:
1928 return FALSE;
1931 static inline BOOL is_same_layout_attributes(struct layout_range_header const *hleft, struct layout_range_header const *hright)
1933 switch (hleft->kind)
1935 case LAYOUT_RANGE_REGULAR:
1937 struct layout_range const *left = (struct layout_range const*)hleft;
1938 struct layout_range const *right = (struct layout_range const*)hright;
1939 return left->weight == right->weight &&
1940 left->style == right->style &&
1941 left->stretch == right->stretch &&
1942 left->fontsize == right->fontsize &&
1943 left->object == right->object &&
1944 left->pair_kerning == right->pair_kerning &&
1945 left->collection == right->collection &&
1946 !strcmpiW(left->locale, right->locale) &&
1947 !strcmpW(left->fontfamily, right->fontfamily);
1949 case LAYOUT_RANGE_UNDERLINE:
1950 case LAYOUT_RANGE_STRIKETHROUGH:
1952 struct layout_range_bool const *left = (struct layout_range_bool const*)hleft;
1953 struct layout_range_bool const *right = (struct layout_range_bool const*)hright;
1954 return left->value == right->value;
1956 case LAYOUT_RANGE_EFFECT:
1957 case LAYOUT_RANGE_TYPOGRAPHY:
1959 struct layout_range_iface const *left = (struct layout_range_iface const*)hleft;
1960 struct layout_range_iface const *right = (struct layout_range_iface const*)hright;
1961 return left->iface == right->iface;
1963 case LAYOUT_RANGE_SPACING:
1965 struct layout_range_spacing const *left = (struct layout_range_spacing const*)hleft;
1966 struct layout_range_spacing const *right = (struct layout_range_spacing const*)hright;
1967 return left->leading == right->leading &&
1968 left->trailing == right->trailing &&
1969 left->min_advance == right->min_advance;
1971 default:
1972 FIXME("unknown range kind %d\n", hleft->kind);
1973 return FALSE;
1977 static inline BOOL is_same_text_range(const DWRITE_TEXT_RANGE *left, const DWRITE_TEXT_RANGE *right)
1979 return left->startPosition == right->startPosition && left->length == right->length;
1982 /* Allocates range and inits it with default values from text format. */
1983 static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout *layout, const DWRITE_TEXT_RANGE *r,
1984 enum layout_range_kind kind)
1986 struct layout_range_header *h;
1988 switch (kind)
1990 case LAYOUT_RANGE_REGULAR:
1992 struct layout_range *range;
1994 range = heap_alloc(sizeof(*range));
1995 if (!range) return NULL;
1997 range->weight = layout->format.weight;
1998 range->style = layout->format.style;
1999 range->stretch = layout->format.stretch;
2000 range->fontsize = layout->format.fontsize;
2001 range->object = NULL;
2002 range->pair_kerning = FALSE;
2004 range->fontfamily = heap_strdupW(layout->format.family_name);
2005 if (!range->fontfamily) {
2006 heap_free(range);
2007 return NULL;
2010 range->collection = layout->format.collection;
2011 if (range->collection)
2012 IDWriteFontCollection_AddRef(range->collection);
2013 strcpyW(range->locale, layout->format.locale);
2015 h = &range->h;
2016 break;
2018 case LAYOUT_RANGE_UNDERLINE:
2019 case LAYOUT_RANGE_STRIKETHROUGH:
2021 struct layout_range_bool *range;
2023 range = heap_alloc(sizeof(*range));
2024 if (!range) return NULL;
2026 range->value = FALSE;
2027 h = &range->h;
2028 break;
2030 case LAYOUT_RANGE_EFFECT:
2031 case LAYOUT_RANGE_TYPOGRAPHY:
2033 struct layout_range_iface *range;
2035 range = heap_alloc(sizeof(*range));
2036 if (!range) return NULL;
2038 range->iface = NULL;
2039 h = &range->h;
2040 break;
2042 case LAYOUT_RANGE_SPACING:
2044 struct layout_range_spacing *range;
2046 range = heap_alloc(sizeof(*range));
2047 if (!range) return NULL;
2049 range->leading = 0.0f;
2050 range->trailing = 0.0f;
2051 range->min_advance = 0.0f;
2052 h = &range->h;
2053 break;
2055 default:
2056 FIXME("unknown range kind %d\n", kind);
2057 return NULL;
2060 h->kind = kind;
2061 h->range = *r;
2062 return h;
2065 static struct layout_range_header *alloc_layout_range_from(struct layout_range_header *h, const DWRITE_TEXT_RANGE *r)
2067 struct layout_range_header *ret;
2069 switch (h->kind)
2071 case LAYOUT_RANGE_REGULAR:
2073 struct layout_range *from = (struct layout_range*)h;
2075 struct layout_range *range = heap_alloc(sizeof(*range));
2076 if (!range) return NULL;
2078 *range = *from;
2079 range->fontfamily = heap_strdupW(from->fontfamily);
2080 if (!range->fontfamily) {
2081 heap_free(range);
2082 return NULL;
2085 /* update refcounts */
2086 if (range->object)
2087 IDWriteInlineObject_AddRef(range->object);
2088 if (range->collection)
2089 IDWriteFontCollection_AddRef(range->collection);
2090 ret = &range->h;
2091 break;
2093 case LAYOUT_RANGE_UNDERLINE:
2094 case LAYOUT_RANGE_STRIKETHROUGH:
2096 struct layout_range_bool *strike = heap_alloc(sizeof(*strike));
2097 if (!strike) return NULL;
2099 *strike = *(struct layout_range_bool*)h;
2100 ret = &strike->h;
2101 break;
2103 case LAYOUT_RANGE_EFFECT:
2104 case LAYOUT_RANGE_TYPOGRAPHY:
2106 struct layout_range_iface *effect = heap_alloc(sizeof(*effect));
2107 if (!effect) return NULL;
2109 *effect = *(struct layout_range_iface*)h;
2110 if (effect->iface)
2111 IUnknown_AddRef(effect->iface);
2112 ret = &effect->h;
2113 break;
2115 case LAYOUT_RANGE_SPACING:
2117 struct layout_range_spacing *spacing = heap_alloc(sizeof(*spacing));
2118 if (!spacing) return NULL;
2120 *spacing = *(struct layout_range_spacing*)h;
2121 ret = &spacing->h;
2122 break;
2124 default:
2125 FIXME("unknown range kind %d\n", h->kind);
2126 return NULL;
2129 ret->range = *r;
2130 return ret;
2133 static void free_layout_range(struct layout_range_header *h)
2135 if (!h)
2136 return;
2138 switch (h->kind)
2140 case LAYOUT_RANGE_REGULAR:
2142 struct layout_range *range = (struct layout_range*)h;
2144 if (range->object)
2145 IDWriteInlineObject_Release(range->object);
2146 if (range->collection)
2147 IDWriteFontCollection_Release(range->collection);
2148 heap_free(range->fontfamily);
2149 break;
2151 case LAYOUT_RANGE_EFFECT:
2152 case LAYOUT_RANGE_TYPOGRAPHY:
2154 struct layout_range_iface *range = (struct layout_range_iface*)h;
2155 if (range->iface)
2156 IUnknown_Release(range->iface);
2157 break;
2159 default:
2163 heap_free(h);
2166 static void free_layout_ranges_list(struct dwrite_textlayout *layout)
2168 struct layout_range_header *cur, *cur2;
2170 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->ranges, struct layout_range_header, entry) {
2171 list_remove(&cur->entry);
2172 free_layout_range(cur);
2175 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->underline_ranges, struct layout_range_header, entry) {
2176 list_remove(&cur->entry);
2177 free_layout_range(cur);
2180 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->strike_ranges, struct layout_range_header, entry) {
2181 list_remove(&cur->entry);
2182 free_layout_range(cur);
2185 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->effects, struct layout_range_header, entry) {
2186 list_remove(&cur->entry);
2187 free_layout_range(cur);
2190 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->spacing, struct layout_range_header, entry) {
2191 list_remove(&cur->entry);
2192 free_layout_range(cur);
2195 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->typographies, struct layout_range_header, entry) {
2196 list_remove(&cur->entry);
2197 free_layout_range(cur);
2201 static struct layout_range_header *find_outer_range(struct list *ranges, const DWRITE_TEXT_RANGE *range)
2203 struct layout_range_header *cur;
2205 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
2207 if (cur->range.startPosition > range->startPosition)
2208 return NULL;
2210 if ((cur->range.startPosition + cur->range.length < range->startPosition + range->length) &&
2211 (range->startPosition < cur->range.startPosition + cur->range.length))
2212 return NULL;
2213 if (cur->range.startPosition + cur->range.length >= range->startPosition + range->length)
2214 return cur;
2217 return NULL;
2220 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos)
2222 struct layout_range *cur;
2224 LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, h.entry) {
2225 DWRITE_TEXT_RANGE *r = &cur->h.range;
2226 if (r->startPosition <= pos && pos < r->startPosition + r->length)
2227 return cur;
2230 return NULL;
2233 static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
2235 if (*dest == value) return FALSE;
2237 if (*dest)
2238 IUnknown_Release(*dest);
2239 *dest = value;
2240 if (*dest)
2241 IUnknown_AddRef(*dest);
2243 return TRUE;
2246 static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2248 struct layout_range_spacing *dest_spacing = (struct layout_range_spacing*)h;
2249 struct layout_range_iface *dest_iface = (struct layout_range_iface*)h;
2250 struct layout_range_bool *dest_bool = (struct layout_range_bool*)h;
2251 struct layout_range *dest = (struct layout_range*)h;
2253 BOOL changed = FALSE;
2255 switch (attr) {
2256 case LAYOUT_RANGE_ATTR_WEIGHT:
2257 changed = dest->weight != value->u.weight;
2258 dest->weight = value->u.weight;
2259 break;
2260 case LAYOUT_RANGE_ATTR_STYLE:
2261 changed = dest->style != value->u.style;
2262 dest->style = value->u.style;
2263 break;
2264 case LAYOUT_RANGE_ATTR_STRETCH:
2265 changed = dest->stretch != value->u.stretch;
2266 dest->stretch = value->u.stretch;
2267 break;
2268 case LAYOUT_RANGE_ATTR_FONTSIZE:
2269 changed = dest->fontsize != value->u.fontsize;
2270 dest->fontsize = value->u.fontsize;
2271 break;
2272 case LAYOUT_RANGE_ATTR_INLINE:
2273 changed = set_layout_range_iface_attr((IUnknown**)&dest->object, (IUnknown*)value->u.object);
2274 break;
2275 case LAYOUT_RANGE_ATTR_EFFECT:
2276 changed = set_layout_range_iface_attr((IUnknown**)&dest_iface->iface, (IUnknown*)value->u.effect);
2277 break;
2278 case LAYOUT_RANGE_ATTR_UNDERLINE:
2279 changed = dest_bool->value != value->u.underline;
2280 dest_bool->value = value->u.underline;
2281 break;
2282 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2283 changed = dest_bool->value != value->u.strikethrough;
2284 dest_bool->value = value->u.strikethrough;
2285 break;
2286 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2287 changed = dest->pair_kerning != value->u.pair_kerning;
2288 dest->pair_kerning = value->u.pair_kerning;
2289 break;
2290 case LAYOUT_RANGE_ATTR_FONTCOLL:
2291 changed = set_layout_range_iface_attr((IUnknown**)&dest->collection, (IUnknown*)value->u.collection);
2292 break;
2293 case LAYOUT_RANGE_ATTR_LOCALE:
2294 changed = strcmpiW(dest->locale, value->u.locale) != 0;
2295 if (changed) {
2296 strcpyW(dest->locale, value->u.locale);
2297 strlwrW(dest->locale);
2299 break;
2300 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2301 changed = strcmpW(dest->fontfamily, value->u.fontfamily) != 0;
2302 if (changed) {
2303 heap_free(dest->fontfamily);
2304 dest->fontfamily = heap_strdupW(value->u.fontfamily);
2306 break;
2307 case LAYOUT_RANGE_ATTR_SPACING:
2308 changed = dest_spacing->leading != value->u.spacing[0] ||
2309 dest_spacing->trailing != value->u.spacing[1] ||
2310 dest_spacing->min_advance != value->u.spacing[2];
2311 dest_spacing->leading = value->u.spacing[0];
2312 dest_spacing->trailing = value->u.spacing[1];
2313 dest_spacing->min_advance = value->u.spacing[2];
2314 break;
2315 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2316 changed = set_layout_range_iface_attr((IUnknown**)&dest_iface->iface, (IUnknown*)value->u.typography);
2317 break;
2318 default:
2322 return changed;
2325 static inline BOOL is_in_layout_range(const DWRITE_TEXT_RANGE *outer, const DWRITE_TEXT_RANGE *inner)
2327 return (inner->startPosition >= outer->startPosition) &&
2328 (inner->startPosition + inner->length <= outer->startPosition + outer->length);
2331 static inline HRESULT return_range(const struct layout_range_header *h, DWRITE_TEXT_RANGE *r)
2333 if (r) *r = h->range;
2334 return S_OK;
2337 /* Sets attribute value for given range, does all needed splitting/merging of existing ranges. */
2338 static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2340 struct layout_range_header *cur, *right, *left, *outer;
2341 BOOL changed = FALSE;
2342 struct list *ranges;
2343 DWRITE_TEXT_RANGE r;
2345 /* ignore zero length ranges */
2346 if (value->range.length == 0)
2347 return S_OK;
2349 /* select from ranges lists */
2350 switch (attr)
2352 case LAYOUT_RANGE_ATTR_WEIGHT:
2353 case LAYOUT_RANGE_ATTR_STYLE:
2354 case LAYOUT_RANGE_ATTR_STRETCH:
2355 case LAYOUT_RANGE_ATTR_FONTSIZE:
2356 case LAYOUT_RANGE_ATTR_INLINE:
2357 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2358 case LAYOUT_RANGE_ATTR_FONTCOLL:
2359 case LAYOUT_RANGE_ATTR_LOCALE:
2360 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2361 ranges = &layout->ranges;
2362 break;
2363 case LAYOUT_RANGE_ATTR_UNDERLINE:
2364 ranges = &layout->underline_ranges;
2365 break;
2366 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2367 ranges = &layout->strike_ranges;
2368 break;
2369 case LAYOUT_RANGE_ATTR_EFFECT:
2370 ranges = &layout->effects;
2371 break;
2372 case LAYOUT_RANGE_ATTR_SPACING:
2373 ranges = &layout->spacing;
2374 break;
2375 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2376 ranges = &layout->typographies;
2377 break;
2378 default:
2379 FIXME("unknown attr kind %d\n", attr);
2380 return E_FAIL;
2383 /* If new range is completely within existing range, split existing range in two */
2384 if ((outer = find_outer_range(ranges, &value->range))) {
2386 /* no need to add same range */
2387 if (is_same_layout_attrvalue(outer, attr, value))
2388 return S_OK;
2390 /* for matching range bounds just replace data */
2391 if (is_same_text_range(&outer->range, &value->range)) {
2392 changed = set_layout_range_attrval(outer, attr, value);
2393 goto done;
2396 /* add new range to the left */
2397 if (value->range.startPosition == outer->range.startPosition) {
2398 left = alloc_layout_range_from(outer, &value->range);
2399 if (!left) return E_OUTOFMEMORY;
2401 changed = set_layout_range_attrval(left, attr, value);
2402 list_add_before(&outer->entry, &left->entry);
2403 outer->range.startPosition += value->range.length;
2404 outer->range.length -= value->range.length;
2405 goto done;
2408 /* add new range to the right */
2409 if (value->range.startPosition + value->range.length == outer->range.startPosition + outer->range.length) {
2410 right = alloc_layout_range_from(outer, &value->range);
2411 if (!right) return E_OUTOFMEMORY;
2413 changed = set_layout_range_attrval(right, attr, value);
2414 list_add_after(&outer->entry, &right->entry);
2415 outer->range.length -= value->range.length;
2416 goto done;
2419 r.startPosition = value->range.startPosition + value->range.length;
2420 r.length = outer->range.length + outer->range.startPosition - r.startPosition;
2422 /* right part */
2423 right = alloc_layout_range_from(outer, &r);
2424 /* new range in the middle */
2425 cur = alloc_layout_range_from(outer, &value->range);
2426 if (!right || !cur) {
2427 free_layout_range(right);
2428 free_layout_range(cur);
2429 return E_OUTOFMEMORY;
2432 /* reuse container range as a left part */
2433 outer->range.length = value->range.startPosition - outer->range.startPosition;
2435 /* new part */
2436 set_layout_range_attrval(cur, attr, value);
2438 list_add_after(&outer->entry, &cur->entry);
2439 list_add_after(&cur->entry, &right->entry);
2441 layout->recompute = RECOMPUTE_EVERYTHING;
2442 return S_OK;
2445 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2446 Update all of them. */
2447 left = get_layout_range_header_by_pos(ranges, value->range.startPosition);
2448 if (left->range.startPosition == value->range.startPosition)
2449 changed = set_layout_range_attrval(left, attr, value);
2450 else /* need to split */ {
2451 r.startPosition = value->range.startPosition;
2452 r.length = left->range.length - value->range.startPosition + left->range.startPosition;
2453 left->range.length -= r.length;
2454 cur = alloc_layout_range_from(left, &r);
2455 changed = set_layout_range_attrval(cur, attr, value);
2456 list_add_after(&left->entry, &cur->entry);
2458 cur = LIST_ENTRY(list_next(ranges, &left->entry), struct layout_range_header, entry);
2460 /* for all existing ranges covered by new one update value */
2461 while (cur && is_in_layout_range(&value->range, &cur->range)) {
2462 changed |= set_layout_range_attrval(cur, attr, value);
2463 cur = LIST_ENTRY(list_next(ranges, &cur->entry), struct layout_range_header, entry);
2466 /* it's possible rightmost range intersects */
2467 if (cur && (cur->range.startPosition < value->range.startPosition + value->range.length)) {
2468 r.startPosition = cur->range.startPosition;
2469 r.length = value->range.startPosition + value->range.length - cur->range.startPosition;
2470 left = alloc_layout_range_from(cur, &r);
2471 changed |= set_layout_range_attrval(left, attr, value);
2472 cur->range.startPosition += left->range.length;
2473 cur->range.length -= left->range.length;
2474 list_add_before(&cur->entry, &left->entry);
2477 done:
2478 if (changed) {
2479 struct list *next, *i;
2481 layout->recompute = RECOMPUTE_EVERYTHING;
2482 i = list_head(ranges);
2483 while ((next = list_next(ranges, i))) {
2484 struct layout_range_header *next_range = LIST_ENTRY(next, struct layout_range_header, entry);
2486 cur = LIST_ENTRY(i, struct layout_range_header, entry);
2487 if (is_same_layout_attributes(cur, next_range)) {
2488 /* remove similar range */
2489 cur->range.length += next_range->range.length;
2490 list_remove(next);
2491 free_layout_range(next_range);
2493 else
2494 i = list_next(ranges, i);
2498 return S_OK;
2501 static inline const WCHAR *get_string_attribute_ptr(struct layout_range *range, enum layout_range_attr_kind kind)
2503 const WCHAR *str;
2505 switch (kind) {
2506 case LAYOUT_RANGE_ATTR_LOCALE:
2507 str = range->locale;
2508 break;
2509 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2510 str = range->fontfamily;
2511 break;
2512 default:
2513 str = NULL;
2516 return str;
2519 static HRESULT get_string_attribute_length(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2520 UINT32 *length, DWRITE_TEXT_RANGE *r)
2522 struct layout_range *range;
2523 const WCHAR *str;
2525 range = get_layout_range_by_pos(layout, position);
2526 if (!range) {
2527 *length = 0;
2528 return S_OK;
2531 str = get_string_attribute_ptr(range, kind);
2532 *length = strlenW(str);
2533 return return_range(&range->h, r);
2536 static HRESULT get_string_attribute_value(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2537 WCHAR *ret, UINT32 length, DWRITE_TEXT_RANGE *r)
2539 struct layout_range *range;
2540 const WCHAR *str;
2542 if (length == 0)
2543 return E_INVALIDARG;
2545 ret[0] = 0;
2546 range = get_layout_range_by_pos(layout, position);
2547 if (!range)
2548 return E_INVALIDARG;
2550 str = get_string_attribute_ptr(range, kind);
2551 if (length < strlenW(str) + 1)
2552 return E_NOT_SUFFICIENT_BUFFER;
2554 strcpyW(ret, str);
2555 return return_range(&range->h, r);
2558 static HRESULT WINAPI dwritetextlayout_QueryInterface(IDWriteTextLayout3 *iface, REFIID riid, void **obj)
2560 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2562 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2564 *obj = NULL;
2566 if (IsEqualIID(riid, &IID_IDWriteTextLayout3) ||
2567 IsEqualIID(riid, &IID_IDWriteTextLayout2) ||
2568 IsEqualIID(riid, &IID_IDWriteTextLayout1) ||
2569 IsEqualIID(riid, &IID_IDWriteTextLayout) ||
2570 IsEqualIID(riid, &IID_IUnknown))
2572 *obj = iface;
2574 else if (IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
2575 IsEqualIID(riid, &IID_IDWriteTextFormat))
2576 *obj = &This->IDWriteTextFormat1_iface;
2578 if (*obj) {
2579 IDWriteTextLayout3_AddRef(iface);
2580 return S_OK;
2583 return E_NOINTERFACE;
2586 static ULONG WINAPI dwritetextlayout_AddRef(IDWriteTextLayout3 *iface)
2588 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2589 ULONG ref = InterlockedIncrement(&This->ref);
2590 TRACE("(%p)->(%d)\n", This, ref);
2591 return ref;
2594 static ULONG WINAPI dwritetextlayout_Release(IDWriteTextLayout3 *iface)
2596 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2597 ULONG ref = InterlockedDecrement(&This->ref);
2599 TRACE("(%p)->(%d)\n", This, ref);
2601 if (!ref) {
2602 IDWriteFactory2_Release(This->factory);
2603 free_layout_ranges_list(This);
2604 free_layout_eruns(This);
2605 free_layout_runs(This);
2606 release_format_data(&This->format);
2607 heap_free(This->nominal_breakpoints);
2608 heap_free(This->actual_breakpoints);
2609 heap_free(This->clustermetrics);
2610 heap_free(This->clusters);
2611 heap_free(This->lines);
2612 heap_free(This->str);
2613 heap_free(This);
2616 return ref;
2619 static HRESULT WINAPI dwritetextlayout_SetTextAlignment(IDWriteTextLayout3 *iface, DWRITE_TEXT_ALIGNMENT alignment)
2621 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2622 return IDWriteTextFormat1_SetTextAlignment(&This->IDWriteTextFormat1_iface, alignment);
2625 static HRESULT WINAPI dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout3 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
2627 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2628 return IDWriteTextFormat1_SetParagraphAlignment(&This->IDWriteTextFormat1_iface, alignment);
2631 static HRESULT WINAPI dwritetextlayout_SetWordWrapping(IDWriteTextLayout3 *iface, DWRITE_WORD_WRAPPING wrapping)
2633 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2634 return IDWriteTextFormat1_SetWordWrapping(&This->IDWriteTextFormat1_iface, wrapping);
2637 static HRESULT WINAPI dwritetextlayout_SetReadingDirection(IDWriteTextLayout3 *iface, DWRITE_READING_DIRECTION direction)
2639 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2640 return IDWriteTextFormat1_SetReadingDirection(&This->IDWriteTextFormat1_iface, direction);
2643 static HRESULT WINAPI dwritetextlayout_SetFlowDirection(IDWriteTextLayout3 *iface, DWRITE_FLOW_DIRECTION direction)
2645 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2646 TRACE("(%p)->(%d)\n", This, direction);
2647 return IDWriteTextFormat1_SetFlowDirection(&This->IDWriteTextFormat1_iface, direction);
2650 static HRESULT WINAPI dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout3 *iface, FLOAT tabstop)
2652 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2653 TRACE("(%p)->(%.2f)\n", This, tabstop);
2654 return IDWriteTextFormat1_SetIncrementalTabStop(&This->IDWriteTextFormat1_iface, tabstop);
2657 static HRESULT WINAPI dwritetextlayout_SetTrimming(IDWriteTextLayout3 *iface, DWRITE_TRIMMING const *trimming,
2658 IDWriteInlineObject *trimming_sign)
2660 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2661 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
2662 return IDWriteTextFormat1_SetTrimming(&This->IDWriteTextFormat1_iface, trimming, trimming_sign);
2665 static HRESULT WINAPI dwritetextlayout_SetLineSpacing(IDWriteTextLayout3 *iface, DWRITE_LINE_SPACING_METHOD spacing,
2666 FLOAT line_spacing, FLOAT baseline)
2668 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2669 TRACE("(%p)->(%d %.2f %.2f)\n", This, spacing, line_spacing, baseline);
2670 return IDWriteTextFormat1_SetLineSpacing(&This->IDWriteTextFormat1_iface, spacing, line_spacing, baseline);
2673 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextlayout_GetTextAlignment(IDWriteTextLayout3 *iface)
2675 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2676 return IDWriteTextFormat1_GetTextAlignment(&This->IDWriteTextFormat1_iface);
2679 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout3 *iface)
2681 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2682 return IDWriteTextFormat1_GetParagraphAlignment(&This->IDWriteTextFormat1_iface);
2685 static DWRITE_WORD_WRAPPING WINAPI dwritetextlayout_GetWordWrapping(IDWriteTextLayout3 *iface)
2687 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2688 return IDWriteTextFormat1_GetWordWrapping(&This->IDWriteTextFormat1_iface);
2691 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_GetReadingDirection(IDWriteTextLayout3 *iface)
2693 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2694 return IDWriteTextFormat1_GetReadingDirection(&This->IDWriteTextFormat1_iface);
2697 static DWRITE_FLOW_DIRECTION WINAPI dwritetextlayout_GetFlowDirection(IDWriteTextLayout3 *iface)
2699 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2700 return IDWriteTextFormat1_GetFlowDirection(&This->IDWriteTextFormat1_iface);
2703 static FLOAT WINAPI dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout3 *iface)
2705 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2706 return IDWriteTextFormat1_GetIncrementalTabStop(&This->IDWriteTextFormat1_iface);
2709 static HRESULT WINAPI dwritetextlayout_GetTrimming(IDWriteTextLayout3 *iface, DWRITE_TRIMMING *options,
2710 IDWriteInlineObject **trimming_sign)
2712 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2713 return IDWriteTextFormat1_GetTrimming(&This->IDWriteTextFormat1_iface, options, trimming_sign);
2716 static HRESULT WINAPI dwritetextlayout_GetLineSpacing(IDWriteTextLayout3 *iface, DWRITE_LINE_SPACING_METHOD *method,
2717 FLOAT *spacing, FLOAT *baseline)
2719 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2720 return IDWriteTextFormat_GetLineSpacing((IDWriteTextFormat*)&This->IDWriteTextFormat1_iface, method, spacing, baseline);
2723 static HRESULT WINAPI dwritetextlayout_GetFontCollection(IDWriteTextLayout3 *iface, IDWriteFontCollection **collection)
2725 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2726 return IDWriteTextFormat1_GetFontCollection(&This->IDWriteTextFormat1_iface, collection);
2729 static UINT32 WINAPI dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout3 *iface)
2731 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2732 return IDWriteTextFormat1_GetFontFamilyNameLength(&This->IDWriteTextFormat1_iface);
2735 static HRESULT WINAPI dwritetextlayout_GetFontFamilyName(IDWriteTextLayout3 *iface, WCHAR *name, UINT32 size)
2737 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2738 return IDWriteTextFormat1_GetFontFamilyName(&This->IDWriteTextFormat1_iface, name, size);
2741 static DWRITE_FONT_WEIGHT WINAPI dwritetextlayout_GetFontWeight(IDWriteTextLayout3 *iface)
2743 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2744 return IDWriteTextFormat1_GetFontWeight(&This->IDWriteTextFormat1_iface);
2747 static DWRITE_FONT_STYLE WINAPI dwritetextlayout_GetFontStyle(IDWriteTextLayout3 *iface)
2749 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2750 return IDWriteTextFormat1_GetFontStyle(&This->IDWriteTextFormat1_iface);
2753 static DWRITE_FONT_STRETCH WINAPI dwritetextlayout_GetFontStretch(IDWriteTextLayout3 *iface)
2755 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2756 return IDWriteTextFormat1_GetFontStretch(&This->IDWriteTextFormat1_iface);
2759 static FLOAT WINAPI dwritetextlayout_GetFontSize(IDWriteTextLayout3 *iface)
2761 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2762 return IDWriteTextFormat1_GetFontSize(&This->IDWriteTextFormat1_iface);
2765 static UINT32 WINAPI dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout3 *iface)
2767 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2768 return IDWriteTextFormat1_GetLocaleNameLength(&This->IDWriteTextFormat1_iface);
2771 static HRESULT WINAPI dwritetextlayout_GetLocaleName(IDWriteTextLayout3 *iface, WCHAR *name, UINT32 size)
2773 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2774 return IDWriteTextFormat1_GetLocaleName(&This->IDWriteTextFormat1_iface, name, size);
2777 static HRESULT WINAPI dwritetextlayout_SetMaxWidth(IDWriteTextLayout3 *iface, FLOAT maxWidth)
2779 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2781 TRACE("(%p)->(%.2f)\n", This, maxWidth);
2783 if (maxWidth < 0.0f)
2784 return E_INVALIDARG;
2786 This->metrics.layoutWidth = maxWidth;
2787 return S_OK;
2790 static HRESULT WINAPI dwritetextlayout_SetMaxHeight(IDWriteTextLayout3 *iface, FLOAT maxHeight)
2792 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2794 TRACE("(%p)->(%.2f)\n", This, maxHeight);
2796 if (maxHeight < 0.0f)
2797 return E_INVALIDARG;
2799 This->metrics.layoutHeight = maxHeight;
2800 return S_OK;
2803 static HRESULT WINAPI dwritetextlayout_SetFontCollection(IDWriteTextLayout3 *iface, IDWriteFontCollection* collection, DWRITE_TEXT_RANGE range)
2805 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2806 struct layout_range_attr_value value;
2808 TRACE("(%p)->(%p %s)\n", This, collection, debugstr_range(&range));
2810 value.range = range;
2811 value.u.collection = collection;
2812 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTCOLL, &value);
2815 static HRESULT WINAPI dwritetextlayout_SetFontFamilyName(IDWriteTextLayout3 *iface, WCHAR const *name, DWRITE_TEXT_RANGE range)
2817 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2818 struct layout_range_attr_value value;
2820 TRACE("(%p)->(%s %s)\n", This, debugstr_w(name), debugstr_range(&range));
2822 if (!name)
2823 return E_INVALIDARG;
2825 value.range = range;
2826 value.u.fontfamily = name;
2827 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTFAMILY, &value);
2830 static HRESULT WINAPI dwritetextlayout_SetFontWeight(IDWriteTextLayout3 *iface, DWRITE_FONT_WEIGHT weight, DWRITE_TEXT_RANGE range)
2832 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2833 struct layout_range_attr_value value;
2835 TRACE("(%p)->(%d %s)\n", This, weight, debugstr_range(&range));
2837 value.range = range;
2838 value.u.weight = weight;
2839 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_WEIGHT, &value);
2842 static HRESULT WINAPI dwritetextlayout_SetFontStyle(IDWriteTextLayout3 *iface, DWRITE_FONT_STYLE style, DWRITE_TEXT_RANGE range)
2844 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2845 struct layout_range_attr_value value;
2847 TRACE("(%p)->(%d %s)\n", This, style, debugstr_range(&range));
2849 if ((UINT32)style > DWRITE_FONT_STYLE_ITALIC)
2850 return E_INVALIDARG;
2852 value.range = range;
2853 value.u.style = style;
2854 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STYLE, &value);
2857 static HRESULT WINAPI dwritetextlayout_SetFontStretch(IDWriteTextLayout3 *iface, DWRITE_FONT_STRETCH stretch, DWRITE_TEXT_RANGE range)
2859 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2860 struct layout_range_attr_value value;
2862 TRACE("(%p)->(%d %s)\n", This, stretch, debugstr_range(&range));
2864 if (stretch == DWRITE_FONT_STRETCH_UNDEFINED || (UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
2865 return E_INVALIDARG;
2867 value.range = range;
2868 value.u.stretch = stretch;
2869 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRETCH, &value);
2872 static HRESULT WINAPI dwritetextlayout_SetFontSize(IDWriteTextLayout3 *iface, FLOAT size, DWRITE_TEXT_RANGE range)
2874 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2875 struct layout_range_attr_value value;
2877 TRACE("(%p)->(%.2f %s)\n", This, size, debugstr_range(&range));
2879 if (size <= 0.0f)
2880 return E_INVALIDARG;
2882 value.range = range;
2883 value.u.fontsize = size;
2884 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTSIZE, &value);
2887 static HRESULT WINAPI dwritetextlayout_SetUnderline(IDWriteTextLayout3 *iface, BOOL underline, DWRITE_TEXT_RANGE range)
2889 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2890 struct layout_range_attr_value value;
2892 TRACE("(%p)->(%d %s)\n", This, underline, debugstr_range(&range));
2894 value.range = range;
2895 value.u.underline = underline;
2896 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_UNDERLINE, &value);
2899 static HRESULT WINAPI dwritetextlayout_SetStrikethrough(IDWriteTextLayout3 *iface, BOOL strikethrough, DWRITE_TEXT_RANGE range)
2901 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2902 struct layout_range_attr_value value;
2904 TRACE("(%p)->(%d %s)\n", This, strikethrough, debugstr_range(&range));
2906 value.range = range;
2907 value.u.strikethrough = strikethrough;
2908 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRIKETHROUGH, &value);
2911 static HRESULT WINAPI dwritetextlayout_SetDrawingEffect(IDWriteTextLayout3 *iface, IUnknown* effect, DWRITE_TEXT_RANGE range)
2913 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2914 struct layout_range_attr_value value;
2916 TRACE("(%p)->(%p %s)\n", This, effect, debugstr_range(&range));
2918 value.range = range;
2919 value.u.effect = effect;
2920 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_EFFECT, &value);
2923 static HRESULT WINAPI dwritetextlayout_SetInlineObject(IDWriteTextLayout3 *iface, IDWriteInlineObject *object, DWRITE_TEXT_RANGE range)
2925 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2926 struct layout_range_attr_value value;
2928 TRACE("(%p)->(%p %s)\n", This, object, debugstr_range(&range));
2930 value.range = range;
2931 value.u.object = object;
2932 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_INLINE, &value);
2935 static HRESULT WINAPI dwritetextlayout_SetTypography(IDWriteTextLayout3 *iface, IDWriteTypography* typography, DWRITE_TEXT_RANGE range)
2937 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2938 struct layout_range_attr_value value;
2940 TRACE("(%p)->(%p %s)\n", This, typography, debugstr_range(&range));
2942 value.range = range;
2943 value.u.typography = typography;
2944 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_TYPOGRAPHY, &value);
2947 static HRESULT WINAPI dwritetextlayout_SetLocaleName(IDWriteTextLayout3 *iface, WCHAR const* locale, DWRITE_TEXT_RANGE range)
2949 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2950 struct layout_range_attr_value value;
2952 TRACE("(%p)->(%s %s)\n", This, debugstr_w(locale), debugstr_range(&range));
2954 if (!locale || strlenW(locale) > LOCALE_NAME_MAX_LENGTH-1)
2955 return E_INVALIDARG;
2957 value.range = range;
2958 value.u.locale = locale;
2959 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_LOCALE, &value);
2962 static FLOAT WINAPI dwritetextlayout_GetMaxWidth(IDWriteTextLayout3 *iface)
2964 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2965 TRACE("(%p)\n", This);
2966 return This->metrics.layoutWidth;
2969 static FLOAT WINAPI dwritetextlayout_GetMaxHeight(IDWriteTextLayout3 *iface)
2971 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2972 TRACE("(%p)\n", This);
2973 return This->metrics.layoutHeight;
2976 static HRESULT WINAPI dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout3 *iface, UINT32 position,
2977 IDWriteFontCollection** collection, DWRITE_TEXT_RANGE *r)
2979 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2980 struct layout_range *range;
2982 TRACE("(%p)->(%u %p %p)\n", This, position, collection, r);
2984 if (position >= This->len)
2985 return S_OK;
2987 range = get_layout_range_by_pos(This, position);
2988 *collection = range->collection;
2989 if (*collection)
2990 IDWriteFontCollection_AddRef(*collection);
2992 return return_range(&range->h, r);
2995 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout3 *iface,
2996 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
2998 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2999 TRACE("(%p)->(%d %p %p)\n", This, position, length, r);
3000 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, length, r);
3003 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout3 *iface,
3004 UINT32 position, WCHAR *name, UINT32 length, DWRITE_TEXT_RANGE *r)
3006 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3007 TRACE("(%p)->(%u %p %u %p)\n", This, position, name, length, r);
3008 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, name, length, r);
3011 static HRESULT WINAPI dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout3 *iface,
3012 UINT32 position, DWRITE_FONT_WEIGHT *weight, DWRITE_TEXT_RANGE *r)
3014 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3015 struct layout_range *range;
3017 TRACE("(%p)->(%u %p %p)\n", This, position, weight, r);
3019 if (position >= This->len)
3020 return S_OK;
3022 range = get_layout_range_by_pos(This, position);
3023 *weight = range->weight;
3025 return return_range(&range->h, r);
3028 static HRESULT WINAPI dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout3 *iface,
3029 UINT32 position, DWRITE_FONT_STYLE *style, DWRITE_TEXT_RANGE *r)
3031 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3032 struct layout_range *range;
3034 TRACE("(%p)->(%u %p %p)\n", This, position, style, r);
3036 range = get_layout_range_by_pos(This, position);
3037 *style = range->style;
3038 return return_range(&range->h, r);
3041 static HRESULT WINAPI dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout3 *iface,
3042 UINT32 position, DWRITE_FONT_STRETCH *stretch, DWRITE_TEXT_RANGE *r)
3044 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3045 struct layout_range *range;
3047 TRACE("(%p)->(%u %p %p)\n", This, position, stretch, r);
3049 range = get_layout_range_by_pos(This, position);
3050 *stretch = range->stretch;
3051 return return_range(&range->h, r);
3054 static HRESULT WINAPI dwritetextlayout_layout_GetFontSize(IDWriteTextLayout3 *iface,
3055 UINT32 position, FLOAT *size, DWRITE_TEXT_RANGE *r)
3057 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3058 struct layout_range *range;
3060 TRACE("(%p)->(%u %p %p)\n", This, position, size, r);
3062 range = get_layout_range_by_pos(This, position);
3063 *size = range->fontsize;
3064 return return_range(&range->h, r);
3067 static HRESULT WINAPI dwritetextlayout_GetUnderline(IDWriteTextLayout3 *iface,
3068 UINT32 position, BOOL *underline, DWRITE_TEXT_RANGE *r)
3070 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3071 struct layout_range_bool *range;
3073 TRACE("(%p)->(%u %p %p)\n", This, position, underline, r);
3075 range = (struct layout_range_bool*)get_layout_range_header_by_pos(&This->underline_ranges, position);
3076 *underline = range->value;
3078 return return_range(&range->h, r);
3081 static HRESULT WINAPI dwritetextlayout_GetStrikethrough(IDWriteTextLayout3 *iface,
3082 UINT32 position, BOOL *strikethrough, DWRITE_TEXT_RANGE *r)
3084 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3085 struct layout_range_bool *range;
3087 TRACE("(%p)->(%u %p %p)\n", This, position, strikethrough, r);
3089 range = (struct layout_range_bool*)get_layout_range_header_by_pos(&This->strike_ranges, position);
3090 *strikethrough = range->value;
3092 return return_range(&range->h, r);
3095 static HRESULT WINAPI dwritetextlayout_GetDrawingEffect(IDWriteTextLayout3 *iface,
3096 UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r)
3098 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3099 struct layout_range_iface *range;
3101 TRACE("(%p)->(%u %p %p)\n", This, position, effect, r);
3103 range = (struct layout_range_iface*)get_layout_range_header_by_pos(&This->effects, position);
3104 *effect = range->iface;
3105 if (*effect)
3106 IUnknown_AddRef(*effect);
3108 return return_range(&range->h, r);
3111 static HRESULT WINAPI dwritetextlayout_GetInlineObject(IDWriteTextLayout3 *iface,
3112 UINT32 position, IDWriteInlineObject **object, DWRITE_TEXT_RANGE *r)
3114 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3115 struct layout_range *range;
3117 TRACE("(%p)->(%u %p %p)\n", This, position, object, r);
3119 if (position >= This->len)
3120 return S_OK;
3122 range = get_layout_range_by_pos(This, position);
3123 *object = range->object;
3124 if (*object)
3125 IDWriteInlineObject_AddRef(*object);
3127 return return_range(&range->h, r);
3130 static HRESULT WINAPI dwritetextlayout_GetTypography(IDWriteTextLayout3 *iface,
3131 UINT32 position, IDWriteTypography** typography, DWRITE_TEXT_RANGE *r)
3133 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3134 struct layout_range_iface *range;
3136 TRACE("(%p)->(%u %p %p)\n", This, position, typography, r);
3138 range = (struct layout_range_iface*)get_layout_range_header_by_pos(&This->typographies, position);
3139 *typography = (IDWriteTypography*)range->iface;
3140 if (*typography)
3141 IDWriteTypography_AddRef(*typography);
3143 return return_range(&range->h, r);
3146 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout3 *iface,
3147 UINT32 position, UINT32* length, DWRITE_TEXT_RANGE *r)
3149 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3150 TRACE("(%p)->(%u %p %p)\n", This, position, length, r);
3151 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_LOCALE, position, length, r);
3154 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout3 *iface,
3155 UINT32 position, WCHAR* locale, UINT32 length, DWRITE_TEXT_RANGE *r)
3157 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3158 TRACE("(%p)->(%u %p %u %p)\n", This, position, locale, length, r);
3159 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_LOCALE, position, locale, length, r);
3162 static inline FLOAT renderer_apply_snapping(FLOAT coord, BOOL skiptransform, FLOAT ppdip, FLOAT det,
3163 const DWRITE_MATRIX *m)
3165 FLOAT vec[2], vec2[2];
3167 if (!skiptransform) {
3168 /* apply transform */
3169 vec[0] = 0.0f;
3170 vec[1] = coord * ppdip;
3172 vec2[0] = m->m11 * vec[0] + m->m21 * vec[1] + m->dx;
3173 vec2[1] = m->m12 * vec[0] + m->m22 * vec[1] + m->dy;
3175 /* snap */
3176 vec2[0] = floorf(vec2[0] + 0.5f);
3177 vec2[1] = floorf(vec2[1] + 0.5f);
3179 /* apply inverted transform, we don't care about X component at this point */
3180 vec[1] = (-m->m12 * vec2[0] + m->m11 * vec2[1] - (m->m11 * m->dy - m->m12 * m->dx)) / det;
3181 vec[1] /= ppdip;
3183 else
3184 vec[1] = floorf(coord * ppdip + 0.5f) / ppdip;
3186 return vec[1];
3189 static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout3 *iface,
3190 void *context, IDWriteTextRenderer* renderer, FLOAT origin_x, FLOAT origin_y)
3192 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3193 BOOL disabled = FALSE, skiptransform = FALSE;
3194 struct layout_effective_inline *inlineobject;
3195 struct layout_effective_run *run;
3196 struct layout_strikethrough *s;
3197 struct layout_underline *u;
3198 FLOAT det = 0.0f, ppdip = 0.0f;
3199 DWRITE_MATRIX m = { 0 };
3200 HRESULT hr;
3202 TRACE("(%p)->(%p %p %.2f %.2f)\n", This, context, renderer, origin_x, origin_y);
3204 hr = layout_compute_effective_runs(This);
3205 if (FAILED(hr))
3206 return hr;
3208 hr = IDWriteTextRenderer_IsPixelSnappingDisabled(renderer, context, &disabled);
3209 if (FAILED(hr))
3210 return hr;
3212 if (!disabled) {
3213 hr = IDWriteTextRenderer_GetPixelsPerDip(renderer, context, &ppdip);
3214 if (FAILED(hr))
3215 return hr;
3217 hr = IDWriteTextRenderer_GetCurrentTransform(renderer, context, &m);
3218 if (FAILED(hr))
3219 return hr;
3221 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
3222 if (ppdip <= 0.0f ||
3223 (m.m11 * m.m22 != 0.0f && (m.m12 != 0.0f || m.m21 != 0.0f)) ||
3224 (m.m12 * m.m21 != 0.0f && (m.m11 != 0.0f || m.m22 != 0.0f)))
3225 disabled = TRUE;
3226 else
3227 skiptransform = should_skip_transform(&m, &det);
3230 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
3231 /* 1. Regular runs */
3232 LIST_FOR_EACH_ENTRY(run, &This->eruns, struct layout_effective_run, entry) {
3233 const struct regular_layout_run *regular = &run->run->u.regular;
3234 UINT32 start_glyph = regular->clustermap[run->start];
3235 DWRITE_GLYPH_RUN_DESCRIPTION descr;
3236 DWRITE_GLYPH_RUN glyph_run;
3238 /* Everything but cluster map will be reused from nominal run, as we only need
3239 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
3240 it can't be reused because it has to start with 0 index for each reported run. */
3241 glyph_run = regular->run;
3242 glyph_run.glyphCount = run->glyphcount;
3244 /* fixup glyph data arrays */
3245 glyph_run.glyphIndices += start_glyph;
3246 glyph_run.glyphAdvances += start_glyph;
3247 glyph_run.glyphOffsets += start_glyph;
3249 /* description */
3250 descr = regular->descr;
3251 descr.stringLength = run->length;
3252 descr.string += run->start;
3253 descr.clusterMap = run->clustermap;
3254 descr.textPosition += run->start;
3256 /* return value is ignored */
3257 IDWriteTextRenderer_DrawGlyphRun(renderer,
3258 context,
3259 run->origin_x + run->align_dx + origin_x,
3260 SNAP_COORD(run->origin_y + origin_y),
3261 This->measuringmode,
3262 &glyph_run,
3263 &descr,
3264 run->effect);
3267 /* 2. Inline objects */
3268 LIST_FOR_EACH_ENTRY(inlineobject, &This->inlineobjects, struct layout_effective_inline, entry) {
3269 IDWriteTextRenderer_DrawInlineObject(renderer,
3270 context,
3271 inlineobject->origin_x + inlineobject->align_dx + origin_x,
3272 SNAP_COORD(inlineobject->origin_y + origin_y),
3273 inlineobject->run->u.object.object,
3274 inlineobject->is_sideways,
3275 inlineobject->is_rtl,
3276 inlineobject->effect);
3279 /* 3. Underlines */
3280 LIST_FOR_EACH_ENTRY(u, &This->underlines, struct layout_underline, entry) {
3281 IDWriteTextRenderer_DrawUnderline(renderer,
3282 context,
3283 /* horizontal underline always grows from left to right, width is always added to origin regardless of run direction */
3284 (is_run_rtl(u->run) ? u->run->origin_x - u->run->width : u->run->origin_x) + u->run->align_dx + origin_x,
3285 SNAP_COORD(u->run->origin_y + origin_y),
3286 &u->u,
3287 u->run->effect);
3290 /* 4. Strikethrough */
3291 LIST_FOR_EACH_ENTRY(s, &This->strikethrough, struct layout_strikethrough, entry) {
3292 IDWriteTextRenderer_DrawStrikethrough(renderer,
3293 context,
3294 s->run->origin_x + s->run->align_dx + origin_x,
3295 SNAP_COORD(s->run->origin_y + origin_y),
3296 &s->s,
3297 s->run->effect);
3299 #undef SNAP_COORD
3301 return S_OK;
3304 static HRESULT WINAPI dwritetextlayout_GetLineMetrics(IDWriteTextLayout3 *iface,
3305 DWRITE_LINE_METRICS *metrics, UINT32 max_count, UINT32 *count)
3307 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3308 HRESULT hr;
3310 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
3312 hr = layout_compute_effective_runs(This);
3313 if (FAILED(hr))
3314 return hr;
3316 if (metrics)
3317 memcpy(metrics, This->lines, sizeof(*metrics)*min(max_count, This->metrics.lineCount));
3319 *count = This->metrics.lineCount;
3320 return max_count >= This->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3323 static HRESULT WINAPI dwritetextlayout_GetMetrics(IDWriteTextLayout3 *iface, DWRITE_TEXT_METRICS *metrics)
3325 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3326 DWRITE_TEXT_METRICS1 metrics1;
3327 HRESULT hr;
3329 TRACE("(%p)->(%p)\n", This, metrics);
3331 hr = IDWriteTextLayout3_GetMetrics(iface, &metrics1);
3332 if (hr == S_OK)
3333 memcpy(metrics, &metrics1, sizeof(*metrics));
3335 return hr;
3338 static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout3 *iface, DWRITE_OVERHANG_METRICS *overhangs)
3340 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3341 FIXME("(%p)->(%p): stub\n", This, overhangs);
3342 return E_NOTIMPL;
3345 static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout3 *iface,
3346 DWRITE_CLUSTER_METRICS *metrics, UINT32 max_count, UINT32 *count)
3348 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3349 HRESULT hr;
3351 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
3353 hr = layout_compute(This);
3354 if (FAILED(hr))
3355 return hr;
3357 if (metrics)
3358 memcpy(metrics, This->clustermetrics, sizeof(DWRITE_CLUSTER_METRICS)*min(max_count, This->cluster_count));
3360 *count = This->cluster_count;
3361 return max_count >= This->cluster_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3364 static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout3 *iface, FLOAT* min_width)
3366 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3367 UINT32 start;
3368 FLOAT width;
3369 HRESULT hr;
3371 TRACE("(%p)->(%p)\n", This, min_width);
3373 if (!min_width)
3374 return E_INVALIDARG;
3376 if (!(This->recompute & RECOMPUTE_MINIMAL_WIDTH))
3377 goto width_done;
3379 *min_width = 0.0f;
3380 hr = layout_compute(This);
3381 if (FAILED(hr))
3382 return hr;
3384 /* Find widest word without emergency breaking between clusters, trailing whitespaces
3385 preceding breaking point do not contribute to word width. */
3386 for (start = 0; start < This->cluster_count;) {
3387 UINT32 end = start, j, next;
3389 /* Last cluster always could be wrapped after. */
3390 while (!This->clustermetrics[end].canWrapLineAfter)
3391 end++;
3392 /* make is so current cluster range that we can wrap after is [start,end) */
3393 end++;
3395 next = end;
3397 /* Ignore trailing whitespace clusters, in case of single space range will
3398 be reduced to empty range, or [start,start+1). */
3399 while (end > start && This->clustermetrics[end-1].isWhitespace)
3400 end--;
3402 /* check if cluster range exceeds last minimal width */
3403 width = 0.0f;
3404 for (j = start; j < end; j++)
3405 width += This->clustermetrics[j].width;
3407 start = next;
3409 if (width > This->minwidth)
3410 This->minwidth = width;
3412 This->recompute &= ~RECOMPUTE_MINIMAL_WIDTH;
3414 width_done:
3415 *min_width = This->minwidth;
3416 return S_OK;
3419 static HRESULT WINAPI dwritetextlayout_HitTestPoint(IDWriteTextLayout3 *iface,
3420 FLOAT pointX, FLOAT pointY, BOOL* is_trailinghit, BOOL* is_inside, DWRITE_HIT_TEST_METRICS *metrics)
3422 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3423 FIXME("(%p)->(%f %f %p %p %p): stub\n", This, pointX, pointY, is_trailinghit, is_inside, metrics);
3424 return E_NOTIMPL;
3427 static HRESULT WINAPI dwritetextlayout_HitTestTextPosition(IDWriteTextLayout3 *iface,
3428 UINT32 textPosition, BOOL is_trailinghit, FLOAT* pointX, FLOAT* pointY, DWRITE_HIT_TEST_METRICS *metrics)
3430 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3431 FIXME("(%p)->(%u %d %p %p %p): stub\n", This, textPosition, is_trailinghit, pointX, pointY, metrics);
3432 return E_NOTIMPL;
3435 static HRESULT WINAPI dwritetextlayout_HitTestTextRange(IDWriteTextLayout3 *iface,
3436 UINT32 textPosition, UINT32 textLength, FLOAT originX, FLOAT originY,
3437 DWRITE_HIT_TEST_METRICS *metrics, UINT32 max_metricscount, UINT32* actual_metricscount)
3439 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3440 FIXME("(%p)->(%u %u %f %f %p %u %p): stub\n", This, textPosition, textLength, originX, originY, metrics,
3441 max_metricscount, actual_metricscount);
3442 return E_NOTIMPL;
3445 static HRESULT WINAPI dwritetextlayout1_SetPairKerning(IDWriteTextLayout3 *iface, BOOL is_pairkerning_enabled,
3446 DWRITE_TEXT_RANGE range)
3448 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3449 struct layout_range_attr_value value;
3451 TRACE("(%p)->(%d %s)\n", This, is_pairkerning_enabled, debugstr_range(&range));
3453 value.range = range;
3454 value.u.pair_kerning = !!is_pairkerning_enabled;
3455 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_PAIR_KERNING, &value);
3458 static HRESULT WINAPI dwritetextlayout1_GetPairKerning(IDWriteTextLayout3 *iface, UINT32 position, BOOL *is_pairkerning_enabled,
3459 DWRITE_TEXT_RANGE *r)
3461 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3462 struct layout_range *range;
3464 TRACE("(%p)->(%u %p %p)\n", This, position, is_pairkerning_enabled, r);
3466 if (position >= This->len)
3467 return S_OK;
3469 range = get_layout_range_by_pos(This, position);
3470 *is_pairkerning_enabled = range->pair_kerning;
3472 return return_range(&range->h, r);
3475 static HRESULT WINAPI dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout3 *iface, FLOAT leading, FLOAT trailing,
3476 FLOAT min_advance, DWRITE_TEXT_RANGE range)
3478 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3479 struct layout_range_attr_value value;
3481 TRACE("(%p)->(%.2f %.2f %.2f %s)\n", This, leading, trailing, min_advance, debugstr_range(&range));
3483 if (min_advance < 0.0f)
3484 return E_INVALIDARG;
3486 value.range = range;
3487 value.u.spacing[0] = leading;
3488 value.u.spacing[1] = trailing;
3489 value.u.spacing[2] = min_advance;
3490 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_SPACING, &value);
3493 static HRESULT WINAPI dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout3 *iface, UINT32 position, FLOAT *leading,
3494 FLOAT *trailing, FLOAT *min_advance, DWRITE_TEXT_RANGE *r)
3496 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3497 struct layout_range_spacing *range;
3499 TRACE("(%p)->(%u %p %p %p %p)\n", This, position, leading, trailing, min_advance, r);
3501 range = (struct layout_range_spacing*)get_layout_range_header_by_pos(&This->spacing, position);
3502 *leading = range->leading;
3503 *trailing = range->trailing;
3504 *min_advance = range->min_advance;
3506 return return_range(&range->h, r);
3509 static HRESULT WINAPI dwritetextlayout2_GetMetrics(IDWriteTextLayout3 *iface, DWRITE_TEXT_METRICS1 *metrics)
3511 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3512 HRESULT hr;
3514 TRACE("(%p)->(%p)\n", This, metrics);
3516 hr = layout_compute_effective_runs(This);
3517 if (FAILED(hr))
3518 return hr;
3520 *metrics = This->metrics;
3521 return S_OK;
3524 static HRESULT WINAPI dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout3 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
3526 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3528 TRACE("(%p)->(%d)\n", This, orientation);
3530 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
3531 return E_INVALIDARG;
3533 This->format.vertical_orientation = orientation;
3534 return S_OK;
3537 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout3 *iface)
3539 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3540 TRACE("(%p)\n", This);
3541 return This->format.vertical_orientation;
3544 static HRESULT WINAPI dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout3 *iface, BOOL lastline_wrapping_enabled)
3546 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3547 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
3548 return IDWriteTextFormat1_SetLastLineWrapping(&This->IDWriteTextFormat1_iface, lastline_wrapping_enabled);
3551 static BOOL WINAPI dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout3 *iface)
3553 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3554 TRACE("(%p)\n", This);
3555 return IDWriteTextFormat1_GetLastLineWrapping(&This->IDWriteTextFormat1_iface);
3558 static HRESULT WINAPI dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout3 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
3560 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3561 TRACE("(%p)->(%d)\n", This, alignment);
3562 return IDWriteTextFormat1_SetOpticalAlignment(&This->IDWriteTextFormat1_iface, alignment);
3565 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout3 *iface)
3567 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3568 TRACE("(%p)\n", This);
3569 return IDWriteTextFormat1_GetOpticalAlignment(&This->IDWriteTextFormat1_iface);
3572 static HRESULT WINAPI dwritetextlayout2_SetFontFallback(IDWriteTextLayout3 *iface, IDWriteFontFallback *fallback)
3574 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3575 TRACE("(%p)->(%p)\n", This, fallback);
3576 return set_fontfallback_for_format(&This->format, fallback);
3579 static HRESULT WINAPI dwritetextlayout2_GetFontFallback(IDWriteTextLayout3 *iface, IDWriteFontFallback **fallback)
3581 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3582 TRACE("(%p)->(%p)\n", This, fallback);
3583 return get_fontfallback_from_format(&This->format, fallback);
3586 static HRESULT WINAPI dwritetextlayout3_InvalidateLayout(IDWriteTextLayout3 *iface)
3588 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3590 TRACE("(%p)\n", This);
3592 This->recompute = RECOMPUTE_EVERYTHING;
3593 return S_OK;
3596 static HRESULT WINAPI dwritetextlayout3_SetLineSpacing(IDWriteTextLayout3 *iface, DWRITE_LINE_SPACING const *spacing)
3598 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3599 FIXME("(%p)->(%p): stub\n", This, spacing);
3600 return E_NOTIMPL;
3603 static HRESULT WINAPI dwritetextlayout3_GetLineSpacing(IDWriteTextLayout3 *iface, DWRITE_LINE_SPACING *spacing)
3605 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3606 FIXME("(%p)->(%p): stub\n", This, spacing);
3607 return E_NOTIMPL;
3610 static HRESULT WINAPI dwritetextlayout3_GetLineMetrics(IDWriteTextLayout3 *iface, DWRITE_LINE_METRICS1 *metrics,
3611 UINT32 max_count, UINT32 *count)
3613 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3614 FIXME("(%p)->(%p %u %p): stub\n", This, metrics, max_count, count);
3615 return E_NOTIMPL;
3618 static const IDWriteTextLayout3Vtbl dwritetextlayoutvtbl = {
3619 dwritetextlayout_QueryInterface,
3620 dwritetextlayout_AddRef,
3621 dwritetextlayout_Release,
3622 dwritetextlayout_SetTextAlignment,
3623 dwritetextlayout_SetParagraphAlignment,
3624 dwritetextlayout_SetWordWrapping,
3625 dwritetextlayout_SetReadingDirection,
3626 dwritetextlayout_SetFlowDirection,
3627 dwritetextlayout_SetIncrementalTabStop,
3628 dwritetextlayout_SetTrimming,
3629 dwritetextlayout_SetLineSpacing,
3630 dwritetextlayout_GetTextAlignment,
3631 dwritetextlayout_GetParagraphAlignment,
3632 dwritetextlayout_GetWordWrapping,
3633 dwritetextlayout_GetReadingDirection,
3634 dwritetextlayout_GetFlowDirection,
3635 dwritetextlayout_GetIncrementalTabStop,
3636 dwritetextlayout_GetTrimming,
3637 dwritetextlayout_GetLineSpacing,
3638 dwritetextlayout_GetFontCollection,
3639 dwritetextlayout_GetFontFamilyNameLength,
3640 dwritetextlayout_GetFontFamilyName,
3641 dwritetextlayout_GetFontWeight,
3642 dwritetextlayout_GetFontStyle,
3643 dwritetextlayout_GetFontStretch,
3644 dwritetextlayout_GetFontSize,
3645 dwritetextlayout_GetLocaleNameLength,
3646 dwritetextlayout_GetLocaleName,
3647 dwritetextlayout_SetMaxWidth,
3648 dwritetextlayout_SetMaxHeight,
3649 dwritetextlayout_SetFontCollection,
3650 dwritetextlayout_SetFontFamilyName,
3651 dwritetextlayout_SetFontWeight,
3652 dwritetextlayout_SetFontStyle,
3653 dwritetextlayout_SetFontStretch,
3654 dwritetextlayout_SetFontSize,
3655 dwritetextlayout_SetUnderline,
3656 dwritetextlayout_SetStrikethrough,
3657 dwritetextlayout_SetDrawingEffect,
3658 dwritetextlayout_SetInlineObject,
3659 dwritetextlayout_SetTypography,
3660 dwritetextlayout_SetLocaleName,
3661 dwritetextlayout_GetMaxWidth,
3662 dwritetextlayout_GetMaxHeight,
3663 dwritetextlayout_layout_GetFontCollection,
3664 dwritetextlayout_layout_GetFontFamilyNameLength,
3665 dwritetextlayout_layout_GetFontFamilyName,
3666 dwritetextlayout_layout_GetFontWeight,
3667 dwritetextlayout_layout_GetFontStyle,
3668 dwritetextlayout_layout_GetFontStretch,
3669 dwritetextlayout_layout_GetFontSize,
3670 dwritetextlayout_GetUnderline,
3671 dwritetextlayout_GetStrikethrough,
3672 dwritetextlayout_GetDrawingEffect,
3673 dwritetextlayout_GetInlineObject,
3674 dwritetextlayout_GetTypography,
3675 dwritetextlayout_layout_GetLocaleNameLength,
3676 dwritetextlayout_layout_GetLocaleName,
3677 dwritetextlayout_Draw,
3678 dwritetextlayout_GetLineMetrics,
3679 dwritetextlayout_GetMetrics,
3680 dwritetextlayout_GetOverhangMetrics,
3681 dwritetextlayout_GetClusterMetrics,
3682 dwritetextlayout_DetermineMinWidth,
3683 dwritetextlayout_HitTestPoint,
3684 dwritetextlayout_HitTestTextPosition,
3685 dwritetextlayout_HitTestTextRange,
3686 dwritetextlayout1_SetPairKerning,
3687 dwritetextlayout1_GetPairKerning,
3688 dwritetextlayout1_SetCharacterSpacing,
3689 dwritetextlayout1_GetCharacterSpacing,
3690 dwritetextlayout2_GetMetrics,
3691 dwritetextlayout2_SetVerticalGlyphOrientation,
3692 dwritetextlayout2_GetVerticalGlyphOrientation,
3693 dwritetextlayout2_SetLastLineWrapping,
3694 dwritetextlayout2_GetLastLineWrapping,
3695 dwritetextlayout2_SetOpticalAlignment,
3696 dwritetextlayout2_GetOpticalAlignment,
3697 dwritetextlayout2_SetFontFallback,
3698 dwritetextlayout2_GetFontFallback,
3699 dwritetextlayout3_InvalidateLayout,
3700 dwritetextlayout3_SetLineSpacing,
3701 dwritetextlayout3_GetLineSpacing,
3702 dwritetextlayout3_GetLineMetrics
3705 static HRESULT WINAPI dwritetextformat_layout_QueryInterface(IDWriteTextFormat1 *iface, REFIID riid, void **obj)
3707 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3708 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3709 return IDWriteTextLayout3_QueryInterface(&This->IDWriteTextLayout3_iface, riid, obj);
3712 static ULONG WINAPI dwritetextformat_layout_AddRef(IDWriteTextFormat1 *iface)
3714 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3715 return IDWriteTextLayout3_AddRef(&This->IDWriteTextLayout3_iface);
3718 static ULONG WINAPI dwritetextformat_layout_Release(IDWriteTextFormat1 *iface)
3720 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3721 return IDWriteTextLayout3_Release(&This->IDWriteTextLayout3_iface);
3724 static HRESULT WINAPI dwritetextformat_layout_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
3726 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3727 BOOL changed;
3728 HRESULT hr;
3730 TRACE("(%p)->(%d)\n", This, alignment);
3732 hr = format_set_textalignment(&This->format, alignment, &changed);
3733 if (FAILED(hr))
3734 return hr;
3736 /* if layout is not ready there's nothing to align */
3737 if (changed && !(This->recompute & RECOMPUTE_EFFECTIVE_RUNS))
3738 layout_apply_text_alignment(This);
3740 return S_OK;
3743 static HRESULT WINAPI dwritetextformat_layout_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
3745 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3746 BOOL changed;
3747 HRESULT hr;
3749 TRACE("(%p)->(%d)\n", This, alignment);
3751 hr = format_set_paralignment(&This->format, alignment, &changed);
3752 if (FAILED(hr))
3753 return hr;
3755 /* if layout is not ready there's nothing to align */
3756 if (changed && !(This->recompute & RECOMPUTE_EFFECTIVE_RUNS))
3757 layout_apply_par_alignment(This);
3759 return S_OK;
3762 static HRESULT WINAPI dwritetextformat_layout_SetWordWrapping(IDWriteTextFormat1 *iface, DWRITE_WORD_WRAPPING wrapping)
3764 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3765 BOOL changed;
3766 HRESULT hr;
3768 TRACE("(%p)->(%d)\n", This, wrapping);
3770 hr = format_set_wordwrapping(&This->format, wrapping, &changed);
3771 if (FAILED(hr))
3772 return hr;
3774 if (changed)
3775 This->recompute |= RECOMPUTE_EFFECTIVE_RUNS;
3777 return S_OK;
3780 static HRESULT WINAPI dwritetextformat_layout_SetReadingDirection(IDWriteTextFormat1 *iface, DWRITE_READING_DIRECTION direction)
3782 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3783 BOOL changed;
3784 HRESULT hr;
3786 TRACE("(%p)->(%d)\n", This, direction);
3788 hr = format_set_readingdirection(&This->format, direction, &changed);
3789 if (FAILED(hr))
3790 return hr;
3792 if (changed)
3793 This->recompute = RECOMPUTE_EVERYTHING;
3795 return S_OK;
3798 static HRESULT WINAPI dwritetextformat_layout_SetFlowDirection(IDWriteTextFormat1 *iface, DWRITE_FLOW_DIRECTION direction)
3800 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3801 BOOL changed;
3802 HRESULT hr;
3804 TRACE("(%p)->(%d)\n", This, direction);
3806 hr = format_set_flowdirection(&This->format, direction, &changed);
3807 if (FAILED(hr))
3808 return hr;
3810 if (changed)
3811 This->recompute = RECOMPUTE_EVERYTHING;
3813 return S_OK;
3816 static HRESULT WINAPI dwritetextformat_layout_SetIncrementalTabStop(IDWriteTextFormat1 *iface, FLOAT tabstop)
3818 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3819 FIXME("(%p)->(%f): stub\n", This, tabstop);
3820 return E_NOTIMPL;
3823 static HRESULT WINAPI dwritetextformat_layout_SetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING const *trimming,
3824 IDWriteInlineObject *trimming_sign)
3826 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3827 FIXME("(%p)->(%p %p): stub\n", This, trimming, trimming_sign);
3828 return E_NOTIMPL;
3831 static HRESULT WINAPI dwritetextformat_layout_SetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD method,
3832 FLOAT spacing, FLOAT baseline)
3834 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3835 BOOL changed;
3836 HRESULT hr;
3838 TRACE("(%p)->(%d %f %f)\n", This, method, spacing, baseline);
3840 hr = format_set_linespacing(&This->format, method, spacing, baseline, &changed);
3841 if (FAILED(hr))
3842 return hr;
3844 if (changed)
3845 This->recompute = RECOMPUTE_EVERYTHING;
3847 return S_OK;
3850 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_layout_GetTextAlignment(IDWriteTextFormat1 *iface)
3852 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3853 TRACE("(%p)\n", This);
3854 return This->format.textalignment;
3857 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_layout_GetParagraphAlignment(IDWriteTextFormat1 *iface)
3859 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3860 TRACE("(%p)\n", This);
3861 return This->format.paralign;
3864 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_layout_GetWordWrapping(IDWriteTextFormat1 *iface)
3866 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3867 TRACE("(%p)\n", This);
3868 return This->format.wrapping;
3871 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_layout_GetReadingDirection(IDWriteTextFormat1 *iface)
3873 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3874 TRACE("(%p)\n", This);
3875 return This->format.readingdir;
3878 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_layout_GetFlowDirection(IDWriteTextFormat1 *iface)
3880 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3881 TRACE("(%p)\n", This);
3882 return This->format.flow;
3885 static FLOAT WINAPI dwritetextformat_layout_GetIncrementalTabStop(IDWriteTextFormat1 *iface)
3887 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3888 FIXME("(%p): stub\n", This);
3889 return 0.0f;
3892 static HRESULT WINAPI dwritetextformat_layout_GetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING *options,
3893 IDWriteInlineObject **trimming_sign)
3895 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3897 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
3899 *options = This->format.trimming;
3900 *trimming_sign = This->format.trimmingsign;
3901 if (*trimming_sign)
3902 IDWriteInlineObject_AddRef(*trimming_sign);
3903 return S_OK;
3906 static HRESULT WINAPI dwritetextformat_layout_GetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD *method,
3907 FLOAT *spacing, FLOAT *baseline)
3909 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3911 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
3913 *method = This->format.spacingmethod;
3914 *spacing = This->format.spacing;
3915 *baseline = This->format.baseline;
3916 return S_OK;
3919 static HRESULT WINAPI dwritetextformat_layout_GetFontCollection(IDWriteTextFormat1 *iface, IDWriteFontCollection **collection)
3921 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3923 TRACE("(%p)->(%p)\n", This, collection);
3925 *collection = This->format.collection;
3926 if (*collection)
3927 IDWriteFontCollection_AddRef(*collection);
3928 return S_OK;
3931 static UINT32 WINAPI dwritetextformat_layout_GetFontFamilyNameLength(IDWriteTextFormat1 *iface)
3933 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3934 TRACE("(%p)\n", This);
3935 return This->format.family_len;
3938 static HRESULT WINAPI dwritetextformat_layout_GetFontFamilyName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
3940 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3942 TRACE("(%p)->(%p %u)\n", This, name, size);
3944 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
3945 strcpyW(name, This->format.family_name);
3946 return S_OK;
3949 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_layout_GetFontWeight(IDWriteTextFormat1 *iface)
3951 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3952 TRACE("(%p)\n", This);
3953 return This->format.weight;
3956 static DWRITE_FONT_STYLE WINAPI dwritetextformat_layout_GetFontStyle(IDWriteTextFormat1 *iface)
3958 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3959 TRACE("(%p)\n", This);
3960 return This->format.style;
3963 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_layout_GetFontStretch(IDWriteTextFormat1 *iface)
3965 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3966 TRACE("(%p)\n", This);
3967 return This->format.stretch;
3970 static FLOAT WINAPI dwritetextformat_layout_GetFontSize(IDWriteTextFormat1 *iface)
3972 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3973 TRACE("(%p)\n", This);
3974 return This->format.fontsize;
3977 static UINT32 WINAPI dwritetextformat_layout_GetLocaleNameLength(IDWriteTextFormat1 *iface)
3979 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3980 TRACE("(%p)\n", This);
3981 return This->format.locale_len;
3984 static HRESULT WINAPI dwritetextformat_layout_GetLocaleName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
3986 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3988 TRACE("(%p)->(%p %u)\n", This, name, size);
3990 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
3991 strcpyW(name, This->format.locale);
3992 return S_OK;
3995 static HRESULT WINAPI dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat1 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
3997 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3998 FIXME("(%p)->(%d): stub\n", This, orientation);
3999 return E_NOTIMPL;
4002 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat1 *iface)
4004 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4005 FIXME("(%p): stub\n", This);
4006 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
4009 static HRESULT WINAPI dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat1 *iface, BOOL lastline_wrapping_enabled)
4011 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4013 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
4015 This->format.last_line_wrapping = !!lastline_wrapping_enabled;
4016 return S_OK;
4019 static BOOL WINAPI dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat1 *iface)
4021 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4022 TRACE("(%p)\n", This);
4023 return This->format.last_line_wrapping;
4026 static HRESULT WINAPI dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat1 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
4028 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4029 TRACE("(%p)->(%d)\n", This, alignment);
4030 return format_set_optical_alignment(&This->format, alignment);
4033 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat1 *iface)
4035 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4036 TRACE("(%p)\n", This);
4037 return This->format.optical_alignment;
4040 static HRESULT WINAPI dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback *fallback)
4042 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4043 TRACE("(%p)->(%p)\n", This, fallback);
4044 return IDWriteTextLayout3_SetFontFallback(&This->IDWriteTextLayout3_iface, fallback);
4047 static HRESULT WINAPI dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback **fallback)
4049 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4050 TRACE("(%p)->(%p)\n", This, fallback);
4051 return IDWriteTextLayout3_GetFontFallback(&This->IDWriteTextLayout3_iface, fallback);
4054 static const IDWriteTextFormat1Vtbl dwritetextformat1_layout_vtbl = {
4055 dwritetextformat_layout_QueryInterface,
4056 dwritetextformat_layout_AddRef,
4057 dwritetextformat_layout_Release,
4058 dwritetextformat_layout_SetTextAlignment,
4059 dwritetextformat_layout_SetParagraphAlignment,
4060 dwritetextformat_layout_SetWordWrapping,
4061 dwritetextformat_layout_SetReadingDirection,
4062 dwritetextformat_layout_SetFlowDirection,
4063 dwritetextformat_layout_SetIncrementalTabStop,
4064 dwritetextformat_layout_SetTrimming,
4065 dwritetextformat_layout_SetLineSpacing,
4066 dwritetextformat_layout_GetTextAlignment,
4067 dwritetextformat_layout_GetParagraphAlignment,
4068 dwritetextformat_layout_GetWordWrapping,
4069 dwritetextformat_layout_GetReadingDirection,
4070 dwritetextformat_layout_GetFlowDirection,
4071 dwritetextformat_layout_GetIncrementalTabStop,
4072 dwritetextformat_layout_GetTrimming,
4073 dwritetextformat_layout_GetLineSpacing,
4074 dwritetextformat_layout_GetFontCollection,
4075 dwritetextformat_layout_GetFontFamilyNameLength,
4076 dwritetextformat_layout_GetFontFamilyName,
4077 dwritetextformat_layout_GetFontWeight,
4078 dwritetextformat_layout_GetFontStyle,
4079 dwritetextformat_layout_GetFontStretch,
4080 dwritetextformat_layout_GetFontSize,
4081 dwritetextformat_layout_GetLocaleNameLength,
4082 dwritetextformat_layout_GetLocaleName,
4083 dwritetextformat1_layout_SetVerticalGlyphOrientation,
4084 dwritetextformat1_layout_GetVerticalGlyphOrientation,
4085 dwritetextformat1_layout_SetLastLineWrapping,
4086 dwritetextformat1_layout_GetLastLineWrapping,
4087 dwritetextformat1_layout_SetOpticalAlignment,
4088 dwritetextformat1_layout_GetOpticalAlignment,
4089 dwritetextformat1_layout_SetFontFallback,
4090 dwritetextformat1_layout_GetFontFallback,
4093 static HRESULT WINAPI dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink1 *iface,
4094 REFIID riid, void **obj)
4096 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink1) ||
4097 IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) ||
4098 IsEqualIID(riid, &IID_IUnknown))
4100 *obj = iface;
4101 IDWriteTextAnalysisSink1_AddRef(iface);
4102 return S_OK;
4105 *obj = NULL;
4106 return E_NOINTERFACE;
4109 static ULONG WINAPI dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink1 *iface)
4111 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4112 return IDWriteTextLayout3_AddRef(&layout->IDWriteTextLayout3_iface);
4115 static ULONG WINAPI dwritetextlayout_sink_Release(IDWriteTextAnalysisSink1 *iface)
4117 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4118 return IDWriteTextLayout3_Release(&layout->IDWriteTextLayout3_iface);
4121 static HRESULT WINAPI dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink1 *iface,
4122 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
4124 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4125 struct layout_run *run;
4127 TRACE("[%u,%u) script=%u:%s\n", position, position + length, sa->script, debugstr_sa_script(sa->script));
4129 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
4130 if (!run)
4131 return E_OUTOFMEMORY;
4133 run->u.regular.descr.string = &layout->str[position];
4134 run->u.regular.descr.stringLength = length;
4135 run->u.regular.descr.textPosition = position;
4136 run->u.regular.sa = *sa;
4137 list_add_tail(&layout->runs, &run->entry);
4138 return S_OK;
4141 static HRESULT WINAPI dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink1 *iface,
4142 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
4144 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4146 if (position + length > layout->len)
4147 return E_FAIL;
4149 memcpy(&layout->nominal_breakpoints[position], breakpoints, length*sizeof(DWRITE_LINE_BREAKPOINT));
4150 return S_OK;
4153 static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink1 *iface, UINT32 position,
4154 UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
4156 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4157 struct layout_run *cur_run;
4159 TRACE("[%u,%u) %u %u\n", position, position + length, explicitLevel, resolvedLevel);
4161 LIST_FOR_EACH_ENTRY(cur_run, &layout->runs, struct layout_run, entry) {
4162 struct regular_layout_run *cur = &cur_run->u.regular;
4163 struct layout_run *run;
4165 if (cur_run->kind == LAYOUT_RUN_INLINE)
4166 continue;
4168 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
4169 if (position < cur->descr.textPosition || position >= cur->descr.textPosition + cur->descr.stringLength)
4170 continue;
4172 /* full hit - just set run level */
4173 if (cur->descr.textPosition == position && cur->descr.stringLength == length) {
4174 cur->run.bidiLevel = resolvedLevel;
4175 break;
4178 /* current run is fully covered, move to next one */
4179 if (cur->descr.textPosition == position && cur->descr.stringLength < length) {
4180 cur->run.bidiLevel = resolvedLevel;
4181 position += cur->descr.stringLength;
4182 length -= cur->descr.stringLength;
4183 continue;
4186 /* all fully covered runs are processed at this point, reuse existing run for remaining
4187 reported bidi range and add another run for the rest of original one */
4189 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
4190 if (!run)
4191 return E_OUTOFMEMORY;
4193 *run = *cur_run;
4194 run->u.regular.descr.textPosition = position + length;
4195 run->u.regular.descr.stringLength = cur->descr.stringLength - length;
4196 run->u.regular.descr.string = &layout->str[position + length];
4198 /* reduce existing run */
4199 cur->run.bidiLevel = resolvedLevel;
4200 cur->descr.stringLength = length;
4202 list_add_after(&cur_run->entry, &run->entry);
4203 break;
4206 return S_OK;
4209 static HRESULT WINAPI dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink1 *iface,
4210 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
4212 return E_NOTIMPL;
4215 static HRESULT WINAPI dwritetextlayout_sink_SetGlyphOrientation(IDWriteTextAnalysisSink1 *iface,
4216 UINT32 position, UINT32 length, DWRITE_GLYPH_ORIENTATION_ANGLE angle, UINT8 adjusted_bidi_level,
4217 BOOL is_sideways, BOOL is_rtl)
4219 return E_NOTIMPL;
4222 static const IDWriteTextAnalysisSink1Vtbl dwritetextlayoutsinkvtbl = {
4223 dwritetextlayout_sink_QueryInterface,
4224 dwritetextlayout_sink_AddRef,
4225 dwritetextlayout_sink_Release,
4226 dwritetextlayout_sink_SetScriptAnalysis,
4227 dwritetextlayout_sink_SetLineBreakpoints,
4228 dwritetextlayout_sink_SetBidiLevel,
4229 dwritetextlayout_sink_SetNumberSubstitution,
4230 dwritetextlayout_sink_SetGlyphOrientation
4233 static HRESULT WINAPI dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource1 *iface,
4234 REFIID riid, void **obj)
4236 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource1) ||
4237 IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) ||
4238 IsEqualIID(riid, &IID_IUnknown))
4240 *obj = iface;
4241 IDWriteTextAnalysisSource1_AddRef(iface);
4242 return S_OK;
4245 *obj = NULL;
4246 return E_NOINTERFACE;
4249 static ULONG WINAPI dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource1 *iface)
4251 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4252 return IDWriteTextLayout3_AddRef(&layout->IDWriteTextLayout3_iface);
4255 static ULONG WINAPI dwritetextlayout_source_Release(IDWriteTextAnalysisSource1 *iface)
4257 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4258 return IDWriteTextLayout3_Release(&layout->IDWriteTextLayout3_iface);
4261 static HRESULT WINAPI dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource1 *iface,
4262 UINT32 position, WCHAR const** text, UINT32* text_len)
4264 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4266 TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
4268 if (position < layout->len) {
4269 *text = &layout->str[position];
4270 *text_len = layout->len - position;
4272 else {
4273 *text = NULL;
4274 *text_len = 0;
4277 return S_OK;
4280 static HRESULT WINAPI dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource1 *iface,
4281 UINT32 position, WCHAR const** text, UINT32* text_len)
4283 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4285 TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
4287 if (position > 0 && position < layout->len) {
4288 *text = layout->str;
4289 *text_len = position;
4291 else {
4292 *text = NULL;
4293 *text_len = 0;
4296 return S_OK;
4299 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource1 *iface)
4301 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4302 return IDWriteTextLayout3_GetReadingDirection(&layout->IDWriteTextLayout3_iface);
4305 static HRESULT WINAPI dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource1 *iface,
4306 UINT32 position, UINT32* text_len, WCHAR const** locale)
4308 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4309 struct layout_range *range = get_layout_range_by_pos(layout, position);
4311 if (position < layout->len) {
4312 struct layout_range *next;
4314 *locale = range->locale;
4315 *text_len = range->h.range.length - position;
4317 next = LIST_ENTRY(list_next(&layout->ranges, &range->h.entry), struct layout_range, h.entry);
4318 while (next && next->h.range.startPosition < layout->len && !strcmpW(range->locale, next->locale)) {
4319 *text_len += next->h.range.length;
4320 next = LIST_ENTRY(list_next(&layout->ranges, &next->h.entry), struct layout_range, h.entry);
4323 *text_len = min(*text_len, layout->len - position);
4325 else {
4326 *locale = NULL;
4327 *text_len = 0;
4330 return S_OK;
4333 static HRESULT WINAPI dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource1 *iface,
4334 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
4336 FIXME("%u %p %p: stub\n", position, text_len, substitution);
4337 return E_NOTIMPL;
4340 static HRESULT WINAPI dwritetextlayout_source_GetVerticalGlyphOrientation(IDWriteTextAnalysisSource1 *iface,
4341 UINT32 position, UINT32 *length, DWRITE_VERTICAL_GLYPH_ORIENTATION *orientation, UINT8 *bidi_level)
4343 FIXME("%u %p %p %p: stub\n", position, length, orientation, bidi_level);
4344 return E_NOTIMPL;
4347 static const IDWriteTextAnalysisSource1Vtbl dwritetextlayoutsourcevtbl = {
4348 dwritetextlayout_source_QueryInterface,
4349 dwritetextlayout_source_AddRef,
4350 dwritetextlayout_source_Release,
4351 dwritetextlayout_source_GetTextAtPosition,
4352 dwritetextlayout_source_GetTextBeforePosition,
4353 dwritetextlayout_source_GetParagraphReadingDirection,
4354 dwritetextlayout_source_GetLocaleName,
4355 dwritetextlayout_source_GetNumberSubstitution,
4356 dwritetextlayout_source_GetVerticalGlyphOrientation
4359 static HRESULT layout_format_from_textformat(struct dwrite_textlayout *layout, IDWriteTextFormat *format)
4361 struct dwrite_textformat *textformat;
4362 IDWriteTextFormat1 *format1;
4363 UINT32 len;
4364 HRESULT hr;
4366 if ((textformat = unsafe_impl_from_IDWriteTextFormat(format))) {
4367 layout->format = textformat->format;
4369 layout->format.locale = heap_strdupW(textformat->format.locale);
4370 layout->format.family_name = heap_strdupW(textformat->format.family_name);
4371 if (!layout->format.locale || !layout->format.family_name)
4373 heap_free(layout->format.locale);
4374 heap_free(layout->format.family_name);
4375 return E_OUTOFMEMORY;
4378 if (layout->format.trimmingsign)
4379 IDWriteInlineObject_AddRef(layout->format.trimmingsign);
4380 if (layout->format.collection)
4381 IDWriteFontCollection_AddRef(layout->format.collection);
4382 if (layout->format.fallback)
4383 IDWriteFontFallback_AddRef(layout->format.fallback);
4385 return S_OK;
4388 layout->format.weight = IDWriteTextFormat_GetFontWeight(format);
4389 layout->format.style = IDWriteTextFormat_GetFontStyle(format);
4390 layout->format.stretch = IDWriteTextFormat_GetFontStretch(format);
4391 layout->format.fontsize= IDWriteTextFormat_GetFontSize(format);
4392 layout->format.textalignment = IDWriteTextFormat_GetTextAlignment(format);
4393 layout->format.paralign = IDWriteTextFormat_GetParagraphAlignment(format);
4394 layout->format.wrapping = IDWriteTextFormat_GetWordWrapping(format);
4395 layout->format.readingdir = IDWriteTextFormat_GetReadingDirection(format);
4396 layout->format.flow = IDWriteTextFormat_GetFlowDirection(format);
4397 layout->format.fallback = NULL;
4398 hr = IDWriteTextFormat_GetLineSpacing(format, &layout->format.spacingmethod,
4399 &layout->format.spacing, &layout->format.baseline);
4400 if (FAILED(hr))
4401 return hr;
4403 hr = IDWriteTextFormat_GetTrimming(format, &layout->format.trimming, &layout->format.trimmingsign);
4404 if (FAILED(hr))
4405 return hr;
4407 /* locale name and length */
4408 len = IDWriteTextFormat_GetLocaleNameLength(format);
4409 layout->format.locale = heap_alloc((len+1)*sizeof(WCHAR));
4410 if (!layout->format.locale)
4411 return E_OUTOFMEMORY;
4413 hr = IDWriteTextFormat_GetLocaleName(format, layout->format.locale, len+1);
4414 if (FAILED(hr))
4415 return hr;
4416 layout->format.locale_len = len;
4418 /* font family name and length */
4419 len = IDWriteTextFormat_GetFontFamilyNameLength(format);
4420 layout->format.family_name = heap_alloc((len+1)*sizeof(WCHAR));
4421 if (!layout->format.family_name)
4422 return E_OUTOFMEMORY;
4424 hr = IDWriteTextFormat_GetFontFamilyName(format, layout->format.family_name, len+1);
4425 if (FAILED(hr))
4426 return hr;
4427 layout->format.family_len = len;
4429 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
4430 if (hr == S_OK) {
4431 layout->format.vertical_orientation = IDWriteTextFormat1_GetVerticalGlyphOrientation(format1);
4432 layout->format.optical_alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
4433 IDWriteTextFormat1_GetFontFallback(format1, &layout->format.fallback);
4434 IDWriteTextFormat1_Release(format1);
4436 else {
4437 layout->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
4438 layout->format.optical_alignment = DWRITE_OPTICAL_ALIGNMENT_NONE;
4441 return IDWriteTextFormat_GetFontCollection(format, &layout->format.collection);
4444 static HRESULT init_textlayout(IDWriteFactory2 *factory, const WCHAR *str, UINT32 len, IDWriteTextFormat *format,
4445 FLOAT maxwidth, FLOAT maxheight, struct dwrite_textlayout *layout)
4447 struct layout_range_header *range, *strike, *underline, *effect, *spacing, *typography;
4448 static const DWRITE_TEXT_RANGE r = { 0, ~0u };
4449 HRESULT hr;
4451 layout->IDWriteTextLayout3_iface.lpVtbl = &dwritetextlayoutvtbl;
4452 layout->IDWriteTextFormat1_iface.lpVtbl = &dwritetextformat1_layout_vtbl;
4453 layout->IDWriteTextAnalysisSink1_iface.lpVtbl = &dwritetextlayoutsinkvtbl;
4454 layout->IDWriteTextAnalysisSource1_iface.lpVtbl = &dwritetextlayoutsourcevtbl;
4455 layout->ref = 1;
4456 layout->len = len;
4457 layout->recompute = RECOMPUTE_EVERYTHING;
4458 layout->nominal_breakpoints = NULL;
4459 layout->actual_breakpoints = NULL;
4460 layout->cluster_count = 0;
4461 layout->clustermetrics = NULL;
4462 layout->clusters = NULL;
4463 layout->lines = NULL;
4464 layout->line_alloc = 0;
4465 layout->minwidth = 0.0f;
4466 list_init(&layout->eruns);
4467 list_init(&layout->inlineobjects);
4468 list_init(&layout->underlines);
4469 list_init(&layout->strikethrough);
4470 list_init(&layout->runs);
4471 list_init(&layout->ranges);
4472 list_init(&layout->strike_ranges);
4473 list_init(&layout->underline_ranges);
4474 list_init(&layout->effects);
4475 list_init(&layout->spacing);
4476 list_init(&layout->typographies);
4477 memset(&layout->format, 0, sizeof(layout->format));
4478 memset(&layout->metrics, 0, sizeof(layout->metrics));
4479 layout->metrics.layoutWidth = maxwidth;
4480 layout->metrics.layoutHeight = maxheight;
4481 layout->measuringmode = DWRITE_MEASURING_MODE_NATURAL;
4483 layout->ppdip = 0.0f;
4484 memset(&layout->transform, 0, sizeof(layout->transform));
4486 layout->str = heap_strdupnW(str, len);
4487 if (len && !layout->str) {
4488 hr = E_OUTOFMEMORY;
4489 goto fail;
4492 hr = layout_format_from_textformat(layout, format);
4493 if (FAILED(hr))
4494 goto fail;
4496 range = alloc_layout_range(layout, &r, LAYOUT_RANGE_REGULAR);
4497 strike = alloc_layout_range(layout, &r, LAYOUT_RANGE_STRIKETHROUGH);
4498 underline = alloc_layout_range(layout, &r, LAYOUT_RANGE_UNDERLINE);
4499 effect = alloc_layout_range(layout, &r, LAYOUT_RANGE_EFFECT);
4500 spacing = alloc_layout_range(layout, &r, LAYOUT_RANGE_SPACING);
4501 typography = alloc_layout_range(layout, &r, LAYOUT_RANGE_TYPOGRAPHY);
4502 if (!range || !strike || !effect || !spacing || !typography || !underline) {
4503 free_layout_range(range);
4504 free_layout_range(strike);
4505 free_layout_range(underline);
4506 free_layout_range(effect);
4507 free_layout_range(spacing);
4508 free_layout_range(typography);
4509 hr = E_OUTOFMEMORY;
4510 goto fail;
4513 layout->factory = factory;
4514 IDWriteFactory2_AddRef(layout->factory);
4515 list_add_head(&layout->ranges, &range->entry);
4516 list_add_head(&layout->strike_ranges, &strike->entry);
4517 list_add_head(&layout->underline_ranges, &underline->entry);
4518 list_add_head(&layout->effects, &effect->entry);
4519 list_add_head(&layout->spacing, &spacing->entry);
4520 list_add_head(&layout->typographies, &typography->entry);
4521 return S_OK;
4523 fail:
4524 IDWriteTextLayout3_Release(&layout->IDWriteTextLayout3_iface);
4525 return hr;
4528 HRESULT create_textlayout(IDWriteFactory2 *factory, const WCHAR *str, UINT32 len, IDWriteTextFormat *format,
4529 FLOAT maxwidth, FLOAT maxheight, IDWriteTextLayout **ret)
4531 struct dwrite_textlayout *layout;
4532 HRESULT hr;
4534 *ret = NULL;
4536 if (!format || !str)
4537 return E_INVALIDARG;
4539 layout = heap_alloc(sizeof(struct dwrite_textlayout));
4540 if (!layout) return E_OUTOFMEMORY;
4542 hr = init_textlayout(factory, str, len, format, maxwidth, maxheight, layout);
4543 if (hr == S_OK)
4544 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout3_iface;
4546 return hr;
4549 HRESULT create_gdicompat_textlayout(IDWriteFactory2 *factory, const WCHAR *str, UINT32 len, IDWriteTextFormat *format,
4550 FLOAT maxwidth, FLOAT maxheight, FLOAT ppdip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural, IDWriteTextLayout **ret)
4552 struct dwrite_textlayout *layout;
4553 HRESULT hr;
4555 *ret = NULL;
4557 if (!format || !str)
4558 return E_INVALIDARG;
4560 layout = heap_alloc(sizeof(struct dwrite_textlayout));
4561 if (!layout) return E_OUTOFMEMORY;
4563 hr = init_textlayout(factory, str, len, format, maxwidth, maxheight, layout);
4564 if (hr == S_OK) {
4565 layout->measuringmode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
4567 /* set gdi-specific properties */
4568 layout->ppdip = ppdip;
4569 layout->transform = transform ? *transform : identity;
4571 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout3_iface;
4574 return hr;
4577 static HRESULT WINAPI dwritetrimmingsign_QueryInterface(IDWriteInlineObject *iface, REFIID riid, void **obj)
4579 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4581 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4583 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteInlineObject)) {
4584 *obj = iface;
4585 IDWriteInlineObject_AddRef(iface);
4586 return S_OK;
4589 *obj = NULL;
4590 return E_NOINTERFACE;
4593 static ULONG WINAPI dwritetrimmingsign_AddRef(IDWriteInlineObject *iface)
4595 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4596 ULONG ref = InterlockedIncrement(&This->ref);
4597 TRACE("(%p)->(%d)\n", This, ref);
4598 return ref;
4601 static ULONG WINAPI dwritetrimmingsign_Release(IDWriteInlineObject *iface)
4603 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4604 ULONG ref = InterlockedDecrement(&This->ref);
4606 TRACE("(%p)->(%d)\n", This, ref);
4608 if (!ref) {
4609 IDWriteTextLayout_Release(This->layout);
4610 heap_free(This);
4613 return ref;
4616 static HRESULT WINAPI dwritetrimmingsign_Draw(IDWriteInlineObject *iface, void *context, IDWriteTextRenderer *renderer,
4617 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *effect)
4619 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4620 DWRITE_TEXT_RANGE range = { 0, ~0u };
4621 HRESULT hr;
4623 TRACE("(%p)->(%p %p %.2f %.2f %d %d %p)\n", This, context, renderer, originX, originY, is_sideways, is_rtl, effect);
4625 IDWriteTextLayout_SetDrawingEffect(This->layout, effect, range);
4626 hr = IDWriteTextLayout_Draw(This->layout, context, renderer, originX, originY);
4627 IDWriteTextLayout_SetDrawingEffect(This->layout, NULL, range);
4628 return hr;
4631 static HRESULT WINAPI dwritetrimmingsign_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *ret)
4633 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4634 DWRITE_TEXT_METRICS metrics;
4635 HRESULT hr;
4637 TRACE("(%p)->(%p)\n", This, ret);
4639 hr = IDWriteTextLayout_GetMetrics(This->layout, &metrics);
4640 if (FAILED(hr)) {
4641 memset(ret, 0, sizeof(*ret));
4642 return hr;
4645 ret->width = metrics.width;
4646 ret->height = 0.0f;
4647 ret->baseline = 0.0f;
4648 ret->supportsSideways = FALSE;
4649 return S_OK;
4652 static HRESULT WINAPI dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
4654 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4655 FIXME("(%p)->(%p): stub\n", This, overhangs);
4656 return E_NOTIMPL;
4659 static HRESULT WINAPI dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
4660 DWRITE_BREAK_CONDITION *after)
4662 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4664 TRACE("(%p)->(%p %p)\n", This, before, after);
4666 *before = *after = DWRITE_BREAK_CONDITION_NEUTRAL;
4667 return S_OK;
4670 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl = {
4671 dwritetrimmingsign_QueryInterface,
4672 dwritetrimmingsign_AddRef,
4673 dwritetrimmingsign_Release,
4674 dwritetrimmingsign_Draw,
4675 dwritetrimmingsign_GetMetrics,
4676 dwritetrimmingsign_GetOverhangMetrics,
4677 dwritetrimmingsign_GetBreakConditions
4680 static inline BOOL is_reading_direction_horz(DWRITE_READING_DIRECTION direction)
4682 return (direction == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT) ||
4683 (direction == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
4686 static inline BOOL is_reading_direction_vert(DWRITE_READING_DIRECTION direction)
4688 return (direction == DWRITE_READING_DIRECTION_TOP_TO_BOTTOM) ||
4689 (direction == DWRITE_READING_DIRECTION_BOTTOM_TO_TOP);
4692 static inline BOOL is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction)
4694 return (direction == DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT) ||
4695 (direction == DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT);
4698 static inline BOOL is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction)
4700 return (direction == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM) ||
4701 (direction == DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP);
4704 HRESULT create_trimmingsign(IDWriteFactory2 *factory, IDWriteTextFormat *format, IDWriteInlineObject **sign)
4706 static const WCHAR ellipsisW = 0x2026;
4707 struct dwrite_trimmingsign *This;
4708 DWRITE_READING_DIRECTION reading;
4709 DWRITE_FLOW_DIRECTION flow;
4710 HRESULT hr;
4712 *sign = NULL;
4714 /* Validate reading/flow direction here, layout creation won't complain about
4715 invalid combinations. */
4716 reading = IDWriteTextFormat_GetReadingDirection(format);
4717 flow = IDWriteTextFormat_GetFlowDirection(format);
4719 if ((is_reading_direction_horz(reading) && is_flow_direction_horz(flow)) ||
4720 (is_reading_direction_vert(reading) && is_flow_direction_vert(flow)))
4721 return DWRITE_E_FLOWDIRECTIONCONFLICTS;
4723 This = heap_alloc(sizeof(*This));
4724 if (!This)
4725 return E_OUTOFMEMORY;
4727 This->IDWriteInlineObject_iface.lpVtbl = &dwritetrimmingsignvtbl;
4728 This->ref = 1;
4730 hr = IDWriteFactory2_CreateTextLayout(factory, &ellipsisW, 1, format, 0.0f, 0.0f, &This->layout);
4731 if (FAILED(hr)) {
4732 heap_free(This);
4733 return hr;
4736 IDWriteTextLayout_SetWordWrapping(This->layout, DWRITE_WORD_WRAPPING_NO_WRAP);
4737 *sign = &This->IDWriteInlineObject_iface;
4739 return S_OK;
4742 static HRESULT WINAPI dwritetextformat_QueryInterface(IDWriteTextFormat2 *iface, REFIID riid, void **obj)
4744 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4746 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4748 if (IsEqualIID(riid, &IID_IDWriteTextFormat2) ||
4749 IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
4750 IsEqualIID(riid, &IID_IDWriteTextFormat) ||
4751 IsEqualIID(riid, &IID_IUnknown))
4753 *obj = iface;
4754 IDWriteTextFormat2_AddRef(iface);
4755 return S_OK;
4758 *obj = NULL;
4760 return E_NOINTERFACE;
4763 static ULONG WINAPI dwritetextformat_AddRef(IDWriteTextFormat2 *iface)
4765 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4766 ULONG ref = InterlockedIncrement(&This->ref);
4767 TRACE("(%p)->(%d)\n", This, ref);
4768 return ref;
4771 static ULONG WINAPI dwritetextformat_Release(IDWriteTextFormat2 *iface)
4773 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4774 ULONG ref = InterlockedDecrement(&This->ref);
4776 TRACE("(%p)->(%d)\n", This, ref);
4778 if (!ref)
4780 release_format_data(&This->format);
4781 heap_free(This);
4784 return ref;
4787 static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat2 *iface, DWRITE_TEXT_ALIGNMENT alignment)
4789 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4790 TRACE("(%p)->(%d)\n", This, alignment);
4791 return format_set_textalignment(&This->format, alignment, NULL);
4794 static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat2 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
4796 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4797 TRACE("(%p)->(%d)\n", This, alignment);
4798 return format_set_paralignment(&This->format, alignment, NULL);
4801 static HRESULT WINAPI dwritetextformat_SetWordWrapping(IDWriteTextFormat2 *iface, DWRITE_WORD_WRAPPING wrapping)
4803 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4804 TRACE("(%p)->(%d)\n", This, wrapping);
4805 return format_set_wordwrapping(&This->format, wrapping, NULL);
4808 static HRESULT WINAPI dwritetextformat_SetReadingDirection(IDWriteTextFormat2 *iface, DWRITE_READING_DIRECTION direction)
4810 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4811 TRACE("(%p)->(%d)\n", This, direction);
4812 return format_set_readingdirection(&This->format, direction, NULL);
4815 static HRESULT WINAPI dwritetextformat_SetFlowDirection(IDWriteTextFormat2 *iface, DWRITE_FLOW_DIRECTION direction)
4817 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4818 TRACE("(%p)->(%d)\n", This, direction);
4819 return format_set_flowdirection(&This->format, direction, NULL);
4822 static HRESULT WINAPI dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat2 *iface, FLOAT tabstop)
4824 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4825 FIXME("(%p)->(%f): stub\n", This, tabstop);
4826 return E_NOTIMPL;
4829 static HRESULT WINAPI dwritetextformat_SetTrimming(IDWriteTextFormat2 *iface, DWRITE_TRIMMING const *trimming,
4830 IDWriteInlineObject *trimming_sign)
4832 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4833 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
4835 This->format.trimming = *trimming;
4836 if (This->format.trimmingsign)
4837 IDWriteInlineObject_Release(This->format.trimmingsign);
4838 This->format.trimmingsign = trimming_sign;
4839 if (This->format.trimmingsign)
4840 IDWriteInlineObject_AddRef(This->format.trimmingsign);
4841 return S_OK;
4844 static HRESULT WINAPI dwritetextformat_SetLineSpacing(IDWriteTextFormat2 *iface, DWRITE_LINE_SPACING_METHOD method,
4845 FLOAT spacing, FLOAT baseline)
4847 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4848 TRACE("(%p)->(%d %f %f)\n", This, method, spacing, baseline);
4849 return format_set_linespacing(&This->format, method, spacing, baseline, NULL);
4852 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_GetTextAlignment(IDWriteTextFormat2 *iface)
4854 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4855 TRACE("(%p)\n", This);
4856 return This->format.textalignment;
4859 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_GetParagraphAlignment(IDWriteTextFormat2 *iface)
4861 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4862 TRACE("(%p)\n", This);
4863 return This->format.paralign;
4866 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_GetWordWrapping(IDWriteTextFormat2 *iface)
4868 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4869 TRACE("(%p)\n", This);
4870 return This->format.wrapping;
4873 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_GetReadingDirection(IDWriteTextFormat2 *iface)
4875 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4876 TRACE("(%p)\n", This);
4877 return This->format.readingdir;
4880 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_GetFlowDirection(IDWriteTextFormat2 *iface)
4882 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4883 TRACE("(%p)\n", This);
4884 return This->format.flow;
4887 static FLOAT WINAPI dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat2 *iface)
4889 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4890 FIXME("(%p): stub\n", This);
4891 return 0.0f;
4894 static HRESULT WINAPI dwritetextformat_GetTrimming(IDWriteTextFormat2 *iface, DWRITE_TRIMMING *options,
4895 IDWriteInlineObject **trimming_sign)
4897 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4898 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
4900 *options = This->format.trimming;
4901 if ((*trimming_sign = This->format.trimmingsign))
4902 IDWriteInlineObject_AddRef(*trimming_sign);
4904 return S_OK;
4907 static HRESULT WINAPI dwritetextformat_GetLineSpacing(IDWriteTextFormat2 *iface, DWRITE_LINE_SPACING_METHOD *method,
4908 FLOAT *spacing, FLOAT *baseline)
4910 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4911 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
4913 *method = This->format.spacingmethod;
4914 *spacing = This->format.spacing;
4915 *baseline = This->format.baseline;
4916 return S_OK;
4919 static HRESULT WINAPI dwritetextformat_GetFontCollection(IDWriteTextFormat2 *iface, IDWriteFontCollection **collection)
4921 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4923 TRACE("(%p)->(%p)\n", This, collection);
4925 *collection = This->format.collection;
4926 IDWriteFontCollection_AddRef(*collection);
4928 return S_OK;
4931 static UINT32 WINAPI dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat2 *iface)
4933 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4934 TRACE("(%p)\n", This);
4935 return This->format.family_len;
4938 static HRESULT WINAPI dwritetextformat_GetFontFamilyName(IDWriteTextFormat2 *iface, WCHAR *name, UINT32 size)
4940 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4942 TRACE("(%p)->(%p %u)\n", This, name, size);
4944 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
4945 strcpyW(name, This->format.family_name);
4946 return S_OK;
4949 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_GetFontWeight(IDWriteTextFormat2 *iface)
4951 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4952 TRACE("(%p)\n", This);
4953 return This->format.weight;
4956 static DWRITE_FONT_STYLE WINAPI dwritetextformat_GetFontStyle(IDWriteTextFormat2 *iface)
4958 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4959 TRACE("(%p)\n", This);
4960 return This->format.style;
4963 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_GetFontStretch(IDWriteTextFormat2 *iface)
4965 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4966 TRACE("(%p)\n", This);
4967 return This->format.stretch;
4970 static FLOAT WINAPI dwritetextformat_GetFontSize(IDWriteTextFormat2 *iface)
4972 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4973 TRACE("(%p)\n", This);
4974 return This->format.fontsize;
4977 static UINT32 WINAPI dwritetextformat_GetLocaleNameLength(IDWriteTextFormat2 *iface)
4979 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4980 TRACE("(%p)\n", This);
4981 return This->format.locale_len;
4984 static HRESULT WINAPI dwritetextformat_GetLocaleName(IDWriteTextFormat2 *iface, WCHAR *name, UINT32 size)
4986 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4988 TRACE("(%p)->(%p %u)\n", This, name, size);
4990 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
4991 strcpyW(name, This->format.locale);
4992 return S_OK;
4995 static HRESULT WINAPI dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat2 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4997 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4999 TRACE("(%p)->(%d)\n", This, orientation);
5001 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
5002 return E_INVALIDARG;
5004 This->format.vertical_orientation = orientation;
5005 return S_OK;
5008 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat2 *iface)
5010 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5011 TRACE("(%p)\n", This);
5012 return This->format.vertical_orientation;
5015 static HRESULT WINAPI dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat2 *iface, BOOL lastline_wrapping_enabled)
5017 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5019 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
5021 This->format.last_line_wrapping = !!lastline_wrapping_enabled;
5022 return S_OK;
5025 static BOOL WINAPI dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat2 *iface)
5027 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5028 TRACE("(%p)\n", This);
5029 return This->format.last_line_wrapping;
5032 static HRESULT WINAPI dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat2 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
5034 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5035 TRACE("(%p)->(%d)\n", This, alignment);
5036 return format_set_optical_alignment(&This->format, alignment);
5039 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat2 *iface)
5041 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5042 TRACE("(%p)\n", This);
5043 return This->format.optical_alignment;
5046 static HRESULT WINAPI dwritetextformat1_SetFontFallback(IDWriteTextFormat2 *iface, IDWriteFontFallback *fallback)
5048 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5049 TRACE("(%p)->(%p)\n", This, fallback);
5050 return set_fontfallback_for_format(&This->format, fallback);
5053 static HRESULT WINAPI dwritetextformat1_GetFontFallback(IDWriteTextFormat2 *iface, IDWriteFontFallback **fallback)
5055 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5056 TRACE("(%p)->(%p)\n", This, fallback);
5057 return get_fontfallback_from_format(&This->format, fallback);
5060 static HRESULT WINAPI dwritetextformat2_SetLineSpacing(IDWriteTextFormat2 *iface, DWRITE_LINE_SPACING const *spacing)
5062 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5063 FIXME("(%p)->(%p): stub\n", This, spacing);
5064 return E_NOTIMPL;
5067 static HRESULT WINAPI dwritetextformat2_GetLineSpacing(IDWriteTextFormat2 *iface, DWRITE_LINE_SPACING *spacing)
5069 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5070 FIXME("(%p)->(%p): stub\n", This, spacing);
5071 return E_NOTIMPL;
5074 static const IDWriteTextFormat2Vtbl dwritetextformatvtbl = {
5075 dwritetextformat_QueryInterface,
5076 dwritetextformat_AddRef,
5077 dwritetextformat_Release,
5078 dwritetextformat_SetTextAlignment,
5079 dwritetextformat_SetParagraphAlignment,
5080 dwritetextformat_SetWordWrapping,
5081 dwritetextformat_SetReadingDirection,
5082 dwritetextformat_SetFlowDirection,
5083 dwritetextformat_SetIncrementalTabStop,
5084 dwritetextformat_SetTrimming,
5085 dwritetextformat_SetLineSpacing,
5086 dwritetextformat_GetTextAlignment,
5087 dwritetextformat_GetParagraphAlignment,
5088 dwritetextformat_GetWordWrapping,
5089 dwritetextformat_GetReadingDirection,
5090 dwritetextformat_GetFlowDirection,
5091 dwritetextformat_GetIncrementalTabStop,
5092 dwritetextformat_GetTrimming,
5093 dwritetextformat_GetLineSpacing,
5094 dwritetextformat_GetFontCollection,
5095 dwritetextformat_GetFontFamilyNameLength,
5096 dwritetextformat_GetFontFamilyName,
5097 dwritetextformat_GetFontWeight,
5098 dwritetextformat_GetFontStyle,
5099 dwritetextformat_GetFontStretch,
5100 dwritetextformat_GetFontSize,
5101 dwritetextformat_GetLocaleNameLength,
5102 dwritetextformat_GetLocaleName,
5103 dwritetextformat1_SetVerticalGlyphOrientation,
5104 dwritetextformat1_GetVerticalGlyphOrientation,
5105 dwritetextformat1_SetLastLineWrapping,
5106 dwritetextformat1_GetLastLineWrapping,
5107 dwritetextformat1_SetOpticalAlignment,
5108 dwritetextformat1_GetOpticalAlignment,
5109 dwritetextformat1_SetFontFallback,
5110 dwritetextformat1_GetFontFallback,
5111 dwritetextformat2_SetLineSpacing,
5112 dwritetextformat2_GetLineSpacing
5115 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat *iface)
5117 return (iface->lpVtbl == (IDWriteTextFormatVtbl*)&dwritetextformatvtbl) ?
5118 CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat2_iface) : NULL;
5121 HRESULT create_textformat(const WCHAR *family_name, IDWriteFontCollection *collection, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style,
5122 DWRITE_FONT_STRETCH stretch, FLOAT size, const WCHAR *locale, IDWriteTextFormat **format)
5124 struct dwrite_textformat *This;
5126 *format = NULL;
5128 This = heap_alloc(sizeof(struct dwrite_textformat));
5129 if (!This) return E_OUTOFMEMORY;
5131 This->IDWriteTextFormat2_iface.lpVtbl = &dwritetextformatvtbl;
5132 This->ref = 1;
5133 This->format.family_name = heap_strdupW(family_name);
5134 This->format.family_len = strlenW(family_name);
5135 This->format.locale = heap_strdupW(locale);
5136 This->format.locale_len = strlenW(locale);
5137 /* force locale name to lower case, layout will inherit this modified value */
5138 strlwrW(This->format.locale);
5139 This->format.weight = weight;
5140 This->format.style = style;
5141 This->format.fontsize = size;
5142 This->format.stretch = stretch;
5143 This->format.textalignment = DWRITE_TEXT_ALIGNMENT_LEADING;
5144 This->format.optical_alignment = DWRITE_OPTICAL_ALIGNMENT_NONE;
5145 This->format.paralign = DWRITE_PARAGRAPH_ALIGNMENT_NEAR;
5146 This->format.wrapping = DWRITE_WORD_WRAPPING_WRAP;
5147 This->format.last_line_wrapping = TRUE;
5148 This->format.readingdir = DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
5149 This->format.flow = DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM;
5150 This->format.spacingmethod = DWRITE_LINE_SPACING_METHOD_DEFAULT;
5151 This->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
5152 This->format.spacing = 0.0f;
5153 This->format.baseline = 0.0f;
5154 This->format.trimming.granularity = DWRITE_TRIMMING_GRANULARITY_NONE;
5155 This->format.trimming.delimiter = 0;
5156 This->format.trimming.delimiterCount = 0;
5157 This->format.trimmingsign = NULL;
5158 This->format.collection = collection;
5159 This->format.fallback = NULL;
5160 IDWriteFontCollection_AddRef(collection);
5162 *format = (IDWriteTextFormat*)&This->IDWriteTextFormat2_iface;
5164 return S_OK;
5167 static HRESULT WINAPI dwritetypography_QueryInterface(IDWriteTypography *iface, REFIID riid, void **obj)
5169 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5171 TRACE("(%p)->(%s %p)\n", typography, debugstr_guid(riid), obj);
5173 if (IsEqualIID(riid, &IID_IDWriteTypography) || IsEqualIID(riid, &IID_IUnknown)) {
5174 *obj = iface;
5175 IDWriteTypography_AddRef(iface);
5176 return S_OK;
5179 *obj = NULL;
5181 return E_NOINTERFACE;
5184 static ULONG WINAPI dwritetypography_AddRef(IDWriteTypography *iface)
5186 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5187 ULONG ref = InterlockedIncrement(&typography->ref);
5188 TRACE("(%p)->(%d)\n", typography, ref);
5189 return ref;
5192 static ULONG WINAPI dwritetypography_Release(IDWriteTypography *iface)
5194 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5195 ULONG ref = InterlockedDecrement(&typography->ref);
5197 TRACE("(%p)->(%d)\n", typography, ref);
5199 if (!ref) {
5200 heap_free(typography->features);
5201 heap_free(typography);
5204 return ref;
5207 static HRESULT WINAPI dwritetypography_AddFontFeature(IDWriteTypography *iface, DWRITE_FONT_FEATURE feature)
5209 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5211 TRACE("(%p)->(%x %u)\n", typography, feature.nameTag, feature.parameter);
5213 if (typography->count == typography->allocated) {
5214 DWRITE_FONT_FEATURE *ptr = heap_realloc(typography->features, 2*typography->allocated*sizeof(DWRITE_FONT_FEATURE));
5215 if (!ptr)
5216 return E_OUTOFMEMORY;
5218 typography->features = ptr;
5219 typography->allocated *= 2;
5222 typography->features[typography->count++] = feature;
5223 return S_OK;
5226 static UINT32 WINAPI dwritetypography_GetFontFeatureCount(IDWriteTypography *iface)
5228 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5229 TRACE("(%p)\n", typography);
5230 return typography->count;
5233 static HRESULT WINAPI dwritetypography_GetFontFeature(IDWriteTypography *iface, UINT32 index, DWRITE_FONT_FEATURE *feature)
5235 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5237 TRACE("(%p)->(%u %p)\n", typography, index, feature);
5239 if (index >= typography->count)
5240 return E_INVALIDARG;
5242 *feature = typography->features[index];
5243 return S_OK;
5246 static const IDWriteTypographyVtbl dwritetypographyvtbl = {
5247 dwritetypography_QueryInterface,
5248 dwritetypography_AddRef,
5249 dwritetypography_Release,
5250 dwritetypography_AddFontFeature,
5251 dwritetypography_GetFontFeatureCount,
5252 dwritetypography_GetFontFeature
5255 HRESULT create_typography(IDWriteTypography **ret)
5257 struct dwrite_typography *typography;
5259 *ret = NULL;
5261 typography = heap_alloc(sizeof(*typography));
5262 if (!typography)
5263 return E_OUTOFMEMORY;
5265 typography->IDWriteTypography_iface.lpVtbl = &dwritetypographyvtbl;
5266 typography->ref = 1;
5267 typography->allocated = 2;
5268 typography->count = 0;
5270 typography->features = heap_alloc(typography->allocated*sizeof(DWRITE_FONT_FEATURE));
5271 if (!typography->features) {
5272 heap_free(typography);
5273 return E_OUTOFMEMORY;
5276 *ret = &typography->IDWriteTypography_iface;
5277 return S_OK;