dwrite: Partially implement GetSystemFontCollection().
[wine.git] / dlls / dwrite / layout.c
blob8a736f9e2a1530f9472ecdd03dde05000a493f09
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"
32 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
34 struct dwrite_textformat_data {
35 WCHAR *family_name;
36 UINT32 family_len;
37 WCHAR *locale;
38 UINT32 locale_len;
40 DWRITE_FONT_WEIGHT weight;
41 DWRITE_FONT_STYLE style;
42 DWRITE_FONT_STRETCH stretch;
44 DWRITE_PARAGRAPH_ALIGNMENT paralign;
45 DWRITE_READING_DIRECTION readingdir;
46 DWRITE_WORD_WRAPPING wrapping;
47 BOOL last_line_wrapping;
48 DWRITE_TEXT_ALIGNMENT textalignment;
49 DWRITE_FLOW_DIRECTION flow;
50 DWRITE_LINE_SPACING_METHOD spacingmethod;
51 DWRITE_VERTICAL_GLYPH_ORIENTATION vertical_orientation;
52 DWRITE_OPTICAL_ALIGNMENT optical_alignment;
54 FLOAT spacing;
55 FLOAT baseline;
56 FLOAT fontsize;
58 DWRITE_TRIMMING trimming;
59 IDWriteInlineObject *trimmingsign;
61 IDWriteFontCollection *collection;
62 IDWriteFontFallback *fallback;
65 enum layout_range_attr_kind {
66 LAYOUT_RANGE_ATTR_WEIGHT,
67 LAYOUT_RANGE_ATTR_STYLE,
68 LAYOUT_RANGE_ATTR_STRETCH,
69 LAYOUT_RANGE_ATTR_FONTSIZE,
70 LAYOUT_RANGE_ATTR_EFFECT,
71 LAYOUT_RANGE_ATTR_INLINE,
72 LAYOUT_RANGE_ATTR_UNDERLINE,
73 LAYOUT_RANGE_ATTR_STRIKETHROUGH,
74 LAYOUT_RANGE_ATTR_PAIR_KERNING,
75 LAYOUT_RANGE_ATTR_FONTCOLL,
76 LAYOUT_RANGE_ATTR_LOCALE,
77 LAYOUT_RANGE_ATTR_FONTFAMILY,
78 LAYOUT_RANGE_ATTR_SPACING,
79 LAYOUT_RANGE_ATTR_TYPOGRAPHY
82 struct layout_range_attr_value {
83 DWRITE_TEXT_RANGE range;
84 union {
85 DWRITE_FONT_WEIGHT weight;
86 DWRITE_FONT_STYLE style;
87 DWRITE_FONT_STRETCH stretch;
88 FLOAT fontsize;
89 IDWriteInlineObject *object;
90 IUnknown *effect;
91 BOOL underline;
92 BOOL strikethrough;
93 BOOL pair_kerning;
94 IDWriteFontCollection *collection;
95 const WCHAR *locale;
96 const WCHAR *fontfamily;
97 FLOAT spacing[3]; /* in arguments order - leading, trailing, advance */
98 IDWriteTypography *typography;
99 } u;
102 enum layout_range_kind {
103 LAYOUT_RANGE_REGULAR,
104 LAYOUT_RANGE_UNDERLINE,
105 LAYOUT_RANGE_STRIKETHROUGH,
106 LAYOUT_RANGE_EFFECT,
107 LAYOUT_RANGE_SPACING,
108 LAYOUT_RANGE_TYPOGRAPHY
111 struct layout_range_header {
112 struct list entry;
113 enum layout_range_kind kind;
114 DWRITE_TEXT_RANGE range;
117 struct layout_range {
118 struct layout_range_header h;
119 DWRITE_FONT_WEIGHT weight;
120 DWRITE_FONT_STYLE style;
121 FLOAT fontsize;
122 DWRITE_FONT_STRETCH stretch;
123 IDWriteInlineObject *object;
124 BOOL pair_kerning;
125 IDWriteFontCollection *collection;
126 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
127 WCHAR *fontfamily;
130 struct layout_range_bool {
131 struct layout_range_header h;
132 BOOL value;
135 struct layout_range_iface {
136 struct layout_range_header h;
137 IUnknown *iface;
140 struct layout_range_spacing {
141 struct layout_range_header h;
142 FLOAT leading;
143 FLOAT trailing;
144 FLOAT min_advance;
147 enum layout_run_kind {
148 LAYOUT_RUN_REGULAR,
149 LAYOUT_RUN_INLINE
152 struct inline_object_run {
153 IDWriteInlineObject *object;
154 UINT16 length;
157 struct regular_layout_run {
158 DWRITE_GLYPH_RUN_DESCRIPTION descr;
159 DWRITE_GLYPH_RUN run;
160 DWRITE_SCRIPT_ANALYSIS sa;
161 UINT16 *glyphs;
162 UINT16 *clustermap;
163 FLOAT *advances;
164 DWRITE_GLYPH_OFFSET *offsets;
165 /* this is actual glyph count after shaping, it's not necessary the same as reported to Draw() */
166 UINT32 glyphcount;
169 struct layout_run {
170 struct list entry;
171 enum layout_run_kind kind;
172 union {
173 struct inline_object_run object;
174 struct regular_layout_run regular;
175 } u;
176 FLOAT baseline;
177 FLOAT height;
180 struct layout_effective_run {
181 struct list entry;
182 const struct layout_run *run; /* nominal run this one is based on */
183 UINT32 start; /* relative text position, 0 means first text position of a nominal run */
184 UINT32 length; /* length in codepoints that this run covers */
185 UINT32 glyphcount; /* total glyph count in this run */
186 IUnknown *effect; /* original reference is kept only at range level */
187 FLOAT origin_x; /* baseline X position */
188 FLOAT origin_y; /* baseline Y position */
189 FLOAT align_dx; /* adjustment from text alignment */
190 FLOAT width; /* run width */
191 UINT16 *clustermap; /* effective clustermap, allocated separately, is not reused from nominal map */
192 UINT32 line; /* 0-based line index in line metrics array */
193 BOOL underlined; /* set if this run is underlined */
196 struct layout_effective_inline {
197 struct list entry;
198 const struct layout_run *run; /* nominal run this one is based on */
199 IUnknown *effect; /* original reference is kept only at range level */
200 FLOAT origin_x; /* left X position */
201 FLOAT origin_y; /* left top corner Y position */
202 FLOAT align_dx; /* adjustment from text alignment */
203 FLOAT width; /* object width as it's reported it */
204 BOOL is_sideways; /* vertical flow direction flag passed to Draw */
205 BOOL is_rtl; /* bidi flag passed to Draw */
206 UINT32 line; /* 0-based line index in line metrics array */
209 struct layout_underline {
210 struct list entry;
211 const struct layout_effective_run *run;
212 DWRITE_UNDERLINE u;
215 struct layout_strikethrough {
216 struct list entry;
217 const struct layout_effective_run *run;
218 DWRITE_STRIKETHROUGH s;
221 struct layout_cluster {
222 const struct layout_run *run; /* link to nominal run this cluster belongs to */
223 UINT32 position; /* relative to run, first cluster has 0 position */
226 enum layout_recompute_mask {
227 RECOMPUTE_NOMINAL_RUNS = 1 << 0,
228 RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
229 RECOMPUTE_EFFECTIVE_RUNS = 1 << 2,
230 RECOMPUTE_EVERYTHING = 0xffff
233 struct dwrite_textlayout {
234 IDWriteTextLayout3 IDWriteTextLayout3_iface;
235 IDWriteTextFormat1 IDWriteTextFormat1_iface;
236 IDWriteTextAnalysisSink1 IDWriteTextAnalysisSink1_iface;
237 IDWriteTextAnalysisSource1 IDWriteTextAnalysisSource1_iface;
238 LONG ref;
240 IDWriteFactory3 *factory;
242 WCHAR *str;
243 UINT32 len;
244 struct dwrite_textformat_data format;
245 struct list strike_ranges;
246 struct list underline_ranges;
247 struct list typographies;
248 struct list effects;
249 struct list spacing;
250 struct list ranges;
251 struct list runs;
252 /* lists ready to use by Draw() */
253 struct list eruns;
254 struct list inlineobjects;
255 struct list underlines;
256 struct list strikethrough;
257 USHORT recompute;
259 DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
260 DWRITE_LINE_BREAKPOINT *actual_breakpoints;
262 struct layout_cluster *clusters;
263 DWRITE_CLUSTER_METRICS *clustermetrics;
264 UINT32 cluster_count;
265 FLOAT minwidth;
267 DWRITE_LINE_METRICS *lines;
268 UINT32 line_alloc;
270 DWRITE_TEXT_METRICS1 metrics;
272 DWRITE_MEASURING_MODE measuringmode;
274 /* gdi-compatible layout specifics */
275 FLOAT ppdip;
276 DWRITE_MATRIX transform;
279 struct dwrite_textformat {
280 IDWriteTextFormat2 IDWriteTextFormat2_iface;
281 LONG ref;
282 struct dwrite_textformat_data format;
285 struct dwrite_trimmingsign {
286 IDWriteInlineObject IDWriteInlineObject_iface;
287 LONG ref;
289 IDWriteTextLayout *layout;
292 struct dwrite_typography {
293 IDWriteTypography IDWriteTypography_iface;
294 LONG ref;
296 DWRITE_FONT_FEATURE *features;
297 UINT32 allocated;
298 UINT32 count;
301 struct dwrite_vec {
302 FLOAT x;
303 FLOAT y;
306 static const IDWriteTextFormat2Vtbl dwritetextformatvtbl;
308 static void release_format_data(struct dwrite_textformat_data *data)
310 if (data->collection) IDWriteFontCollection_Release(data->collection);
311 if (data->fallback) IDWriteFontFallback_Release(data->fallback);
312 if (data->trimmingsign) IDWriteInlineObject_Release(data->trimmingsign);
313 heap_free(data->family_name);
314 heap_free(data->locale);
317 static inline struct dwrite_textlayout *impl_from_IDWriteTextLayout3(IDWriteTextLayout3 *iface)
319 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextLayout3_iface);
322 static inline struct dwrite_textlayout *impl_layout_from_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
324 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextFormat1_iface);
327 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSink1(IDWriteTextAnalysisSink1 *iface)
329 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSink1_iface);
332 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSource1(IDWriteTextAnalysisSource1 *iface)
334 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSource1_iface);
337 static inline struct dwrite_textformat *impl_from_IDWriteTextFormat2(IDWriteTextFormat2 *iface)
339 return CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat2_iface);
342 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat*);
344 static inline struct dwrite_trimmingsign *impl_from_IDWriteInlineObject(IDWriteInlineObject *iface)
346 return CONTAINING_RECORD(iface, struct dwrite_trimmingsign, IDWriteInlineObject_iface);
349 static inline struct dwrite_typography *impl_from_IDWriteTypography(IDWriteTypography *iface)
351 return CONTAINING_RECORD(iface, struct dwrite_typography, IDWriteTypography_iface);
354 static inline const char *debugstr_rundescr(const DWRITE_GLYPH_RUN_DESCRIPTION *descr)
356 return wine_dbg_sprintf("[%u,%u)", descr->textPosition, descr->textPosition + descr->stringLength);
359 static inline BOOL is_layout_gdi_compatible(struct dwrite_textlayout *layout)
361 return layout->measuringmode != DWRITE_MEASURING_MODE_NATURAL;
364 static inline HRESULT format_set_textalignment(struct dwrite_textformat_data *format, DWRITE_TEXT_ALIGNMENT alignment,
365 BOOL *changed)
367 if ((UINT32)alignment > DWRITE_TEXT_ALIGNMENT_JUSTIFIED)
368 return E_INVALIDARG;
369 if (changed) *changed = format->textalignment != alignment;
370 format->textalignment = alignment;
371 return S_OK;
374 static inline HRESULT format_set_paralignment(struct dwrite_textformat_data *format,
375 DWRITE_PARAGRAPH_ALIGNMENT alignment, BOOL *changed)
377 if ((UINT32)alignment > DWRITE_PARAGRAPH_ALIGNMENT_CENTER)
378 return E_INVALIDARG;
379 if (changed) *changed = format->paralign != alignment;
380 format->paralign = alignment;
381 return S_OK;
384 static inline HRESULT format_set_readingdirection(struct dwrite_textformat_data *format,
385 DWRITE_READING_DIRECTION direction, BOOL *changed)
387 if ((UINT32)direction > DWRITE_READING_DIRECTION_BOTTOM_TO_TOP)
388 return E_INVALIDARG;
389 if (changed) *changed = format->readingdir != direction;
390 format->readingdir = direction;
391 return S_OK;
394 static inline HRESULT format_set_wordwrapping(struct dwrite_textformat_data *format,
395 DWRITE_WORD_WRAPPING wrapping, BOOL *changed)
397 if ((UINT32)wrapping > DWRITE_WORD_WRAPPING_CHARACTER)
398 return E_INVALIDARG;
399 if (changed) *changed = format->wrapping != wrapping;
400 format->wrapping = wrapping;
401 return S_OK;
404 static inline HRESULT format_set_flowdirection(struct dwrite_textformat_data *format,
405 DWRITE_FLOW_DIRECTION direction, BOOL *changed)
407 if ((UINT32)direction > DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT)
408 return E_INVALIDARG;
409 if (changed) *changed = format->flow != direction;
410 format->flow = direction;
411 return S_OK;
414 static inline HRESULT format_set_linespacing(struct dwrite_textformat_data *format,
415 DWRITE_LINE_SPACING_METHOD method, FLOAT spacing, FLOAT baseline, BOOL *changed)
417 if (spacing < 0.0f || (UINT32)method > DWRITE_LINE_SPACING_METHOD_UNIFORM)
418 return E_INVALIDARG;
420 if (changed) *changed = format->spacingmethod != method ||
421 format->spacing != spacing || format->baseline != baseline;
423 format->spacingmethod = method;
424 format->spacing = spacing;
425 format->baseline = baseline;
426 return S_OK;
429 static HRESULT get_fontfallback_from_format(const struct dwrite_textformat_data *format, IDWriteFontFallback **fallback)
431 *fallback = format->fallback;
432 if (*fallback)
433 IDWriteFontFallback_AddRef(*fallback);
434 return S_OK;
437 static HRESULT set_fontfallback_for_format(struct dwrite_textformat_data *format, IDWriteFontFallback *fallback)
439 if (format->fallback)
440 IDWriteFontFallback_Release(format->fallback);
441 format->fallback = fallback;
442 if (fallback)
443 IDWriteFontFallback_AddRef(fallback);
444 return S_OK;
447 static HRESULT format_set_optical_alignment(struct dwrite_textformat_data *format,
448 DWRITE_OPTICAL_ALIGNMENT alignment)
450 if ((UINT32)alignment > DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS)
451 return E_INVALIDARG;
452 format->optical_alignment = alignment;
453 return S_OK;
456 static BOOL is_run_rtl(const struct layout_effective_run *run)
458 return run->run->u.regular.run.bidiLevel & 1;
461 static struct layout_run *alloc_layout_run(enum layout_run_kind kind)
463 struct layout_run *ret;
465 ret = heap_alloc(sizeof(*ret));
466 if (!ret) return NULL;
468 memset(ret, 0, sizeof(*ret));
469 ret->kind = kind;
470 if (kind == LAYOUT_RUN_REGULAR) {
471 ret->u.regular.sa.script = Script_Unknown;
472 ret->u.regular.sa.shapes = DWRITE_SCRIPT_SHAPES_DEFAULT;
475 return ret;
478 static void free_layout_runs(struct dwrite_textlayout *layout)
480 struct layout_run *cur, *cur2;
481 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->runs, struct layout_run, entry) {
482 list_remove(&cur->entry);
483 if (cur->kind == LAYOUT_RUN_REGULAR) {
484 if (cur->u.regular.run.fontFace)
485 IDWriteFontFace_Release(cur->u.regular.run.fontFace);
486 heap_free(cur->u.regular.glyphs);
487 heap_free(cur->u.regular.clustermap);
488 heap_free(cur->u.regular.advances);
489 heap_free(cur->u.regular.offsets);
491 heap_free(cur);
495 static void free_layout_eruns(struct dwrite_textlayout *layout)
497 struct layout_effective_inline *in, *in2;
498 struct layout_effective_run *cur, *cur2;
499 struct layout_strikethrough *s, *s2;
500 struct layout_underline *u, *u2;
502 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->eruns, struct layout_effective_run, entry) {
503 list_remove(&cur->entry);
504 heap_free(cur->clustermap);
505 heap_free(cur);
508 LIST_FOR_EACH_ENTRY_SAFE(in, in2, &layout->inlineobjects, struct layout_effective_inline, entry) {
509 list_remove(&in->entry);
510 heap_free(in);
513 LIST_FOR_EACH_ENTRY_SAFE(u, u2, &layout->underlines, struct layout_underline, entry) {
514 list_remove(&u->entry);
515 heap_free(u);
518 LIST_FOR_EACH_ENTRY_SAFE(s, s2, &layout->strikethrough, struct layout_strikethrough, entry) {
519 list_remove(&s->entry);
520 heap_free(s);
524 /* Used to resolve break condition by forcing stronger condition over weaker. */
525 static inline DWRITE_BREAK_CONDITION override_break_condition(DWRITE_BREAK_CONDITION existingbreak, DWRITE_BREAK_CONDITION newbreak)
527 switch (existingbreak) {
528 case DWRITE_BREAK_CONDITION_NEUTRAL:
529 return newbreak;
530 case DWRITE_BREAK_CONDITION_CAN_BREAK:
531 return newbreak == DWRITE_BREAK_CONDITION_NEUTRAL ? existingbreak : newbreak;
532 /* let's keep stronger conditions as is */
533 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK:
534 case DWRITE_BREAK_CONDITION_MUST_BREAK:
535 break;
536 default:
537 ERR("unknown break condition %d\n", existingbreak);
540 return existingbreak;
543 /* This helper should be used to get effective range length, in other words it returns number of text
544 positions from range starting point to the end of the range, limited by layout text length */
545 static inline UINT32 get_clipped_range_length(const struct dwrite_textlayout *layout, const struct layout_range *range)
547 if (range->h.range.startPosition + range->h.range.length <= layout->len)
548 return range->h.range.length;
549 return layout->len - range->h.range.startPosition;
552 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
553 static HRESULT layout_update_breakpoints_range(struct dwrite_textlayout *layout, const struct layout_range *cur)
555 DWRITE_BREAK_CONDITION before, after;
556 UINT32 i, length;
557 HRESULT hr;
559 /* ignore returned conditions if failed */
560 hr = IDWriteInlineObject_GetBreakConditions(cur->object, &before, &after);
561 if (FAILED(hr))
562 after = before = DWRITE_BREAK_CONDITION_NEUTRAL;
564 if (!layout->actual_breakpoints) {
565 layout->actual_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
566 if (!layout->actual_breakpoints)
567 return E_OUTOFMEMORY;
568 memcpy(layout->actual_breakpoints, layout->nominal_breakpoints, sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
571 length = get_clipped_range_length(layout, cur);
572 for (i = cur->h.range.startPosition; i < length + cur->h.range.startPosition; i++) {
573 /* for first codepoint check if there's anything before it and update accordingly */
574 if (i == cur->h.range.startPosition) {
575 if (i > 0)
576 layout->actual_breakpoints[i].breakConditionBefore = layout->actual_breakpoints[i-1].breakConditionAfter =
577 override_break_condition(layout->actual_breakpoints[i-1].breakConditionAfter, before);
578 else
579 layout->actual_breakpoints[i].breakConditionBefore = before;
580 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
582 /* similar check for last codepoint */
583 else if (i == cur->h.range.startPosition + length - 1) {
584 if (i == layout->len - 1)
585 layout->actual_breakpoints[i].breakConditionAfter = after;
586 else
587 layout->actual_breakpoints[i].breakConditionAfter = layout->actual_breakpoints[i+1].breakConditionBefore =
588 override_break_condition(layout->actual_breakpoints[i+1].breakConditionBefore, after);
589 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
591 /* for all positions within a range disable breaks */
592 else {
593 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
594 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
597 layout->actual_breakpoints[i].isWhitespace = 0;
598 layout->actual_breakpoints[i].isSoftHyphen = 0;
601 return S_OK;
604 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos);
606 static inline DWRITE_LINE_BREAKPOINT get_effective_breakpoint(const struct dwrite_textlayout *layout, UINT32 pos)
608 if (layout->actual_breakpoints)
609 return layout->actual_breakpoints[pos];
610 return layout->nominal_breakpoints[pos];
613 static inline void init_cluster_metrics(const struct dwrite_textlayout *layout, const struct regular_layout_run *run,
614 UINT16 start_glyph, UINT16 stop_glyph, UINT32 stop_position, UINT16 length, DWRITE_CLUSTER_METRICS *metrics)
616 UINT8 breakcondition;
617 UINT32 position;
618 UINT16 j;
620 /* For clusters made of control chars we report zero glyphs, and we need zero cluster
621 width as well; advances are already computed at this point and are not necessary zero. */
622 metrics->width = 0.0f;
623 if (run->run.glyphCount) {
624 for (j = start_glyph; j < stop_glyph; j++)
625 metrics->width += run->run.glyphAdvances[j];
627 metrics->length = length;
629 position = run->descr.textPosition + stop_position;
630 if (stop_glyph == run->glyphcount)
631 breakcondition = get_effective_breakpoint(layout, position).breakConditionAfter;
632 else {
633 breakcondition = get_effective_breakpoint(layout, position).breakConditionBefore;
634 if (stop_position) position -= 1;
637 metrics->canWrapLineAfter = breakcondition == DWRITE_BREAK_CONDITION_CAN_BREAK ||
638 breakcondition == DWRITE_BREAK_CONDITION_MUST_BREAK;
639 if (metrics->length == 1) {
640 DWRITE_LINE_BREAKPOINT bp = get_effective_breakpoint(layout, position);
641 metrics->isWhitespace = bp.isWhitespace;
642 metrics->isNewline = metrics->canWrapLineAfter && lb_is_newline_char(layout->str[position]);
643 metrics->isSoftHyphen = bp.isSoftHyphen;
645 else {
646 metrics->isWhitespace = 0;
647 metrics->isNewline = 0;
648 metrics->isSoftHyphen = 0;
650 metrics->isRightToLeft = run->run.bidiLevel & 1;
651 metrics->padding = 0;
656 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
657 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
658 Note that there's no need to reallocate anything at this point as we allocate one cluster per
659 codepoint initially.
662 static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 *cluster)
664 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[*cluster];
665 struct layout_cluster *c = &layout->clusters[*cluster];
666 const struct regular_layout_run *run = &r->u.regular;
667 UINT32 i, start = 0;
669 for (i = 0; i < run->descr.stringLength; i++) {
670 BOOL end = i == run->descr.stringLength - 1;
672 if (run->descr.clusterMap[start] != run->descr.clusterMap[i]) {
673 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->descr.clusterMap[i], i,
674 i - start, metrics);
675 c->position = start;
676 c->run = r;
678 *cluster += 1;
679 metrics++;
680 c++;
681 start = i;
684 if (end) {
685 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->glyphcount, i,
686 i - start + 1, metrics);
687 c->position = start;
688 c->run = r;
690 *cluster += 1;
691 return;
696 #define SCALE_FONT_METRIC(metric, emSize, metrics) ((FLOAT)(metric) * (emSize) / (FLOAT)(metrics)->designUnitsPerEm)
698 static void layout_get_font_metrics(struct dwrite_textlayout *layout, IDWriteFontFace *fontface, FLOAT emsize,
699 DWRITE_FONT_METRICS *fontmetrics)
701 if (is_layout_gdi_compatible(layout)) {
702 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(fontface, emsize, layout->ppdip, &layout->transform, fontmetrics);
703 if (FAILED(hr))
704 WARN("failed to get compat metrics, 0x%08x\n", hr);
706 else
707 IDWriteFontFace_GetMetrics(fontface, fontmetrics);
710 static void layout_get_font_height(FLOAT emsize, DWRITE_FONT_METRICS *fontmetrics, FLOAT *baseline, FLOAT *height)
712 *baseline = SCALE_FONT_METRIC(fontmetrics->ascent + fontmetrics->lineGap, emsize, fontmetrics);
713 *height = SCALE_FONT_METRIC(fontmetrics->ascent + fontmetrics->descent + fontmetrics->lineGap, emsize, fontmetrics);
716 static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
718 IDWriteFontFallback *fallback;
719 IDWriteTextAnalyzer *analyzer;
720 struct layout_range *range;
721 struct layout_run *r;
722 UINT32 cluster = 0;
723 HRESULT hr;
725 free_layout_eruns(layout);
726 free_layout_runs(layout);
728 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
729 if (!layout->clustermetrics && layout->len) {
730 layout->clustermetrics = heap_alloc(layout->len*sizeof(*layout->clustermetrics));
731 layout->clusters = heap_alloc(layout->len*sizeof(*layout->clusters));
732 if (!layout->clustermetrics || !layout->clusters) {
733 heap_free(layout->clustermetrics);
734 heap_free(layout->clusters);
735 return E_OUTOFMEMORY;
738 layout->cluster_count = 0;
740 hr = get_textanalyzer(&analyzer);
741 if (FAILED(hr))
742 return hr;
744 LIST_FOR_EACH_ENTRY(range, &layout->ranges, struct layout_range, h.entry) {
745 /* we don't care about ranges that don't contain any text */
746 if (range->h.range.startPosition >= layout->len)
747 break;
749 /* inline objects override actual text in a range */
750 if (range->object) {
751 hr = layout_update_breakpoints_range(layout, range);
752 if (FAILED(hr))
753 return hr;
755 r = alloc_layout_run(LAYOUT_RUN_INLINE);
756 if (!r)
757 return E_OUTOFMEMORY;
759 r->u.object.object = range->object;
760 r->u.object.length = get_clipped_range_length(layout, range);
761 list_add_tail(&layout->runs, &r->entry);
762 continue;
765 /* initial splitting by script */
766 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, (IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
767 range->h.range.startPosition, get_clipped_range_length(layout, range), (IDWriteTextAnalysisSink*)&layout->IDWriteTextAnalysisSink1_iface);
768 if (FAILED(hr))
769 break;
771 /* this splits it further */
772 hr = IDWriteTextAnalyzer_AnalyzeBidi(analyzer, (IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
773 range->h.range.startPosition, get_clipped_range_length(layout, range), (IDWriteTextAnalysisSink*)&layout->IDWriteTextAnalysisSink1_iface);
774 if (FAILED(hr))
775 break;
778 if (layout->format.fallback) {
779 fallback = layout->format.fallback;
780 IDWriteFontFallback_AddRef(fallback);
782 else {
783 hr = IDWriteFactory3_GetSystemFontFallback(layout->factory, &fallback);
784 if (FAILED(hr))
785 return hr;
788 /* resolve run fonts */
789 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
790 struct regular_layout_run *run = &r->u.regular;
791 IDWriteFont *font;
792 UINT32 length;
794 if (r->kind == LAYOUT_RUN_INLINE)
795 continue;
797 range = get_layout_range_by_pos(layout, run->descr.textPosition);
799 if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL) {
800 IDWriteFontCollection *collection;
802 if (range->collection) {
803 collection = range->collection;
804 IDWriteFontCollection_AddRef(collection);
806 else
807 IDWriteFactory3_GetSystemFontCollection(layout->factory, FALSE, (IDWriteFontCollection1**)&collection, FALSE);
809 hr = create_matching_font(collection, range->fontfamily, range->weight,
810 range->style, range->stretch, &font);
812 IDWriteFontCollection_Release(collection);
814 if (FAILED(hr)) {
815 WARN("%s: failed to create a font for non visual run, %s, collection %p\n", debugstr_rundescr(&run->descr),
816 debugstr_w(range->fontfamily), range->collection);
817 return hr;
820 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
821 IDWriteFont_Release(font);
822 if (FAILED(hr))
823 return hr;
825 run->run.fontEmSize = range->fontsize;
826 continue;
829 length = run->descr.stringLength;
831 while (length) {
832 UINT32 mapped_length;
833 FLOAT scale;
835 run = &r->u.regular;
837 hr = IDWriteFontFallback_MapCharacters(fallback,
838 (IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
839 run->descr.textPosition,
840 run->descr.stringLength,
841 range->collection,
842 range->fontfamily,
843 range->weight,
844 range->style,
845 range->stretch,
846 &mapped_length,
847 &font,
848 &scale);
849 if (FAILED(hr)) {
850 WARN("%s: failed to map family %s, collection %p\n", debugstr_rundescr(&run->descr), debugstr_w(range->fontfamily), range->collection);
851 return hr;
854 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
855 IDWriteFont_Release(font);
856 if (FAILED(hr))
857 return hr;
858 run->run.fontEmSize = range->fontsize * scale;
860 if (mapped_length < length) {
861 struct regular_layout_run *nextrun = &r->u.regular;
862 struct layout_run *nextr;
864 /* keep mapped part for current run, add another run for the rest */
865 nextr = alloc_layout_run(LAYOUT_RUN_REGULAR);
866 if (!nextr)
867 return E_OUTOFMEMORY;
869 *nextr = *r;
870 nextrun = &nextr->u.regular;
871 nextrun->descr.textPosition = run->descr.textPosition + mapped_length;
872 nextrun->descr.stringLength = run->descr.stringLength - mapped_length;
873 nextrun->descr.string = &layout->str[nextrun->descr.textPosition];
874 run->descr.stringLength = mapped_length;
875 list_add_after(&r->entry, &nextr->entry);
876 r = nextr;
879 length -= mapped_length;
883 IDWriteFontFallback_Release(fallback);
885 /* fill run info */
886 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
887 DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props = NULL;
888 DWRITE_SHAPING_TEXT_PROPERTIES *text_props = NULL;
889 struct regular_layout_run *run = &r->u.regular;
890 DWRITE_FONT_METRICS fontmetrics = { 0 };
891 UINT32 max_count;
893 /* we need to do very little in case of inline objects */
894 if (r->kind == LAYOUT_RUN_INLINE) {
895 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[cluster];
896 struct layout_cluster *c = &layout->clusters[cluster];
897 DWRITE_INLINE_OBJECT_METRICS inlinemetrics;
899 metrics->width = 0.0f;
900 metrics->length = r->u.object.length;
901 metrics->canWrapLineAfter = 0;
902 metrics->isWhitespace = 0;
903 metrics->isNewline = 0;
904 metrics->isSoftHyphen = 0;
905 metrics->isRightToLeft = 0;
906 metrics->padding = 0;
907 c->run = r;
908 c->position = 0; /* there's always one cluster per inline object, so 0 is valid value */
909 cluster++;
911 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
912 hr = IDWriteInlineObject_GetMetrics(r->u.object.object, &inlinemetrics);
913 if (FAILED(hr)) {
914 memset(&inlinemetrics, 0, sizeof(inlinemetrics));
915 hr = S_OK;
917 metrics->width = inlinemetrics.width;
918 r->baseline = inlinemetrics.baseline;
919 r->height = inlinemetrics.height;
921 /* FIXME: use resolved breakpoints in this case too */
923 continue;
926 range = get_layout_range_by_pos(layout, run->descr.textPosition);
927 run->descr.localeName = range->locale;
928 run->clustermap = heap_alloc(run->descr.stringLength*sizeof(UINT16));
930 max_count = 3*run->descr.stringLength/2 + 16;
931 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
932 if (!run->clustermap || !run->glyphs)
933 goto memerr;
935 text_props = heap_alloc(run->descr.stringLength*sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
936 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
937 if (!text_props || !glyph_props)
938 goto memerr;
940 while (1) {
941 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, run->descr.string, run->descr.stringLength,
942 run->run.fontFace, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
943 NULL /* FIXME */, NULL, NULL, 0, max_count, run->clustermap, text_props, run->glyphs, glyph_props,
944 &run->glyphcount);
945 if (hr == E_NOT_SUFFICIENT_BUFFER) {
946 heap_free(run->glyphs);
947 heap_free(glyph_props);
949 max_count = run->glyphcount;
951 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
952 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
953 if (!run->glyphs || !glyph_props)
954 goto memerr;
956 continue;
959 break;
962 if (FAILED(hr)) {
963 heap_free(text_props);
964 heap_free(glyph_props);
965 WARN("%s: shaping failed 0x%08x\n", debugstr_rundescr(&run->descr), hr);
966 continue;
969 run->run.glyphIndices = run->glyphs;
970 run->descr.clusterMap = run->clustermap;
972 run->advances = heap_alloc(run->glyphcount*sizeof(FLOAT));
973 run->offsets = heap_alloc(run->glyphcount*sizeof(DWRITE_GLYPH_OFFSET));
974 if (!run->advances || !run->offsets)
975 goto memerr;
977 /* now set advances and offsets */
978 if (is_layout_gdi_compatible(layout))
979 hr = IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap,
980 text_props, run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount,
981 run->run.fontFace, run->run.fontEmSize, layout->ppdip, &layout->transform,
982 layout->measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->run.isSideways,
983 run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL, NULL, 0, run->advances, run->offsets);
984 else
985 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap, text_props,
986 run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount, run->run.fontFace,
987 run->run.fontEmSize, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
988 NULL, NULL, 0, run->advances, run->offsets);
990 heap_free(text_props);
991 heap_free(glyph_props);
992 if (FAILED(hr))
993 WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_rundescr(&run->descr), hr);
995 run->run.glyphAdvances = run->advances;
996 run->run.glyphOffsets = run->offsets;
998 /* Special treatment for runs that don't produce visual output, shaping code adds normal glyphs for them,
999 with valid cluster map and potentially with non-zero advances; layout code exposes those as zero width clusters. */
1000 if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL)
1001 run->run.glyphCount = 0;
1002 else
1003 run->run.glyphCount = run->glyphcount;
1005 /* baseline derived from font metrics */
1006 layout_get_font_metrics(layout, run->run.fontFace, run->run.fontEmSize, &fontmetrics);
1007 layout_get_font_height(run->run.fontEmSize, &fontmetrics, &r->baseline, &r->height);
1009 layout_set_cluster_metrics(layout, r, &cluster);
1010 continue;
1012 memerr:
1013 heap_free(text_props);
1014 heap_free(glyph_props);
1015 heap_free(run->clustermap);
1016 heap_free(run->glyphs);
1017 heap_free(run->advances);
1018 heap_free(run->offsets);
1019 run->advances = NULL;
1020 run->offsets = NULL;
1021 run->clustermap = run->glyphs = NULL;
1022 hr = E_OUTOFMEMORY;
1023 break;
1026 if (hr == S_OK) {
1027 layout->cluster_count = cluster;
1028 if (cluster)
1029 layout->clustermetrics[cluster-1].canWrapLineAfter = 1;
1032 IDWriteTextAnalyzer_Release(analyzer);
1033 return hr;
1036 static HRESULT layout_compute(struct dwrite_textlayout *layout)
1038 HRESULT hr;
1040 if (!(layout->recompute & RECOMPUTE_NOMINAL_RUNS))
1041 return S_OK;
1043 /* nominal breakpoints are evaluated only once, because string never changes */
1044 if (!layout->nominal_breakpoints) {
1045 IDWriteTextAnalyzer *analyzer;
1046 HRESULT hr;
1048 layout->nominal_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
1049 if (!layout->nominal_breakpoints)
1050 return E_OUTOFMEMORY;
1052 hr = get_textanalyzer(&analyzer);
1053 if (FAILED(hr))
1054 return hr;
1056 hr = IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer, (IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
1057 0, layout->len, (IDWriteTextAnalysisSink*)&layout->IDWriteTextAnalysisSink1_iface);
1058 IDWriteTextAnalyzer_Release(analyzer);
1060 if (layout->actual_breakpoints) {
1061 heap_free(layout->actual_breakpoints);
1062 layout->actual_breakpoints = NULL;
1065 hr = layout_compute_runs(layout);
1067 if (TRACE_ON(dwrite)) {
1068 struct layout_run *cur;
1070 LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
1071 if (cur->kind == LAYOUT_RUN_INLINE)
1072 TRACE("run inline object %p, len %u\n", cur->u.object.object, cur->u.object.length);
1073 else
1074 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur->u.regular.descr.textPosition, cur->u.regular.descr.textPosition +
1075 cur->u.regular.descr.stringLength-1, cur->u.regular.descr.stringLength, cur->u.regular.run.bidiLevel);
1079 layout->recompute &= ~RECOMPUTE_NOMINAL_RUNS;
1080 return hr;
1083 static inline FLOAT get_cluster_range_width(struct dwrite_textlayout *layout, UINT32 start, UINT32 end)
1085 FLOAT width = 0.0f;
1086 for (; start < end; start++)
1087 width += layout->clustermetrics[start].width;
1088 return width;
1091 static struct layout_range_header *get_layout_range_header_by_pos(struct list *ranges, UINT32 pos)
1093 struct layout_range_header *cur;
1095 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
1096 DWRITE_TEXT_RANGE *r = &cur->range;
1097 if (r->startPosition <= pos && pos < r->startPosition + r->length)
1098 return cur;
1101 return NULL;
1104 static inline IUnknown *layout_get_effect_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1106 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->effects, pos);
1107 return ((struct layout_range_iface*)h)->iface;
1110 static inline BOOL layout_is_erun_rtl(const struct layout_effective_run *erun)
1112 return erun->run->u.regular.run.bidiLevel & 1;
1115 /* A set of parameters that additionally splits resulting runs. It happens after shaping and all text processing,
1116 no glyph changes are possible. It's understandable for drawing effects, because DrawGlyphRun() reports them as
1117 one of the arguments, but it also happens for decorations, so every effective run has uniform
1118 underline/strikethough/effect tuple. */
1119 struct layout_final_splitting_params {
1120 BOOL strikethrough;
1121 BOOL underline;
1122 IUnknown *effect;
1125 static inline BOOL layout_get_strikethrough_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1127 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->strike_ranges, pos);
1128 return ((struct layout_range_bool*)h)->value;
1131 static inline BOOL layout_get_underline_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1133 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->underline_ranges, pos);
1134 return ((struct layout_range_bool*)h)->value;
1137 static void layout_splitting_params_from_pos(struct dwrite_textlayout *layout, UINT32 pos,
1138 struct layout_final_splitting_params *params)
1140 params->strikethrough = layout_get_strikethrough_from_pos(layout, pos);
1141 params->underline = layout_get_underline_from_pos(layout, pos);
1142 params->effect = layout_get_effect_from_pos(layout, pos);
1145 static BOOL is_same_splitting_params(const struct layout_final_splitting_params *left,
1146 const struct layout_final_splitting_params *right)
1148 return left->strikethrough == right->strikethrough &&
1149 left->underline == right->underline &&
1150 left->effect == right->effect;
1153 static void layout_get_erun_font_metrics(struct dwrite_textlayout *layout, struct layout_effective_run *erun,
1154 DWRITE_FONT_METRICS *metrics)
1156 memset(metrics, 0, sizeof(*metrics));
1157 if (is_layout_gdi_compatible(layout)) {
1158 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(
1159 erun->run->u.regular.run.fontFace,
1160 erun->run->u.regular.run.fontEmSize,
1161 layout->ppdip,
1162 &layout->transform,
1163 metrics);
1164 if (FAILED(hr))
1165 WARN("failed to get font metrics, 0x%08x\n", hr);
1167 else
1168 IDWriteFontFace_GetMetrics(erun->run->u.regular.run.fontFace, metrics);
1171 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
1172 'cluster_count' indicates how many clusters to add, including first one. */
1173 static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 first_cluster,
1174 UINT32 cluster_count, UINT32 line, FLOAT origin_x, struct layout_final_splitting_params *params)
1176 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1177 UINT32 i, start, length, last_cluster;
1178 struct layout_effective_run *run;
1180 if (r->kind == LAYOUT_RUN_INLINE) {
1181 struct layout_effective_inline *inlineobject;
1183 inlineobject = heap_alloc(sizeof(*inlineobject));
1184 if (!inlineobject)
1185 return E_OUTOFMEMORY;
1187 inlineobject->run = r;
1188 inlineobject->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1189 inlineobject->origin_x = is_rtl ? origin_x - inlineobject->width : origin_x;
1190 inlineobject->origin_y = 0.0f; /* set after line is built */
1191 inlineobject->align_dx = 0.0f;
1193 /* It's not clear how these two are set, possibly directionality
1194 is derived from surrounding text (replaced text could have
1195 different ranges which differ in reading direction). */
1196 inlineobject->is_sideways = FALSE;
1197 inlineobject->is_rtl = FALSE;
1198 inlineobject->line = line;
1200 /* effect assigned from start position and on is used for inline objects */
1201 inlineobject->effect = layout_get_effect_from_pos(layout, layout->clusters[first_cluster].position);
1203 list_add_tail(&layout->inlineobjects, &inlineobject->entry);
1204 return S_OK;
1207 run = heap_alloc(sizeof(*run));
1208 if (!run)
1209 return E_OUTOFMEMORY;
1211 /* No need to iterate for that, use simple fact that:
1212 <last cluster position> = first cluster position> + <sum of cluster lengths not including last one> */
1213 last_cluster = first_cluster + cluster_count - 1;
1214 length = layout->clusters[last_cluster].position - layout->clusters[first_cluster].position +
1215 layout->clustermetrics[last_cluster].length;
1217 run->clustermap = heap_alloc(sizeof(UINT16)*length);
1218 if (!run->clustermap) {
1219 heap_free(run);
1220 return E_OUTOFMEMORY;
1223 run->run = r;
1224 run->start = start = layout->clusters[first_cluster].position;
1225 run->length = length;
1226 run->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1228 /* Check if run direction matches paragraph direction, if it doesn't adjust by
1229 run width */
1230 if (layout_is_erun_rtl(run) ^ is_rtl)
1231 run->origin_x = is_rtl ? origin_x - run->width : origin_x + run->width;
1232 else
1233 run->origin_x = origin_x;
1235 run->origin_y = 0.0f; /* set after line is built */
1236 run->align_dx = 0.0f;
1237 run->line = line;
1239 if (r->u.regular.run.glyphCount) {
1240 /* trim from the left */
1241 run->glyphcount = r->u.regular.run.glyphCount - r->u.regular.clustermap[start];
1242 /* trim from the right */
1243 if (start + length < r->u.regular.descr.stringLength - 1)
1244 run->glyphcount -= r->u.regular.run.glyphCount - r->u.regular.clustermap[start + length];
1246 else
1247 run->glyphcount = 0;
1249 /* cluster map needs to be shifted */
1250 for (i = 0; i < length; i++)
1251 run->clustermap[i] = r->u.regular.clustermap[start + i] - r->u.regular.clustermap[start];
1253 run->effect = params->effect;
1254 run->underlined = params->underline;
1255 list_add_tail(&layout->eruns, &run->entry);
1257 /* Strikethrough style is guaranteed to be consistent within effective run,
1258 its width equals to run width, thickness and offset are derived from
1259 font metrics, rest of the values are from layout or run itself */
1260 if (params->strikethrough) {
1261 struct layout_strikethrough *s;
1262 DWRITE_FONT_METRICS metrics;
1264 s = heap_alloc(sizeof(*s));
1265 if (!s)
1266 return E_OUTOFMEMORY;
1268 layout_get_erun_font_metrics(layout, run, &metrics);
1269 s->s.width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1270 s->s.thickness = SCALE_FONT_METRIC(metrics.strikethroughThickness, r->u.regular.run.fontEmSize, &metrics);
1271 /* Negative offset moves it above baseline as Y coordinate grows downward. */
1272 s->s.offset = -SCALE_FONT_METRIC(metrics.strikethroughPosition, r->u.regular.run.fontEmSize, &metrics);
1273 s->s.readingDirection = layout->format.readingdir;
1274 s->s.flowDirection = layout->format.flow;
1275 s->s.localeName = r->u.regular.descr.localeName;
1276 s->s.measuringMode = layout->measuringmode;
1277 s->run = run;
1279 list_add_tail(&layout->strikethrough, &s->entry);
1282 return S_OK;
1285 static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_LINE_METRICS *metrics, UINT32 *line)
1287 if (!layout->line_alloc) {
1288 layout->line_alloc = 5;
1289 layout->lines = heap_alloc(layout->line_alloc*sizeof(*layout->lines));
1290 if (!layout->lines)
1291 return E_OUTOFMEMORY;
1294 if (layout->metrics.lineCount == layout->line_alloc) {
1295 DWRITE_LINE_METRICS *l = heap_realloc(layout->lines, layout->line_alloc*2*sizeof(*layout->lines));
1296 if (!l)
1297 return E_OUTOFMEMORY;
1298 layout->lines = l;
1299 layout->line_alloc *= 2;
1302 layout->lines[*line] = *metrics;
1303 layout->metrics.lineCount += 1;
1304 *line += 1;
1305 return S_OK;
1309 static inline struct layout_effective_run *layout_get_next_erun(struct dwrite_textlayout *layout,
1310 const struct layout_effective_run *cur)
1312 struct list *e;
1314 if (!cur)
1315 e = list_head(&layout->eruns);
1316 else
1317 e = list_next(&layout->eruns, &cur->entry);
1318 if (!e)
1319 return NULL;
1320 return LIST_ENTRY(e, struct layout_effective_run, entry);
1323 static inline struct layout_effective_run *layout_get_prev_erun(struct dwrite_textlayout *layout,
1324 const struct layout_effective_run *cur)
1326 struct list *e;
1328 if (!cur)
1329 e = list_tail(&layout->eruns);
1330 else
1331 e = list_prev(&layout->eruns, &cur->entry);
1332 if (!e)
1333 return NULL;
1334 return LIST_ENTRY(e, struct layout_effective_run, entry);
1337 static inline struct layout_effective_inline *layout_get_next_inline_run(struct dwrite_textlayout *layout,
1338 const struct layout_effective_inline *cur)
1340 struct list *e;
1342 if (!cur)
1343 e = list_head(&layout->inlineobjects);
1344 else
1345 e = list_next(&layout->inlineobjects, &cur->entry);
1346 if (!e)
1347 return NULL;
1348 return LIST_ENTRY(e, struct layout_effective_inline, entry);
1351 static FLOAT layout_get_line_width(struct dwrite_textlayout *layout,
1352 struct layout_effective_run *erun, struct layout_effective_inline *inrun, UINT32 line)
1354 FLOAT width = 0.0f;
1356 while (erun && erun->line == line) {
1357 width += erun->width;
1358 erun = layout_get_next_erun(layout, erun);
1359 if (!erun)
1360 break;
1363 while (inrun && inrun->line == line) {
1364 width += inrun->width;
1365 inrun = layout_get_next_inline_run(layout, inrun);
1366 if (!inrun)
1367 break;
1370 return width;
1373 static inline BOOL should_skip_transform(const DWRITE_MATRIX *m, FLOAT *det)
1375 *det = m->m11 * m->m22 - m->m12 * m->m21;
1376 /* on certain conditions we can skip transform */
1377 return (!memcmp(m, &identity, sizeof(*m)) || fabsf(*det) <= 1e-10f);
1380 static inline void layout_apply_snapping(struct dwrite_vec *vec, BOOL skiptransform, FLOAT ppdip,
1381 const DWRITE_MATRIX *m, FLOAT det)
1383 if (!skiptransform) {
1384 FLOAT vec2[2];
1386 /* apply transform */
1387 vec->x *= ppdip;
1388 vec->y *= ppdip;
1390 vec2[0] = m->m11 * vec->x + m->m21 * vec->y + m->dx;
1391 vec2[1] = m->m12 * vec->x + m->m22 * vec->y + m->dy;
1393 /* snap */
1394 vec2[0] = floorf(vec2[0] + 0.5f);
1395 vec2[1] = floorf(vec2[1] + 0.5f);
1397 /* apply inverted transform, we don't care about X component at this point */
1398 vec->x = (m->m22 * vec2[0] - m->m21 * vec2[1] + m->m21 * m->dy - m->m22 * m->dx) / det;
1399 vec->x /= ppdip;
1401 vec->y = (-m->m12 * vec2[0] + m->m11 * vec2[1] - (m->m11 * m->dy - m->m12 * m->dx)) / det;
1402 vec->y /= ppdip;
1404 else {
1405 vec->x = floorf(vec->x * ppdip + 0.5f) / ppdip;
1406 vec->y = floorf(vec->y * ppdip + 0.5f) / ppdip;
1410 static void layout_apply_leading_alignment(struct dwrite_textlayout *layout)
1412 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1413 struct layout_effective_inline *inrun;
1414 struct layout_effective_run *erun;
1416 erun = layout_get_next_erun(layout, NULL);
1417 inrun = layout_get_next_inline_run(layout, NULL);
1419 while (erun) {
1420 erun->align_dx = 0.0f;
1421 erun = layout_get_next_erun(layout, erun);
1424 while (inrun) {
1425 inrun->align_dx = 0.0f;
1426 inrun = layout_get_next_inline_run(layout, inrun);
1429 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
1432 static void layout_apply_trailing_alignment(struct dwrite_textlayout *layout)
1434 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1435 struct layout_effective_inline *inrun;
1436 struct layout_effective_run *erun;
1437 UINT32 line;
1439 erun = layout_get_next_erun(layout, NULL);
1440 inrun = layout_get_next_inline_run(layout, NULL);
1442 for (line = 0; line < layout->metrics.lineCount; line++) {
1443 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1444 FLOAT shift = layout->metrics.layoutWidth - width;
1446 if (is_rtl)
1447 shift *= -1.0f;
1449 while (erun && erun->line == line) {
1450 erun->align_dx = shift;
1451 erun = layout_get_next_erun(layout, erun);
1454 while (inrun && inrun->line == line) {
1455 inrun->align_dx = shift;
1456 inrun = layout_get_next_inline_run(layout, inrun);
1460 layout->metrics.left = is_rtl ? 0.0f : layout->metrics.layoutWidth - layout->metrics.width;
1463 static inline FLOAT layout_get_centered_shift(struct dwrite_textlayout *layout, BOOL skiptransform,
1464 FLOAT width, FLOAT det)
1466 if (is_layout_gdi_compatible(layout)) {
1467 struct dwrite_vec vec = { layout->metrics.layoutWidth - width, 0.0f};
1468 layout_apply_snapping(&vec, skiptransform, layout->ppdip, &layout->transform, det);
1469 return floorf(vec.x / 2.0f);
1471 else
1472 return (layout->metrics.layoutWidth - width) / 2.0f;
1475 static void layout_apply_centered_alignment(struct dwrite_textlayout *layout)
1477 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1478 struct layout_effective_inline *inrun;
1479 struct layout_effective_run *erun;
1480 BOOL skiptransform;
1481 UINT32 line;
1482 FLOAT det;
1484 erun = layout_get_next_erun(layout, NULL);
1485 inrun = layout_get_next_inline_run(layout, NULL);
1487 skiptransform = should_skip_transform(&layout->transform, &det);
1489 for (line = 0; line < layout->metrics.lineCount; line++) {
1490 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1491 FLOAT shift = layout_get_centered_shift(layout, skiptransform, width, det);
1493 if (is_rtl)
1494 shift *= -1.0f;
1496 while (erun && erun->line == line) {
1497 erun->align_dx = shift;
1498 erun = layout_get_next_erun(layout, erun);
1501 while (inrun && inrun->line == line) {
1502 inrun->align_dx = shift;
1503 inrun = layout_get_next_inline_run(layout, inrun);
1507 layout->metrics.left = (layout->metrics.layoutWidth - layout->metrics.width) / 2.0f;
1510 static void layout_apply_text_alignment(struct dwrite_textlayout *layout)
1512 switch (layout->format.textalignment)
1514 case DWRITE_TEXT_ALIGNMENT_LEADING:
1515 layout_apply_leading_alignment(layout);
1516 break;
1517 case DWRITE_TEXT_ALIGNMENT_TRAILING:
1518 layout_apply_trailing_alignment(layout);
1519 break;
1520 case DWRITE_TEXT_ALIGNMENT_CENTER:
1521 layout_apply_centered_alignment(layout);
1522 break;
1523 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED:
1524 FIXME("alignment %d not implemented\n", layout->format.textalignment);
1525 break;
1526 default:
1531 static void layout_apply_par_alignment(struct dwrite_textlayout *layout)
1533 struct layout_effective_inline *inrun;
1534 struct layout_effective_run *erun;
1535 FLOAT origin_y = 0.0f;
1536 UINT32 line;
1538 /* alignment mode defines origin, after that all run origins are updated
1539 the same way */
1541 switch (layout->format.paralign)
1543 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR:
1544 origin_y = 0.0f;
1545 break;
1546 case DWRITE_PARAGRAPH_ALIGNMENT_FAR:
1547 origin_y = layout->metrics.layoutHeight - layout->metrics.height;
1548 break;
1549 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER:
1550 origin_y = (layout->metrics.layoutHeight - layout->metrics.height) / 2.0f;
1551 break;
1552 default:
1556 layout->metrics.top = origin_y;
1558 erun = layout_get_next_erun(layout, NULL);
1559 inrun = layout_get_next_inline_run(layout, NULL);
1560 for (line = 0; line < layout->metrics.lineCount; line++) {
1561 origin_y += layout->lines[line].baseline;
1563 while (erun && erun->line == line) {
1564 erun->origin_y = origin_y;
1565 erun = layout_get_next_erun(layout, erun);
1568 while (inrun && inrun->line == line) {
1569 inrun->origin_y = origin_y - inrun->run->baseline;
1570 inrun = layout_get_next_inline_run(layout, inrun);
1575 struct layout_underline_splitting_params {
1576 const WCHAR *locale; /* points to range data, no additional allocation */
1577 IUnknown *effect; /* does not hold another reference */
1580 static void init_u_splitting_params_from_erun(struct layout_effective_run *erun,
1581 struct layout_underline_splitting_params *params)
1583 params->locale = erun->run->u.regular.descr.localeName;
1584 params->effect = erun->effect;
1587 static BOOL is_same_u_splitting(struct layout_underline_splitting_params *left,
1588 struct layout_underline_splitting_params *right)
1590 return left->effect == right->effect && !strcmpiW(left->locale, right->locale);
1593 static HRESULT layout_add_underline(struct dwrite_textlayout *layout, struct layout_effective_run *first,
1594 struct layout_effective_run *last)
1596 struct layout_effective_run *cur;
1597 DWRITE_FONT_METRICS metrics;
1598 FLOAT thickness, offset;
1600 if (first == layout_get_prev_erun(layout, last)) {
1601 layout_get_erun_font_metrics(layout, first, &metrics);
1602 thickness = SCALE_FONT_METRIC(metrics.underlineThickness, first->run->u.regular.run.fontEmSize, &metrics);
1603 offset = SCALE_FONT_METRIC(metrics.underlinePosition, first->run->u.regular.run.fontEmSize, &metrics);
1605 else {
1606 FLOAT width = 0.0f;
1608 /* Single underline is added for consecutive underlined runs. In this case underline parameters are
1609 calculated as weighted average, where run width acts as a weight. */
1610 thickness = offset = 0.0f;
1611 cur = first;
1612 do {
1613 layout_get_erun_font_metrics(layout, cur, &metrics);
1615 thickness += SCALE_FONT_METRIC(metrics.underlineThickness, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
1616 offset += SCALE_FONT_METRIC(metrics.underlinePosition, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
1617 width += cur->width;
1619 cur = layout_get_next_erun(layout, cur);
1620 } while (cur != last);
1622 thickness /= width;
1623 offset /= width;
1626 cur = first;
1627 do {
1628 struct layout_underline_splitting_params params, prev_params;
1629 struct layout_effective_run *next, *w;
1630 struct layout_underline *u;
1632 init_u_splitting_params_from_erun(cur, &prev_params);
1633 while ((next = layout_get_next_erun(layout, cur)) != last) {
1634 init_u_splitting_params_from_erun(next, &params);
1635 if (!is_same_u_splitting(&prev_params, &params))
1636 break;
1637 cur = next;
1640 u = heap_alloc(sizeof(*u));
1641 if (!u)
1642 return E_OUTOFMEMORY;
1644 w = cur;
1645 u->u.width = 0.0f;
1646 while (w != next) {
1647 u->u.width += w->width;
1648 w = layout_get_next_erun(layout, w);
1651 u->u.thickness = thickness;
1652 /* Font metrics convention is to have it negative when below baseline, for rendering
1653 however Y grows from baseline down for horizontal baseline. */
1654 u->u.offset = -offset;
1655 u->u.runHeight = 0.0f; /* FIXME */
1656 u->u.readingDirection = is_run_rtl(cur) ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
1657 DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
1658 u->u.flowDirection = layout->format.flow;
1659 u->u.localeName = cur->run->u.regular.descr.localeName;
1660 u->u.measuringMode = layout->measuringmode;
1661 u->run = cur;
1662 list_add_tail(&layout->underlines, &u->entry);
1664 cur = next;
1665 } while (cur != last);
1667 return S_OK;
1670 /* Adds zero width line, metrics are derived from font at specified text position. */
1671 static HRESULT layout_set_dummy_line_metrics(struct dwrite_textlayout *layout, UINT32 pos, UINT32 *line)
1673 DWRITE_FONT_METRICS fontmetrics;
1674 DWRITE_LINE_METRICS metrics;
1675 struct layout_range *range;
1676 IDWriteFontFace *fontface;
1677 IDWriteFont *font;
1678 HRESULT hr;
1680 range = get_layout_range_by_pos(layout, pos);
1681 hr = create_matching_font(range->collection,
1682 range->fontfamily,
1683 range->weight,
1684 range->style,
1685 range->stretch,
1686 &font);
1687 if (FAILED(hr))
1688 return hr;
1689 hr = IDWriteFont_CreateFontFace(font, &fontface);
1690 IDWriteFont_Release(font);
1691 if (FAILED(hr))
1692 return hr;
1694 layout_get_font_metrics(layout, fontface, range->fontsize, &fontmetrics);
1695 layout_get_font_height(range->fontsize, &fontmetrics, &metrics.baseline, &metrics.height);
1696 IDWriteFontFace_Release(fontface);
1698 metrics.length = 0;
1699 metrics.trailingWhitespaceLength = 0;
1700 metrics.newlineLength = 0;
1701 metrics.isTrimmed = FALSE;
1702 return layout_set_line_metrics(layout, &metrics, line);
1705 static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
1707 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1708 struct layout_final_splitting_params prev_params, params;
1709 struct layout_effective_run *erun, *first_underlined;
1710 struct layout_effective_inline *inrun;
1711 const struct layout_run *run;
1712 DWRITE_LINE_METRICS metrics;
1713 FLOAT width, origin_x, origin_y;
1714 UINT32 i, start, line, textpos;
1715 HRESULT hr;
1717 if (!(layout->recompute & RECOMPUTE_EFFECTIVE_RUNS))
1718 return S_OK;
1720 hr = layout_compute(layout);
1721 if (FAILED(hr))
1722 return hr;
1724 layout->metrics.lineCount = 0;
1725 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0f;
1726 line = 0;
1727 memset(&metrics, 0, sizeof(metrics));
1729 layout_splitting_params_from_pos(layout, 0, &params);
1730 prev_params = params;
1732 if (layout->cluster_count)
1733 run = layout->clusters[0].run;
1734 for (i = 0, start = 0, textpos = 0, width = 0.0f; i < layout->cluster_count; i++) {
1735 BOOL overflow;
1737 layout_splitting_params_from_pos(layout, textpos, &params);
1739 /* switched to next nominal run, at this point all previous pending clusters are already
1740 checked for layout line overflow, so new effective run will fit in current line */
1741 if (run != layout->clusters[i].run || !is_same_splitting_params(&prev_params, &params)) {
1742 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, &prev_params);
1743 if (FAILED(hr))
1744 return hr;
1745 origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) :
1746 get_cluster_range_width(layout, start, i);
1747 run = layout->clusters[i].run;
1748 start = i;
1751 overflow = layout->clustermetrics[i].canWrapLineAfter &&
1752 (width + layout->clustermetrics[i].width > layout->metrics.layoutWidth) &&
1753 (layout->format.wrapping != DWRITE_WORD_WRAPPING_NO_WRAP);
1754 /* check if we got new */
1755 if (overflow ||
1756 layout->clustermetrics[i].isNewline || /* always wrap on new line */
1757 i == layout->cluster_count - 1) /* end of the text */ {
1759 UINT32 strlength, last_cluster, index;
1760 FLOAT descent, trailingspacewidth;
1761 struct layout_final_splitting_params *p;
1763 if (!overflow) {
1764 width += layout->clustermetrics[i].width;
1765 metrics.length += layout->clustermetrics[i].length;
1766 last_cluster = i;
1767 p = &params;
1769 else {
1770 last_cluster = i ? i - 1 : i;
1771 p = &prev_params;
1774 if (i >= start) {
1775 hr = layout_add_effective_run(layout, run, start, last_cluster - start + 1, line, origin_x, p);
1776 if (FAILED(hr))
1777 return hr;
1778 /* we don't need to update origin for next run as we're going to wrap */
1781 /* take a look at clusters we got for this line in reverse order to set
1782 trailing properties for current line */
1783 strlength = metrics.length;
1784 index = last_cluster;
1785 trailingspacewidth = 0.0f;
1786 while (strlength) {
1787 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1788 struct layout_cluster *lc = &layout->clusters[index];
1789 WCHAR ch;
1791 /* This also filters out clusters added from inline objects, those are never
1792 treated as a white space. */
1793 if (!cluster->isWhitespace)
1794 break;
1796 /* Every isNewline cluster is also isWhitespace, but not every
1797 newline character cluster has isNewline set, so go back to original string. */
1798 ch = lc->run->u.regular.descr.string[lc->position];
1799 if (cluster->length == 1 && lb_is_newline_char(ch))
1800 metrics.newlineLength += cluster->length;
1802 metrics.trailingWhitespaceLength += cluster->length;
1803 trailingspacewidth += cluster->width;
1805 strlength -= cluster->length;
1806 index--;
1809 /* look for max baseline and descent for this line */
1810 strlength = metrics.length;
1811 index = last_cluster;
1812 metrics.baseline = 0.0f;
1813 descent = 0.0f;
1814 while (strlength) {
1815 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1816 const struct layout_run *cur = layout->clusters[index].run;
1817 FLOAT cur_descent = cur->height - cur->baseline;
1819 if (cur->baseline > metrics.baseline)
1820 metrics.baseline = cur->baseline;
1822 if (cur_descent > descent)
1823 descent = cur_descent;
1825 strlength -= cluster->length;
1826 index--;
1828 metrics.height = descent + metrics.baseline;
1830 if (width > layout->metrics.widthIncludingTrailingWhitespace)
1831 layout->metrics.widthIncludingTrailingWhitespace = width;
1832 if (width - trailingspacewidth > layout->metrics.width)
1833 layout->metrics.width = width - trailingspacewidth;
1835 metrics.isTrimmed = width > layout->metrics.layoutWidth;
1836 hr = layout_set_line_metrics(layout, &metrics, &line);
1837 if (FAILED(hr))
1838 return hr;
1840 width = layout->clustermetrics[i].width;
1841 memset(&metrics, 0, sizeof(metrics));
1842 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0f;
1843 start = i;
1845 else {
1846 metrics.length += layout->clustermetrics[i].length;
1847 width += layout->clustermetrics[i].width;
1850 prev_params = params;
1851 textpos += layout->clustermetrics[i].length;
1854 /* Add dummy line if:
1855 - there's no text, metrics come from first range in this case;
1856 - last ended with a mandatory break, metrics come from last text position.
1858 if (layout->len == 0)
1859 hr = layout_set_dummy_line_metrics(layout, 0, &line);
1860 else if (layout->clustermetrics[layout->cluster_count-1].isNewline)
1861 hr = layout_set_dummy_line_metrics(layout, layout->len-1, &line);
1862 if (FAILED(hr))
1863 return hr;
1865 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
1866 layout->metrics.top = 0.0f;
1867 layout->metrics.maxBidiReorderingDepth = 1; /* FIXME */
1868 layout->metrics.height = 0.0f;
1870 /* Now all line info is here, update effective runs positions in flow direction */
1871 erun = layout_get_next_erun(layout, NULL);
1872 first_underlined = erun && erun->underlined ? erun : NULL;
1874 inrun = layout_get_next_inline_run(layout, NULL);
1876 origin_y = 0.0f;
1877 for (line = 0; line < layout->metrics.lineCount; line++) {
1879 origin_y += layout->lines[line].baseline;
1881 /* For all runs on this line */
1882 while (erun && erun->line == line) {
1883 erun->origin_y = origin_y;
1884 erun = layout_get_next_erun(layout, erun);
1886 if (first_underlined && (!erun || !erun->underlined)) {
1887 layout_add_underline(layout, first_underlined, erun);
1888 first_underlined = NULL;
1890 else if (!first_underlined && erun && erun->underlined)
1891 first_underlined = erun;
1894 /* Same for inline runs */
1895 while (inrun && inrun->line == line) {
1896 inrun->origin_y = origin_y - inrun->run->baseline;
1897 inrun = layout_get_next_inline_run(layout, inrun);
1900 layout->metrics.height += layout->lines[line].height;
1903 /* initial alignment is always leading */
1904 if (layout->format.textalignment != DWRITE_TEXT_ALIGNMENT_LEADING)
1905 layout_apply_text_alignment(layout);
1907 /* initial paragraph alignment is always near */
1908 if (layout->format.paralign != DWRITE_PARAGRAPH_ALIGNMENT_NEAR)
1909 layout_apply_par_alignment(layout);
1911 layout->metrics.heightIncludingTrailingWhitespace = layout->metrics.height; /* FIXME: not true for vertical text */
1913 layout->recompute &= ~RECOMPUTE_EFFECTIVE_RUNS;
1914 return hr;
1917 static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
1919 struct layout_range_spacing const *range_spacing = (struct layout_range_spacing*)h;
1920 struct layout_range_iface const *range_iface = (struct layout_range_iface*)h;
1921 struct layout_range_bool const *range_bool = (struct layout_range_bool*)h;
1922 struct layout_range const *range = (struct layout_range*)h;
1924 switch (attr) {
1925 case LAYOUT_RANGE_ATTR_WEIGHT:
1926 return range->weight == value->u.weight;
1927 case LAYOUT_RANGE_ATTR_STYLE:
1928 return range->style == value->u.style;
1929 case LAYOUT_RANGE_ATTR_STRETCH:
1930 return range->stretch == value->u.stretch;
1931 case LAYOUT_RANGE_ATTR_FONTSIZE:
1932 return range->fontsize == value->u.fontsize;
1933 case LAYOUT_RANGE_ATTR_INLINE:
1934 return range->object == value->u.object;
1935 case LAYOUT_RANGE_ATTR_EFFECT:
1936 return range_iface->iface == value->u.effect;
1937 case LAYOUT_RANGE_ATTR_UNDERLINE:
1938 return range_bool->value == value->u.underline;
1939 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
1940 return range_bool->value == value->u.strikethrough;
1941 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
1942 return range->pair_kerning == value->u.pair_kerning;
1943 case LAYOUT_RANGE_ATTR_FONTCOLL:
1944 return range->collection == value->u.collection;
1945 case LAYOUT_RANGE_ATTR_LOCALE:
1946 return strcmpiW(range->locale, value->u.locale) == 0;
1947 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1948 return strcmpW(range->fontfamily, value->u.fontfamily) == 0;
1949 case LAYOUT_RANGE_ATTR_SPACING:
1950 return range_spacing->leading == value->u.spacing[0] &&
1951 range_spacing->trailing == value->u.spacing[1] &&
1952 range_spacing->min_advance == value->u.spacing[2];
1953 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
1954 return range_iface->iface == (IUnknown*)value->u.typography;
1955 default:
1959 return FALSE;
1962 static inline BOOL is_same_layout_attributes(struct layout_range_header const *hleft, struct layout_range_header const *hright)
1964 switch (hleft->kind)
1966 case LAYOUT_RANGE_REGULAR:
1968 struct layout_range const *left = (struct layout_range const*)hleft;
1969 struct layout_range const *right = (struct layout_range const*)hright;
1970 return left->weight == right->weight &&
1971 left->style == right->style &&
1972 left->stretch == right->stretch &&
1973 left->fontsize == right->fontsize &&
1974 left->object == right->object &&
1975 left->pair_kerning == right->pair_kerning &&
1976 left->collection == right->collection &&
1977 !strcmpiW(left->locale, right->locale) &&
1978 !strcmpW(left->fontfamily, right->fontfamily);
1980 case LAYOUT_RANGE_UNDERLINE:
1981 case LAYOUT_RANGE_STRIKETHROUGH:
1983 struct layout_range_bool const *left = (struct layout_range_bool const*)hleft;
1984 struct layout_range_bool const *right = (struct layout_range_bool const*)hright;
1985 return left->value == right->value;
1987 case LAYOUT_RANGE_EFFECT:
1988 case LAYOUT_RANGE_TYPOGRAPHY:
1990 struct layout_range_iface const *left = (struct layout_range_iface const*)hleft;
1991 struct layout_range_iface const *right = (struct layout_range_iface const*)hright;
1992 return left->iface == right->iface;
1994 case LAYOUT_RANGE_SPACING:
1996 struct layout_range_spacing const *left = (struct layout_range_spacing const*)hleft;
1997 struct layout_range_spacing const *right = (struct layout_range_spacing const*)hright;
1998 return left->leading == right->leading &&
1999 left->trailing == right->trailing &&
2000 left->min_advance == right->min_advance;
2002 default:
2003 FIXME("unknown range kind %d\n", hleft->kind);
2004 return FALSE;
2008 static inline BOOL is_same_text_range(const DWRITE_TEXT_RANGE *left, const DWRITE_TEXT_RANGE *right)
2010 return left->startPosition == right->startPosition && left->length == right->length;
2013 /* Allocates range and inits it with default values from text format. */
2014 static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout *layout, const DWRITE_TEXT_RANGE *r,
2015 enum layout_range_kind kind)
2017 struct layout_range_header *h;
2019 switch (kind)
2021 case LAYOUT_RANGE_REGULAR:
2023 struct layout_range *range;
2025 range = heap_alloc(sizeof(*range));
2026 if (!range) return NULL;
2028 range->weight = layout->format.weight;
2029 range->style = layout->format.style;
2030 range->stretch = layout->format.stretch;
2031 range->fontsize = layout->format.fontsize;
2032 range->object = NULL;
2033 range->pair_kerning = FALSE;
2035 range->fontfamily = heap_strdupW(layout->format.family_name);
2036 if (!range->fontfamily) {
2037 heap_free(range);
2038 return NULL;
2041 range->collection = layout->format.collection;
2042 if (range->collection)
2043 IDWriteFontCollection_AddRef(range->collection);
2044 strcpyW(range->locale, layout->format.locale);
2046 h = &range->h;
2047 break;
2049 case LAYOUT_RANGE_UNDERLINE:
2050 case LAYOUT_RANGE_STRIKETHROUGH:
2052 struct layout_range_bool *range;
2054 range = heap_alloc(sizeof(*range));
2055 if (!range) return NULL;
2057 range->value = FALSE;
2058 h = &range->h;
2059 break;
2061 case LAYOUT_RANGE_EFFECT:
2062 case LAYOUT_RANGE_TYPOGRAPHY:
2064 struct layout_range_iface *range;
2066 range = heap_alloc(sizeof(*range));
2067 if (!range) return NULL;
2069 range->iface = NULL;
2070 h = &range->h;
2071 break;
2073 case LAYOUT_RANGE_SPACING:
2075 struct layout_range_spacing *range;
2077 range = heap_alloc(sizeof(*range));
2078 if (!range) return NULL;
2080 range->leading = 0.0f;
2081 range->trailing = 0.0f;
2082 range->min_advance = 0.0f;
2083 h = &range->h;
2084 break;
2086 default:
2087 FIXME("unknown range kind %d\n", kind);
2088 return NULL;
2091 h->kind = kind;
2092 h->range = *r;
2093 return h;
2096 static struct layout_range_header *alloc_layout_range_from(struct layout_range_header *h, const DWRITE_TEXT_RANGE *r)
2098 struct layout_range_header *ret;
2100 switch (h->kind)
2102 case LAYOUT_RANGE_REGULAR:
2104 struct layout_range *from = (struct layout_range*)h;
2106 struct layout_range *range = heap_alloc(sizeof(*range));
2107 if (!range) return NULL;
2109 *range = *from;
2110 range->fontfamily = heap_strdupW(from->fontfamily);
2111 if (!range->fontfamily) {
2112 heap_free(range);
2113 return NULL;
2116 /* update refcounts */
2117 if (range->object)
2118 IDWriteInlineObject_AddRef(range->object);
2119 if (range->collection)
2120 IDWriteFontCollection_AddRef(range->collection);
2121 ret = &range->h;
2122 break;
2124 case LAYOUT_RANGE_UNDERLINE:
2125 case LAYOUT_RANGE_STRIKETHROUGH:
2127 struct layout_range_bool *strike = heap_alloc(sizeof(*strike));
2128 if (!strike) return NULL;
2130 *strike = *(struct layout_range_bool*)h;
2131 ret = &strike->h;
2132 break;
2134 case LAYOUT_RANGE_EFFECT:
2135 case LAYOUT_RANGE_TYPOGRAPHY:
2137 struct layout_range_iface *effect = heap_alloc(sizeof(*effect));
2138 if (!effect) return NULL;
2140 *effect = *(struct layout_range_iface*)h;
2141 if (effect->iface)
2142 IUnknown_AddRef(effect->iface);
2143 ret = &effect->h;
2144 break;
2146 case LAYOUT_RANGE_SPACING:
2148 struct layout_range_spacing *spacing = heap_alloc(sizeof(*spacing));
2149 if (!spacing) return NULL;
2151 *spacing = *(struct layout_range_spacing*)h;
2152 ret = &spacing->h;
2153 break;
2155 default:
2156 FIXME("unknown range kind %d\n", h->kind);
2157 return NULL;
2160 ret->range = *r;
2161 return ret;
2164 static void free_layout_range(struct layout_range_header *h)
2166 if (!h)
2167 return;
2169 switch (h->kind)
2171 case LAYOUT_RANGE_REGULAR:
2173 struct layout_range *range = (struct layout_range*)h;
2175 if (range->object)
2176 IDWriteInlineObject_Release(range->object);
2177 if (range->collection)
2178 IDWriteFontCollection_Release(range->collection);
2179 heap_free(range->fontfamily);
2180 break;
2182 case LAYOUT_RANGE_EFFECT:
2183 case LAYOUT_RANGE_TYPOGRAPHY:
2185 struct layout_range_iface *range = (struct layout_range_iface*)h;
2186 if (range->iface)
2187 IUnknown_Release(range->iface);
2188 break;
2190 default:
2194 heap_free(h);
2197 static void free_layout_ranges_list(struct dwrite_textlayout *layout)
2199 struct layout_range_header *cur, *cur2;
2201 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->ranges, struct layout_range_header, entry) {
2202 list_remove(&cur->entry);
2203 free_layout_range(cur);
2206 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->underline_ranges, struct layout_range_header, entry) {
2207 list_remove(&cur->entry);
2208 free_layout_range(cur);
2211 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->strike_ranges, struct layout_range_header, entry) {
2212 list_remove(&cur->entry);
2213 free_layout_range(cur);
2216 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->effects, struct layout_range_header, entry) {
2217 list_remove(&cur->entry);
2218 free_layout_range(cur);
2221 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->spacing, struct layout_range_header, entry) {
2222 list_remove(&cur->entry);
2223 free_layout_range(cur);
2226 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->typographies, struct layout_range_header, entry) {
2227 list_remove(&cur->entry);
2228 free_layout_range(cur);
2232 static struct layout_range_header *find_outer_range(struct list *ranges, const DWRITE_TEXT_RANGE *range)
2234 struct layout_range_header *cur;
2236 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
2238 if (cur->range.startPosition > range->startPosition)
2239 return NULL;
2241 if ((cur->range.startPosition + cur->range.length < range->startPosition + range->length) &&
2242 (range->startPosition < cur->range.startPosition + cur->range.length))
2243 return NULL;
2244 if (cur->range.startPosition + cur->range.length >= range->startPosition + range->length)
2245 return cur;
2248 return NULL;
2251 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos)
2253 struct layout_range *cur;
2255 LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, h.entry) {
2256 DWRITE_TEXT_RANGE *r = &cur->h.range;
2257 if (r->startPosition <= pos && pos < r->startPosition + r->length)
2258 return cur;
2261 return NULL;
2264 static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
2266 if (*dest == value) return FALSE;
2268 if (*dest)
2269 IUnknown_Release(*dest);
2270 *dest = value;
2271 if (*dest)
2272 IUnknown_AddRef(*dest);
2274 return TRUE;
2277 static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2279 struct layout_range_spacing *dest_spacing = (struct layout_range_spacing*)h;
2280 struct layout_range_iface *dest_iface = (struct layout_range_iface*)h;
2281 struct layout_range_bool *dest_bool = (struct layout_range_bool*)h;
2282 struct layout_range *dest = (struct layout_range*)h;
2284 BOOL changed = FALSE;
2286 switch (attr) {
2287 case LAYOUT_RANGE_ATTR_WEIGHT:
2288 changed = dest->weight != value->u.weight;
2289 dest->weight = value->u.weight;
2290 break;
2291 case LAYOUT_RANGE_ATTR_STYLE:
2292 changed = dest->style != value->u.style;
2293 dest->style = value->u.style;
2294 break;
2295 case LAYOUT_RANGE_ATTR_STRETCH:
2296 changed = dest->stretch != value->u.stretch;
2297 dest->stretch = value->u.stretch;
2298 break;
2299 case LAYOUT_RANGE_ATTR_FONTSIZE:
2300 changed = dest->fontsize != value->u.fontsize;
2301 dest->fontsize = value->u.fontsize;
2302 break;
2303 case LAYOUT_RANGE_ATTR_INLINE:
2304 changed = set_layout_range_iface_attr((IUnknown**)&dest->object, (IUnknown*)value->u.object);
2305 break;
2306 case LAYOUT_RANGE_ATTR_EFFECT:
2307 changed = set_layout_range_iface_attr((IUnknown**)&dest_iface->iface, (IUnknown*)value->u.effect);
2308 break;
2309 case LAYOUT_RANGE_ATTR_UNDERLINE:
2310 changed = dest_bool->value != value->u.underline;
2311 dest_bool->value = value->u.underline;
2312 break;
2313 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2314 changed = dest_bool->value != value->u.strikethrough;
2315 dest_bool->value = value->u.strikethrough;
2316 break;
2317 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2318 changed = dest->pair_kerning != value->u.pair_kerning;
2319 dest->pair_kerning = value->u.pair_kerning;
2320 break;
2321 case LAYOUT_RANGE_ATTR_FONTCOLL:
2322 changed = set_layout_range_iface_attr((IUnknown**)&dest->collection, (IUnknown*)value->u.collection);
2323 break;
2324 case LAYOUT_RANGE_ATTR_LOCALE:
2325 changed = strcmpiW(dest->locale, value->u.locale) != 0;
2326 if (changed) {
2327 strcpyW(dest->locale, value->u.locale);
2328 strlwrW(dest->locale);
2330 break;
2331 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2332 changed = strcmpW(dest->fontfamily, value->u.fontfamily) != 0;
2333 if (changed) {
2334 heap_free(dest->fontfamily);
2335 dest->fontfamily = heap_strdupW(value->u.fontfamily);
2337 break;
2338 case LAYOUT_RANGE_ATTR_SPACING:
2339 changed = dest_spacing->leading != value->u.spacing[0] ||
2340 dest_spacing->trailing != value->u.spacing[1] ||
2341 dest_spacing->min_advance != value->u.spacing[2];
2342 dest_spacing->leading = value->u.spacing[0];
2343 dest_spacing->trailing = value->u.spacing[1];
2344 dest_spacing->min_advance = value->u.spacing[2];
2345 break;
2346 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2347 changed = set_layout_range_iface_attr((IUnknown**)&dest_iface->iface, (IUnknown*)value->u.typography);
2348 break;
2349 default:
2353 return changed;
2356 static inline BOOL is_in_layout_range(const DWRITE_TEXT_RANGE *outer, const DWRITE_TEXT_RANGE *inner)
2358 return (inner->startPosition >= outer->startPosition) &&
2359 (inner->startPosition + inner->length <= outer->startPosition + outer->length);
2362 static inline HRESULT return_range(const struct layout_range_header *h, DWRITE_TEXT_RANGE *r)
2364 if (r) *r = h->range;
2365 return S_OK;
2368 /* Sets attribute value for given range, does all needed splitting/merging of existing ranges. */
2369 static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2371 struct layout_range_header *cur, *right, *left, *outer;
2372 BOOL changed = FALSE;
2373 struct list *ranges;
2374 DWRITE_TEXT_RANGE r;
2376 /* ignore zero length ranges */
2377 if (value->range.length == 0)
2378 return S_OK;
2380 /* select from ranges lists */
2381 switch (attr)
2383 case LAYOUT_RANGE_ATTR_WEIGHT:
2384 case LAYOUT_RANGE_ATTR_STYLE:
2385 case LAYOUT_RANGE_ATTR_STRETCH:
2386 case LAYOUT_RANGE_ATTR_FONTSIZE:
2387 case LAYOUT_RANGE_ATTR_INLINE:
2388 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2389 case LAYOUT_RANGE_ATTR_FONTCOLL:
2390 case LAYOUT_RANGE_ATTR_LOCALE:
2391 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2392 ranges = &layout->ranges;
2393 break;
2394 case LAYOUT_RANGE_ATTR_UNDERLINE:
2395 ranges = &layout->underline_ranges;
2396 break;
2397 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2398 ranges = &layout->strike_ranges;
2399 break;
2400 case LAYOUT_RANGE_ATTR_EFFECT:
2401 ranges = &layout->effects;
2402 break;
2403 case LAYOUT_RANGE_ATTR_SPACING:
2404 ranges = &layout->spacing;
2405 break;
2406 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2407 ranges = &layout->typographies;
2408 break;
2409 default:
2410 FIXME("unknown attr kind %d\n", attr);
2411 return E_FAIL;
2414 /* If new range is completely within existing range, split existing range in two */
2415 if ((outer = find_outer_range(ranges, &value->range))) {
2417 /* no need to add same range */
2418 if (is_same_layout_attrvalue(outer, attr, value))
2419 return S_OK;
2421 /* for matching range bounds just replace data */
2422 if (is_same_text_range(&outer->range, &value->range)) {
2423 changed = set_layout_range_attrval(outer, attr, value);
2424 goto done;
2427 /* add new range to the left */
2428 if (value->range.startPosition == outer->range.startPosition) {
2429 left = alloc_layout_range_from(outer, &value->range);
2430 if (!left) return E_OUTOFMEMORY;
2432 changed = set_layout_range_attrval(left, attr, value);
2433 list_add_before(&outer->entry, &left->entry);
2434 outer->range.startPosition += value->range.length;
2435 outer->range.length -= value->range.length;
2436 goto done;
2439 /* add new range to the right */
2440 if (value->range.startPosition + value->range.length == outer->range.startPosition + outer->range.length) {
2441 right = alloc_layout_range_from(outer, &value->range);
2442 if (!right) return E_OUTOFMEMORY;
2444 changed = set_layout_range_attrval(right, attr, value);
2445 list_add_after(&outer->entry, &right->entry);
2446 outer->range.length -= value->range.length;
2447 goto done;
2450 r.startPosition = value->range.startPosition + value->range.length;
2451 r.length = outer->range.length + outer->range.startPosition - r.startPosition;
2453 /* right part */
2454 right = alloc_layout_range_from(outer, &r);
2455 /* new range in the middle */
2456 cur = alloc_layout_range_from(outer, &value->range);
2457 if (!right || !cur) {
2458 free_layout_range(right);
2459 free_layout_range(cur);
2460 return E_OUTOFMEMORY;
2463 /* reuse container range as a left part */
2464 outer->range.length = value->range.startPosition - outer->range.startPosition;
2466 /* new part */
2467 set_layout_range_attrval(cur, attr, value);
2469 list_add_after(&outer->entry, &cur->entry);
2470 list_add_after(&cur->entry, &right->entry);
2472 layout->recompute = RECOMPUTE_EVERYTHING;
2473 return S_OK;
2476 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2477 Update all of them. */
2478 left = get_layout_range_header_by_pos(ranges, value->range.startPosition);
2479 if (left->range.startPosition == value->range.startPosition)
2480 changed = set_layout_range_attrval(left, attr, value);
2481 else /* need to split */ {
2482 r.startPosition = value->range.startPosition;
2483 r.length = left->range.length - value->range.startPosition + left->range.startPosition;
2484 left->range.length -= r.length;
2485 cur = alloc_layout_range_from(left, &r);
2486 changed = set_layout_range_attrval(cur, attr, value);
2487 list_add_after(&left->entry, &cur->entry);
2489 cur = LIST_ENTRY(list_next(ranges, &left->entry), struct layout_range_header, entry);
2491 /* for all existing ranges covered by new one update value */
2492 while (cur && is_in_layout_range(&value->range, &cur->range)) {
2493 changed |= set_layout_range_attrval(cur, attr, value);
2494 cur = LIST_ENTRY(list_next(ranges, &cur->entry), struct layout_range_header, entry);
2497 /* it's possible rightmost range intersects */
2498 if (cur && (cur->range.startPosition < value->range.startPosition + value->range.length)) {
2499 r.startPosition = cur->range.startPosition;
2500 r.length = value->range.startPosition + value->range.length - cur->range.startPosition;
2501 left = alloc_layout_range_from(cur, &r);
2502 changed |= set_layout_range_attrval(left, attr, value);
2503 cur->range.startPosition += left->range.length;
2504 cur->range.length -= left->range.length;
2505 list_add_before(&cur->entry, &left->entry);
2508 done:
2509 if (changed) {
2510 struct list *next, *i;
2512 layout->recompute = RECOMPUTE_EVERYTHING;
2513 i = list_head(ranges);
2514 while ((next = list_next(ranges, i))) {
2515 struct layout_range_header *next_range = LIST_ENTRY(next, struct layout_range_header, entry);
2517 cur = LIST_ENTRY(i, struct layout_range_header, entry);
2518 if (is_same_layout_attributes(cur, next_range)) {
2519 /* remove similar range */
2520 cur->range.length += next_range->range.length;
2521 list_remove(next);
2522 free_layout_range(next_range);
2524 else
2525 i = list_next(ranges, i);
2529 return S_OK;
2532 static inline const WCHAR *get_string_attribute_ptr(struct layout_range *range, enum layout_range_attr_kind kind)
2534 const WCHAR *str;
2536 switch (kind) {
2537 case LAYOUT_RANGE_ATTR_LOCALE:
2538 str = range->locale;
2539 break;
2540 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2541 str = range->fontfamily;
2542 break;
2543 default:
2544 str = NULL;
2547 return str;
2550 static HRESULT get_string_attribute_length(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2551 UINT32 *length, DWRITE_TEXT_RANGE *r)
2553 struct layout_range *range;
2554 const WCHAR *str;
2556 range = get_layout_range_by_pos(layout, position);
2557 if (!range) {
2558 *length = 0;
2559 return S_OK;
2562 str = get_string_attribute_ptr(range, kind);
2563 *length = strlenW(str);
2564 return return_range(&range->h, r);
2567 static HRESULT get_string_attribute_value(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2568 WCHAR *ret, UINT32 length, DWRITE_TEXT_RANGE *r)
2570 struct layout_range *range;
2571 const WCHAR *str;
2573 if (length == 0)
2574 return E_INVALIDARG;
2576 ret[0] = 0;
2577 range = get_layout_range_by_pos(layout, position);
2578 if (!range)
2579 return E_INVALIDARG;
2581 str = get_string_attribute_ptr(range, kind);
2582 if (length < strlenW(str) + 1)
2583 return E_NOT_SUFFICIENT_BUFFER;
2585 strcpyW(ret, str);
2586 return return_range(&range->h, r);
2589 static HRESULT WINAPI dwritetextlayout_QueryInterface(IDWriteTextLayout3 *iface, REFIID riid, void **obj)
2591 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2593 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2595 *obj = NULL;
2597 if (IsEqualIID(riid, &IID_IDWriteTextLayout3) ||
2598 IsEqualIID(riid, &IID_IDWriteTextLayout2) ||
2599 IsEqualIID(riid, &IID_IDWriteTextLayout1) ||
2600 IsEqualIID(riid, &IID_IDWriteTextLayout) ||
2601 IsEqualIID(riid, &IID_IUnknown))
2603 *obj = iface;
2605 else if (IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
2606 IsEqualIID(riid, &IID_IDWriteTextFormat))
2607 *obj = &This->IDWriteTextFormat1_iface;
2609 if (*obj) {
2610 IDWriteTextLayout3_AddRef(iface);
2611 return S_OK;
2614 return E_NOINTERFACE;
2617 static ULONG WINAPI dwritetextlayout_AddRef(IDWriteTextLayout3 *iface)
2619 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2620 ULONG ref = InterlockedIncrement(&This->ref);
2621 TRACE("(%p)->(%d)\n", This, ref);
2622 return ref;
2625 static ULONG WINAPI dwritetextlayout_Release(IDWriteTextLayout3 *iface)
2627 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2628 ULONG ref = InterlockedDecrement(&This->ref);
2630 TRACE("(%p)->(%d)\n", This, ref);
2632 if (!ref) {
2633 IDWriteFactory3_Release(This->factory);
2634 free_layout_ranges_list(This);
2635 free_layout_eruns(This);
2636 free_layout_runs(This);
2637 release_format_data(&This->format);
2638 heap_free(This->nominal_breakpoints);
2639 heap_free(This->actual_breakpoints);
2640 heap_free(This->clustermetrics);
2641 heap_free(This->clusters);
2642 heap_free(This->lines);
2643 heap_free(This->str);
2644 heap_free(This);
2647 return ref;
2650 static HRESULT WINAPI dwritetextlayout_SetTextAlignment(IDWriteTextLayout3 *iface, DWRITE_TEXT_ALIGNMENT alignment)
2652 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2653 return IDWriteTextFormat1_SetTextAlignment(&This->IDWriteTextFormat1_iface, alignment);
2656 static HRESULT WINAPI dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout3 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
2658 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2659 return IDWriteTextFormat1_SetParagraphAlignment(&This->IDWriteTextFormat1_iface, alignment);
2662 static HRESULT WINAPI dwritetextlayout_SetWordWrapping(IDWriteTextLayout3 *iface, DWRITE_WORD_WRAPPING wrapping)
2664 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2665 return IDWriteTextFormat1_SetWordWrapping(&This->IDWriteTextFormat1_iface, wrapping);
2668 static HRESULT WINAPI dwritetextlayout_SetReadingDirection(IDWriteTextLayout3 *iface, DWRITE_READING_DIRECTION direction)
2670 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2671 return IDWriteTextFormat1_SetReadingDirection(&This->IDWriteTextFormat1_iface, direction);
2674 static HRESULT WINAPI dwritetextlayout_SetFlowDirection(IDWriteTextLayout3 *iface, DWRITE_FLOW_DIRECTION direction)
2676 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2677 TRACE("(%p)->(%d)\n", This, direction);
2678 return IDWriteTextFormat1_SetFlowDirection(&This->IDWriteTextFormat1_iface, direction);
2681 static HRESULT WINAPI dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout3 *iface, FLOAT tabstop)
2683 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2684 TRACE("(%p)->(%.2f)\n", This, tabstop);
2685 return IDWriteTextFormat1_SetIncrementalTabStop(&This->IDWriteTextFormat1_iface, tabstop);
2688 static HRESULT WINAPI dwritetextlayout_SetTrimming(IDWriteTextLayout3 *iface, DWRITE_TRIMMING const *trimming,
2689 IDWriteInlineObject *trimming_sign)
2691 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2692 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
2693 return IDWriteTextFormat1_SetTrimming(&This->IDWriteTextFormat1_iface, trimming, trimming_sign);
2696 static HRESULT WINAPI dwritetextlayout_SetLineSpacing(IDWriteTextLayout3 *iface, DWRITE_LINE_SPACING_METHOD spacing,
2697 FLOAT line_spacing, FLOAT baseline)
2699 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2700 TRACE("(%p)->(%d %.2f %.2f)\n", This, spacing, line_spacing, baseline);
2701 return IDWriteTextFormat1_SetLineSpacing(&This->IDWriteTextFormat1_iface, spacing, line_spacing, baseline);
2704 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextlayout_GetTextAlignment(IDWriteTextLayout3 *iface)
2706 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2707 return IDWriteTextFormat1_GetTextAlignment(&This->IDWriteTextFormat1_iface);
2710 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout3 *iface)
2712 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2713 return IDWriteTextFormat1_GetParagraphAlignment(&This->IDWriteTextFormat1_iface);
2716 static DWRITE_WORD_WRAPPING WINAPI dwritetextlayout_GetWordWrapping(IDWriteTextLayout3 *iface)
2718 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2719 return IDWriteTextFormat1_GetWordWrapping(&This->IDWriteTextFormat1_iface);
2722 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_GetReadingDirection(IDWriteTextLayout3 *iface)
2724 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2725 return IDWriteTextFormat1_GetReadingDirection(&This->IDWriteTextFormat1_iface);
2728 static DWRITE_FLOW_DIRECTION WINAPI dwritetextlayout_GetFlowDirection(IDWriteTextLayout3 *iface)
2730 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2731 return IDWriteTextFormat1_GetFlowDirection(&This->IDWriteTextFormat1_iface);
2734 static FLOAT WINAPI dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout3 *iface)
2736 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2737 return IDWriteTextFormat1_GetIncrementalTabStop(&This->IDWriteTextFormat1_iface);
2740 static HRESULT WINAPI dwritetextlayout_GetTrimming(IDWriteTextLayout3 *iface, DWRITE_TRIMMING *options,
2741 IDWriteInlineObject **trimming_sign)
2743 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2744 return IDWriteTextFormat1_GetTrimming(&This->IDWriteTextFormat1_iface, options, trimming_sign);
2747 static HRESULT WINAPI dwritetextlayout_GetLineSpacing(IDWriteTextLayout3 *iface, DWRITE_LINE_SPACING_METHOD *method,
2748 FLOAT *spacing, FLOAT *baseline)
2750 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2751 return IDWriteTextFormat_GetLineSpacing((IDWriteTextFormat*)&This->IDWriteTextFormat1_iface, method, spacing, baseline);
2754 static HRESULT WINAPI dwritetextlayout_GetFontCollection(IDWriteTextLayout3 *iface, IDWriteFontCollection **collection)
2756 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2757 return IDWriteTextFormat1_GetFontCollection(&This->IDWriteTextFormat1_iface, collection);
2760 static UINT32 WINAPI dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout3 *iface)
2762 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2763 return IDWriteTextFormat1_GetFontFamilyNameLength(&This->IDWriteTextFormat1_iface);
2766 static HRESULT WINAPI dwritetextlayout_GetFontFamilyName(IDWriteTextLayout3 *iface, WCHAR *name, UINT32 size)
2768 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2769 return IDWriteTextFormat1_GetFontFamilyName(&This->IDWriteTextFormat1_iface, name, size);
2772 static DWRITE_FONT_WEIGHT WINAPI dwritetextlayout_GetFontWeight(IDWriteTextLayout3 *iface)
2774 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2775 return IDWriteTextFormat1_GetFontWeight(&This->IDWriteTextFormat1_iface);
2778 static DWRITE_FONT_STYLE WINAPI dwritetextlayout_GetFontStyle(IDWriteTextLayout3 *iface)
2780 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2781 return IDWriteTextFormat1_GetFontStyle(&This->IDWriteTextFormat1_iface);
2784 static DWRITE_FONT_STRETCH WINAPI dwritetextlayout_GetFontStretch(IDWriteTextLayout3 *iface)
2786 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2787 return IDWriteTextFormat1_GetFontStretch(&This->IDWriteTextFormat1_iface);
2790 static FLOAT WINAPI dwritetextlayout_GetFontSize(IDWriteTextLayout3 *iface)
2792 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2793 return IDWriteTextFormat1_GetFontSize(&This->IDWriteTextFormat1_iface);
2796 static UINT32 WINAPI dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout3 *iface)
2798 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2799 return IDWriteTextFormat1_GetLocaleNameLength(&This->IDWriteTextFormat1_iface);
2802 static HRESULT WINAPI dwritetextlayout_GetLocaleName(IDWriteTextLayout3 *iface, WCHAR *name, UINT32 size)
2804 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2805 return IDWriteTextFormat1_GetLocaleName(&This->IDWriteTextFormat1_iface, name, size);
2808 static HRESULT WINAPI dwritetextlayout_SetMaxWidth(IDWriteTextLayout3 *iface, FLOAT maxWidth)
2810 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2812 TRACE("(%p)->(%.2f)\n", This, maxWidth);
2814 if (maxWidth < 0.0f)
2815 return E_INVALIDARG;
2817 This->metrics.layoutWidth = maxWidth;
2818 return S_OK;
2821 static HRESULT WINAPI dwritetextlayout_SetMaxHeight(IDWriteTextLayout3 *iface, FLOAT maxHeight)
2823 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2825 TRACE("(%p)->(%.2f)\n", This, maxHeight);
2827 if (maxHeight < 0.0f)
2828 return E_INVALIDARG;
2830 This->metrics.layoutHeight = maxHeight;
2831 return S_OK;
2834 static HRESULT WINAPI dwritetextlayout_SetFontCollection(IDWriteTextLayout3 *iface, IDWriteFontCollection* collection, DWRITE_TEXT_RANGE range)
2836 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2837 struct layout_range_attr_value value;
2839 TRACE("(%p)->(%p %s)\n", This, collection, debugstr_range(&range));
2841 value.range = range;
2842 value.u.collection = collection;
2843 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTCOLL, &value);
2846 static HRESULT WINAPI dwritetextlayout_SetFontFamilyName(IDWriteTextLayout3 *iface, WCHAR const *name, DWRITE_TEXT_RANGE range)
2848 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2849 struct layout_range_attr_value value;
2851 TRACE("(%p)->(%s %s)\n", This, debugstr_w(name), debugstr_range(&range));
2853 if (!name)
2854 return E_INVALIDARG;
2856 value.range = range;
2857 value.u.fontfamily = name;
2858 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTFAMILY, &value);
2861 static HRESULT WINAPI dwritetextlayout_SetFontWeight(IDWriteTextLayout3 *iface, DWRITE_FONT_WEIGHT weight, DWRITE_TEXT_RANGE range)
2863 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2864 struct layout_range_attr_value value;
2866 TRACE("(%p)->(%d %s)\n", This, weight, debugstr_range(&range));
2868 value.range = range;
2869 value.u.weight = weight;
2870 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_WEIGHT, &value);
2873 static HRESULT WINAPI dwritetextlayout_SetFontStyle(IDWriteTextLayout3 *iface, DWRITE_FONT_STYLE style, DWRITE_TEXT_RANGE range)
2875 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2876 struct layout_range_attr_value value;
2878 TRACE("(%p)->(%d %s)\n", This, style, debugstr_range(&range));
2880 if ((UINT32)style > DWRITE_FONT_STYLE_ITALIC)
2881 return E_INVALIDARG;
2883 value.range = range;
2884 value.u.style = style;
2885 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STYLE, &value);
2888 static HRESULT WINAPI dwritetextlayout_SetFontStretch(IDWriteTextLayout3 *iface, DWRITE_FONT_STRETCH stretch, DWRITE_TEXT_RANGE range)
2890 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2891 struct layout_range_attr_value value;
2893 TRACE("(%p)->(%d %s)\n", This, stretch, debugstr_range(&range));
2895 if (stretch == DWRITE_FONT_STRETCH_UNDEFINED || (UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
2896 return E_INVALIDARG;
2898 value.range = range;
2899 value.u.stretch = stretch;
2900 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRETCH, &value);
2903 static HRESULT WINAPI dwritetextlayout_SetFontSize(IDWriteTextLayout3 *iface, FLOAT size, DWRITE_TEXT_RANGE range)
2905 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2906 struct layout_range_attr_value value;
2908 TRACE("(%p)->(%.2f %s)\n", This, size, debugstr_range(&range));
2910 if (size <= 0.0f)
2911 return E_INVALIDARG;
2913 value.range = range;
2914 value.u.fontsize = size;
2915 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTSIZE, &value);
2918 static HRESULT WINAPI dwritetextlayout_SetUnderline(IDWriteTextLayout3 *iface, BOOL underline, DWRITE_TEXT_RANGE range)
2920 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2921 struct layout_range_attr_value value;
2923 TRACE("(%p)->(%d %s)\n", This, underline, debugstr_range(&range));
2925 value.range = range;
2926 value.u.underline = underline;
2927 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_UNDERLINE, &value);
2930 static HRESULT WINAPI dwritetextlayout_SetStrikethrough(IDWriteTextLayout3 *iface, BOOL strikethrough, DWRITE_TEXT_RANGE range)
2932 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2933 struct layout_range_attr_value value;
2935 TRACE("(%p)->(%d %s)\n", This, strikethrough, debugstr_range(&range));
2937 value.range = range;
2938 value.u.strikethrough = strikethrough;
2939 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRIKETHROUGH, &value);
2942 static HRESULT WINAPI dwritetextlayout_SetDrawingEffect(IDWriteTextLayout3 *iface, IUnknown* effect, DWRITE_TEXT_RANGE range)
2944 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2945 struct layout_range_attr_value value;
2947 TRACE("(%p)->(%p %s)\n", This, effect, debugstr_range(&range));
2949 value.range = range;
2950 value.u.effect = effect;
2951 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_EFFECT, &value);
2954 static HRESULT WINAPI dwritetextlayout_SetInlineObject(IDWriteTextLayout3 *iface, IDWriteInlineObject *object, DWRITE_TEXT_RANGE range)
2956 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2957 struct layout_range_attr_value value;
2959 TRACE("(%p)->(%p %s)\n", This, object, debugstr_range(&range));
2961 value.range = range;
2962 value.u.object = object;
2963 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_INLINE, &value);
2966 static HRESULT WINAPI dwritetextlayout_SetTypography(IDWriteTextLayout3 *iface, IDWriteTypography* typography, DWRITE_TEXT_RANGE range)
2968 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2969 struct layout_range_attr_value value;
2971 TRACE("(%p)->(%p %s)\n", This, typography, debugstr_range(&range));
2973 value.range = range;
2974 value.u.typography = typography;
2975 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_TYPOGRAPHY, &value);
2978 static HRESULT WINAPI dwritetextlayout_SetLocaleName(IDWriteTextLayout3 *iface, WCHAR const* locale, DWRITE_TEXT_RANGE range)
2980 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2981 struct layout_range_attr_value value;
2983 TRACE("(%p)->(%s %s)\n", This, debugstr_w(locale), debugstr_range(&range));
2985 if (!locale || strlenW(locale) > LOCALE_NAME_MAX_LENGTH-1)
2986 return E_INVALIDARG;
2988 value.range = range;
2989 value.u.locale = locale;
2990 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_LOCALE, &value);
2993 static FLOAT WINAPI dwritetextlayout_GetMaxWidth(IDWriteTextLayout3 *iface)
2995 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2996 TRACE("(%p)\n", This);
2997 return This->metrics.layoutWidth;
3000 static FLOAT WINAPI dwritetextlayout_GetMaxHeight(IDWriteTextLayout3 *iface)
3002 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3003 TRACE("(%p)\n", This);
3004 return This->metrics.layoutHeight;
3007 static HRESULT WINAPI dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout3 *iface, UINT32 position,
3008 IDWriteFontCollection** collection, DWRITE_TEXT_RANGE *r)
3010 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3011 struct layout_range *range;
3013 TRACE("(%p)->(%u %p %p)\n", This, position, collection, r);
3015 if (position >= This->len)
3016 return S_OK;
3018 range = get_layout_range_by_pos(This, position);
3019 *collection = range->collection;
3020 if (*collection)
3021 IDWriteFontCollection_AddRef(*collection);
3023 return return_range(&range->h, r);
3026 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout3 *iface,
3027 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
3029 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3030 TRACE("(%p)->(%d %p %p)\n", This, position, length, r);
3031 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, length, r);
3034 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout3 *iface,
3035 UINT32 position, WCHAR *name, UINT32 length, DWRITE_TEXT_RANGE *r)
3037 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3038 TRACE("(%p)->(%u %p %u %p)\n", This, position, name, length, r);
3039 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, name, length, r);
3042 static HRESULT WINAPI dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout3 *iface,
3043 UINT32 position, DWRITE_FONT_WEIGHT *weight, DWRITE_TEXT_RANGE *r)
3045 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3046 struct layout_range *range;
3048 TRACE("(%p)->(%u %p %p)\n", This, position, weight, r);
3050 if (position >= This->len)
3051 return S_OK;
3053 range = get_layout_range_by_pos(This, position);
3054 *weight = range->weight;
3056 return return_range(&range->h, r);
3059 static HRESULT WINAPI dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout3 *iface,
3060 UINT32 position, DWRITE_FONT_STYLE *style, DWRITE_TEXT_RANGE *r)
3062 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3063 struct layout_range *range;
3065 TRACE("(%p)->(%u %p %p)\n", This, position, style, r);
3067 range = get_layout_range_by_pos(This, position);
3068 *style = range->style;
3069 return return_range(&range->h, r);
3072 static HRESULT WINAPI dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout3 *iface,
3073 UINT32 position, DWRITE_FONT_STRETCH *stretch, DWRITE_TEXT_RANGE *r)
3075 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3076 struct layout_range *range;
3078 TRACE("(%p)->(%u %p %p)\n", This, position, stretch, r);
3080 range = get_layout_range_by_pos(This, position);
3081 *stretch = range->stretch;
3082 return return_range(&range->h, r);
3085 static HRESULT WINAPI dwritetextlayout_layout_GetFontSize(IDWriteTextLayout3 *iface,
3086 UINT32 position, FLOAT *size, DWRITE_TEXT_RANGE *r)
3088 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3089 struct layout_range *range;
3091 TRACE("(%p)->(%u %p %p)\n", This, position, size, r);
3093 range = get_layout_range_by_pos(This, position);
3094 *size = range->fontsize;
3095 return return_range(&range->h, r);
3098 static HRESULT WINAPI dwritetextlayout_GetUnderline(IDWriteTextLayout3 *iface,
3099 UINT32 position, BOOL *underline, DWRITE_TEXT_RANGE *r)
3101 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3102 struct layout_range_bool *range;
3104 TRACE("(%p)->(%u %p %p)\n", This, position, underline, r);
3106 range = (struct layout_range_bool*)get_layout_range_header_by_pos(&This->underline_ranges, position);
3107 *underline = range->value;
3109 return return_range(&range->h, r);
3112 static HRESULT WINAPI dwritetextlayout_GetStrikethrough(IDWriteTextLayout3 *iface,
3113 UINT32 position, BOOL *strikethrough, DWRITE_TEXT_RANGE *r)
3115 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3116 struct layout_range_bool *range;
3118 TRACE("(%p)->(%u %p %p)\n", This, position, strikethrough, r);
3120 range = (struct layout_range_bool*)get_layout_range_header_by_pos(&This->strike_ranges, position);
3121 *strikethrough = range->value;
3123 return return_range(&range->h, r);
3126 static HRESULT WINAPI dwritetextlayout_GetDrawingEffect(IDWriteTextLayout3 *iface,
3127 UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r)
3129 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3130 struct layout_range_iface *range;
3132 TRACE("(%p)->(%u %p %p)\n", This, position, effect, r);
3134 range = (struct layout_range_iface*)get_layout_range_header_by_pos(&This->effects, position);
3135 *effect = range->iface;
3136 if (*effect)
3137 IUnknown_AddRef(*effect);
3139 return return_range(&range->h, r);
3142 static HRESULT WINAPI dwritetextlayout_GetInlineObject(IDWriteTextLayout3 *iface,
3143 UINT32 position, IDWriteInlineObject **object, DWRITE_TEXT_RANGE *r)
3145 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3146 struct layout_range *range;
3148 TRACE("(%p)->(%u %p %p)\n", This, position, object, r);
3150 if (position >= This->len)
3151 return S_OK;
3153 range = get_layout_range_by_pos(This, position);
3154 *object = range->object;
3155 if (*object)
3156 IDWriteInlineObject_AddRef(*object);
3158 return return_range(&range->h, r);
3161 static HRESULT WINAPI dwritetextlayout_GetTypography(IDWriteTextLayout3 *iface,
3162 UINT32 position, IDWriteTypography** typography, DWRITE_TEXT_RANGE *r)
3164 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3165 struct layout_range_iface *range;
3167 TRACE("(%p)->(%u %p %p)\n", This, position, typography, r);
3169 range = (struct layout_range_iface*)get_layout_range_header_by_pos(&This->typographies, position);
3170 *typography = (IDWriteTypography*)range->iface;
3171 if (*typography)
3172 IDWriteTypography_AddRef(*typography);
3174 return return_range(&range->h, r);
3177 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout3 *iface,
3178 UINT32 position, UINT32* length, DWRITE_TEXT_RANGE *r)
3180 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3181 TRACE("(%p)->(%u %p %p)\n", This, position, length, r);
3182 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_LOCALE, position, length, r);
3185 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout3 *iface,
3186 UINT32 position, WCHAR* locale, UINT32 length, DWRITE_TEXT_RANGE *r)
3188 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3189 TRACE("(%p)->(%u %p %u %p)\n", This, position, locale, length, r);
3190 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_LOCALE, position, locale, length, r);
3193 static inline FLOAT renderer_apply_snapping(FLOAT coord, BOOL skiptransform, FLOAT ppdip, FLOAT det,
3194 const DWRITE_MATRIX *m)
3196 FLOAT vec[2], vec2[2];
3198 if (!skiptransform) {
3199 /* apply transform */
3200 vec[0] = 0.0f;
3201 vec[1] = coord * ppdip;
3203 vec2[0] = m->m11 * vec[0] + m->m21 * vec[1] + m->dx;
3204 vec2[1] = m->m12 * vec[0] + m->m22 * vec[1] + m->dy;
3206 /* snap */
3207 vec2[0] = floorf(vec2[0] + 0.5f);
3208 vec2[1] = floorf(vec2[1] + 0.5f);
3210 /* apply inverted transform, we don't care about X component at this point */
3211 vec[1] = (-m->m12 * vec2[0] + m->m11 * vec2[1] - (m->m11 * m->dy - m->m12 * m->dx)) / det;
3212 vec[1] /= ppdip;
3214 else
3215 vec[1] = floorf(coord * ppdip + 0.5f) / ppdip;
3217 return vec[1];
3220 static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout3 *iface,
3221 void *context, IDWriteTextRenderer* renderer, FLOAT origin_x, FLOAT origin_y)
3223 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3224 BOOL disabled = FALSE, skiptransform = FALSE;
3225 struct layout_effective_inline *inlineobject;
3226 struct layout_effective_run *run;
3227 struct layout_strikethrough *s;
3228 struct layout_underline *u;
3229 FLOAT det = 0.0f, ppdip = 0.0f;
3230 DWRITE_MATRIX m = { 0 };
3231 HRESULT hr;
3233 TRACE("(%p)->(%p %p %.2f %.2f)\n", This, context, renderer, origin_x, origin_y);
3235 hr = layout_compute_effective_runs(This);
3236 if (FAILED(hr))
3237 return hr;
3239 hr = IDWriteTextRenderer_IsPixelSnappingDisabled(renderer, context, &disabled);
3240 if (FAILED(hr))
3241 return hr;
3243 if (!disabled) {
3244 hr = IDWriteTextRenderer_GetPixelsPerDip(renderer, context, &ppdip);
3245 if (FAILED(hr))
3246 return hr;
3248 hr = IDWriteTextRenderer_GetCurrentTransform(renderer, context, &m);
3249 if (FAILED(hr))
3250 return hr;
3252 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
3253 if (ppdip <= 0.0f ||
3254 (m.m11 * m.m22 != 0.0f && (m.m12 != 0.0f || m.m21 != 0.0f)) ||
3255 (m.m12 * m.m21 != 0.0f && (m.m11 != 0.0f || m.m22 != 0.0f)))
3256 disabled = TRUE;
3257 else
3258 skiptransform = should_skip_transform(&m, &det);
3261 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
3262 /* 1. Regular runs */
3263 LIST_FOR_EACH_ENTRY(run, &This->eruns, struct layout_effective_run, entry) {
3264 const struct regular_layout_run *regular = &run->run->u.regular;
3265 UINT32 start_glyph = regular->clustermap[run->start];
3266 DWRITE_GLYPH_RUN_DESCRIPTION descr;
3267 DWRITE_GLYPH_RUN glyph_run;
3269 /* Everything but cluster map will be reused from nominal run, as we only need
3270 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
3271 it can't be reused because it has to start with 0 index for each reported run. */
3272 glyph_run = regular->run;
3273 glyph_run.glyphCount = run->glyphcount;
3275 /* fixup glyph data arrays */
3276 glyph_run.glyphIndices += start_glyph;
3277 glyph_run.glyphAdvances += start_glyph;
3278 glyph_run.glyphOffsets += start_glyph;
3280 /* description */
3281 descr = regular->descr;
3282 descr.stringLength = run->length;
3283 descr.string += run->start;
3284 descr.clusterMap = run->clustermap;
3285 descr.textPosition += run->start;
3287 /* return value is ignored */
3288 IDWriteTextRenderer_DrawGlyphRun(renderer,
3289 context,
3290 run->origin_x + run->align_dx + origin_x,
3291 SNAP_COORD(run->origin_y + origin_y),
3292 This->measuringmode,
3293 &glyph_run,
3294 &descr,
3295 run->effect);
3298 /* 2. Inline objects */
3299 LIST_FOR_EACH_ENTRY(inlineobject, &This->inlineobjects, struct layout_effective_inline, entry) {
3300 IDWriteTextRenderer_DrawInlineObject(renderer,
3301 context,
3302 inlineobject->origin_x + inlineobject->align_dx + origin_x,
3303 SNAP_COORD(inlineobject->origin_y + origin_y),
3304 inlineobject->run->u.object.object,
3305 inlineobject->is_sideways,
3306 inlineobject->is_rtl,
3307 inlineobject->effect);
3310 /* 3. Underlines */
3311 LIST_FOR_EACH_ENTRY(u, &This->underlines, struct layout_underline, entry) {
3312 IDWriteTextRenderer_DrawUnderline(renderer,
3313 context,
3314 /* horizontal underline always grows from left to right, width is always added to origin regardless of run direction */
3315 (is_run_rtl(u->run) ? u->run->origin_x - u->run->width : u->run->origin_x) + u->run->align_dx + origin_x,
3316 SNAP_COORD(u->run->origin_y + origin_y),
3317 &u->u,
3318 u->run->effect);
3321 /* 4. Strikethrough */
3322 LIST_FOR_EACH_ENTRY(s, &This->strikethrough, struct layout_strikethrough, entry) {
3323 IDWriteTextRenderer_DrawStrikethrough(renderer,
3324 context,
3325 s->run->origin_x + s->run->align_dx + origin_x,
3326 SNAP_COORD(s->run->origin_y + origin_y),
3327 &s->s,
3328 s->run->effect);
3330 #undef SNAP_COORD
3332 return S_OK;
3335 static HRESULT WINAPI dwritetextlayout_GetLineMetrics(IDWriteTextLayout3 *iface,
3336 DWRITE_LINE_METRICS *metrics, UINT32 max_count, UINT32 *count)
3338 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3339 HRESULT hr;
3341 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
3343 hr = layout_compute_effective_runs(This);
3344 if (FAILED(hr))
3345 return hr;
3347 if (metrics)
3348 memcpy(metrics, This->lines, sizeof(*metrics)*min(max_count, This->metrics.lineCount));
3350 *count = This->metrics.lineCount;
3351 return max_count >= This->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3354 static HRESULT WINAPI dwritetextlayout_GetMetrics(IDWriteTextLayout3 *iface, DWRITE_TEXT_METRICS *metrics)
3356 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3357 DWRITE_TEXT_METRICS1 metrics1;
3358 HRESULT hr;
3360 TRACE("(%p)->(%p)\n", This, metrics);
3362 hr = IDWriteTextLayout3_GetMetrics(iface, &metrics1);
3363 if (hr == S_OK)
3364 memcpy(metrics, &metrics1, sizeof(*metrics));
3366 return hr;
3369 static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout3 *iface, DWRITE_OVERHANG_METRICS *overhangs)
3371 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3372 FIXME("(%p)->(%p): stub\n", This, overhangs);
3373 return E_NOTIMPL;
3376 static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout3 *iface,
3377 DWRITE_CLUSTER_METRICS *metrics, UINT32 max_count, UINT32 *count)
3379 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3380 HRESULT hr;
3382 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
3384 hr = layout_compute(This);
3385 if (FAILED(hr))
3386 return hr;
3388 if (metrics)
3389 memcpy(metrics, This->clustermetrics, sizeof(DWRITE_CLUSTER_METRICS)*min(max_count, This->cluster_count));
3391 *count = This->cluster_count;
3392 return max_count >= This->cluster_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3395 static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout3 *iface, FLOAT* min_width)
3397 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3398 UINT32 start;
3399 FLOAT width;
3400 HRESULT hr;
3402 TRACE("(%p)->(%p)\n", This, min_width);
3404 if (!min_width)
3405 return E_INVALIDARG;
3407 if (!(This->recompute & RECOMPUTE_MINIMAL_WIDTH))
3408 goto width_done;
3410 *min_width = 0.0f;
3411 hr = layout_compute(This);
3412 if (FAILED(hr))
3413 return hr;
3415 /* Find widest word without emergency breaking between clusters, trailing whitespaces
3416 preceding breaking point do not contribute to word width. */
3417 for (start = 0; start < This->cluster_count;) {
3418 UINT32 end = start, j, next;
3420 /* Last cluster always could be wrapped after. */
3421 while (!This->clustermetrics[end].canWrapLineAfter)
3422 end++;
3423 /* make is so current cluster range that we can wrap after is [start,end) */
3424 end++;
3426 next = end;
3428 /* Ignore trailing whitespace clusters, in case of single space range will
3429 be reduced to empty range, or [start,start+1). */
3430 while (end > start && This->clustermetrics[end-1].isWhitespace)
3431 end--;
3433 /* check if cluster range exceeds last minimal width */
3434 width = 0.0f;
3435 for (j = start; j < end; j++)
3436 width += This->clustermetrics[j].width;
3438 start = next;
3440 if (width > This->minwidth)
3441 This->minwidth = width;
3443 This->recompute &= ~RECOMPUTE_MINIMAL_WIDTH;
3445 width_done:
3446 *min_width = This->minwidth;
3447 return S_OK;
3450 static HRESULT WINAPI dwritetextlayout_HitTestPoint(IDWriteTextLayout3 *iface,
3451 FLOAT pointX, FLOAT pointY, BOOL* is_trailinghit, BOOL* is_inside, DWRITE_HIT_TEST_METRICS *metrics)
3453 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3454 FIXME("(%p)->(%f %f %p %p %p): stub\n", This, pointX, pointY, is_trailinghit, is_inside, metrics);
3455 return E_NOTIMPL;
3458 static HRESULT WINAPI dwritetextlayout_HitTestTextPosition(IDWriteTextLayout3 *iface,
3459 UINT32 textPosition, BOOL is_trailinghit, FLOAT* pointX, FLOAT* pointY, DWRITE_HIT_TEST_METRICS *metrics)
3461 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3462 FIXME("(%p)->(%u %d %p %p %p): stub\n", This, textPosition, is_trailinghit, pointX, pointY, metrics);
3463 return E_NOTIMPL;
3466 static HRESULT WINAPI dwritetextlayout_HitTestTextRange(IDWriteTextLayout3 *iface,
3467 UINT32 textPosition, UINT32 textLength, FLOAT originX, FLOAT originY,
3468 DWRITE_HIT_TEST_METRICS *metrics, UINT32 max_metricscount, UINT32* actual_metricscount)
3470 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3471 FIXME("(%p)->(%u %u %f %f %p %u %p): stub\n", This, textPosition, textLength, originX, originY, metrics,
3472 max_metricscount, actual_metricscount);
3473 return E_NOTIMPL;
3476 static HRESULT WINAPI dwritetextlayout1_SetPairKerning(IDWriteTextLayout3 *iface, BOOL is_pairkerning_enabled,
3477 DWRITE_TEXT_RANGE range)
3479 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3480 struct layout_range_attr_value value;
3482 TRACE("(%p)->(%d %s)\n", This, is_pairkerning_enabled, debugstr_range(&range));
3484 value.range = range;
3485 value.u.pair_kerning = !!is_pairkerning_enabled;
3486 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_PAIR_KERNING, &value);
3489 static HRESULT WINAPI dwritetextlayout1_GetPairKerning(IDWriteTextLayout3 *iface, UINT32 position, BOOL *is_pairkerning_enabled,
3490 DWRITE_TEXT_RANGE *r)
3492 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3493 struct layout_range *range;
3495 TRACE("(%p)->(%u %p %p)\n", This, position, is_pairkerning_enabled, r);
3497 if (position >= This->len)
3498 return S_OK;
3500 range = get_layout_range_by_pos(This, position);
3501 *is_pairkerning_enabled = range->pair_kerning;
3503 return return_range(&range->h, r);
3506 static HRESULT WINAPI dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout3 *iface, FLOAT leading, FLOAT trailing,
3507 FLOAT min_advance, DWRITE_TEXT_RANGE range)
3509 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3510 struct layout_range_attr_value value;
3512 TRACE("(%p)->(%.2f %.2f %.2f %s)\n", This, leading, trailing, min_advance, debugstr_range(&range));
3514 if (min_advance < 0.0f)
3515 return E_INVALIDARG;
3517 value.range = range;
3518 value.u.spacing[0] = leading;
3519 value.u.spacing[1] = trailing;
3520 value.u.spacing[2] = min_advance;
3521 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_SPACING, &value);
3524 static HRESULT WINAPI dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout3 *iface, UINT32 position, FLOAT *leading,
3525 FLOAT *trailing, FLOAT *min_advance, DWRITE_TEXT_RANGE *r)
3527 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3528 struct layout_range_spacing *range;
3530 TRACE("(%p)->(%u %p %p %p %p)\n", This, position, leading, trailing, min_advance, r);
3532 range = (struct layout_range_spacing*)get_layout_range_header_by_pos(&This->spacing, position);
3533 *leading = range->leading;
3534 *trailing = range->trailing;
3535 *min_advance = range->min_advance;
3537 return return_range(&range->h, r);
3540 static HRESULT WINAPI dwritetextlayout2_GetMetrics(IDWriteTextLayout3 *iface, DWRITE_TEXT_METRICS1 *metrics)
3542 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3543 HRESULT hr;
3545 TRACE("(%p)->(%p)\n", This, metrics);
3547 hr = layout_compute_effective_runs(This);
3548 if (FAILED(hr))
3549 return hr;
3551 *metrics = This->metrics;
3552 return S_OK;
3555 static HRESULT WINAPI dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout3 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
3557 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3559 TRACE("(%p)->(%d)\n", This, orientation);
3561 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
3562 return E_INVALIDARG;
3564 This->format.vertical_orientation = orientation;
3565 return S_OK;
3568 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout3 *iface)
3570 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3571 TRACE("(%p)\n", This);
3572 return This->format.vertical_orientation;
3575 static HRESULT WINAPI dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout3 *iface, BOOL lastline_wrapping_enabled)
3577 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3578 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
3579 return IDWriteTextFormat1_SetLastLineWrapping(&This->IDWriteTextFormat1_iface, lastline_wrapping_enabled);
3582 static BOOL WINAPI dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout3 *iface)
3584 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3585 TRACE("(%p)\n", This);
3586 return IDWriteTextFormat1_GetLastLineWrapping(&This->IDWriteTextFormat1_iface);
3589 static HRESULT WINAPI dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout3 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
3591 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3592 TRACE("(%p)->(%d)\n", This, alignment);
3593 return IDWriteTextFormat1_SetOpticalAlignment(&This->IDWriteTextFormat1_iface, alignment);
3596 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout3 *iface)
3598 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3599 TRACE("(%p)\n", This);
3600 return IDWriteTextFormat1_GetOpticalAlignment(&This->IDWriteTextFormat1_iface);
3603 static HRESULT WINAPI dwritetextlayout2_SetFontFallback(IDWriteTextLayout3 *iface, IDWriteFontFallback *fallback)
3605 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3606 TRACE("(%p)->(%p)\n", This, fallback);
3607 return set_fontfallback_for_format(&This->format, fallback);
3610 static HRESULT WINAPI dwritetextlayout2_GetFontFallback(IDWriteTextLayout3 *iface, IDWriteFontFallback **fallback)
3612 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3613 TRACE("(%p)->(%p)\n", This, fallback);
3614 return get_fontfallback_from_format(&This->format, fallback);
3617 static HRESULT WINAPI dwritetextlayout3_InvalidateLayout(IDWriteTextLayout3 *iface)
3619 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3621 TRACE("(%p)\n", This);
3623 This->recompute = RECOMPUTE_EVERYTHING;
3624 return S_OK;
3627 static HRESULT WINAPI dwritetextlayout3_SetLineSpacing(IDWriteTextLayout3 *iface, DWRITE_LINE_SPACING const *spacing)
3629 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3630 FIXME("(%p)->(%p): stub\n", This, spacing);
3631 return E_NOTIMPL;
3634 static HRESULT WINAPI dwritetextlayout3_GetLineSpacing(IDWriteTextLayout3 *iface, DWRITE_LINE_SPACING *spacing)
3636 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3637 FIXME("(%p)->(%p): stub\n", This, spacing);
3638 return E_NOTIMPL;
3641 static HRESULT WINAPI dwritetextlayout3_GetLineMetrics(IDWriteTextLayout3 *iface, DWRITE_LINE_METRICS1 *metrics,
3642 UINT32 max_count, UINT32 *count)
3644 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3645 FIXME("(%p)->(%p %u %p): stub\n", This, metrics, max_count, count);
3646 return E_NOTIMPL;
3649 static const IDWriteTextLayout3Vtbl dwritetextlayoutvtbl = {
3650 dwritetextlayout_QueryInterface,
3651 dwritetextlayout_AddRef,
3652 dwritetextlayout_Release,
3653 dwritetextlayout_SetTextAlignment,
3654 dwritetextlayout_SetParagraphAlignment,
3655 dwritetextlayout_SetWordWrapping,
3656 dwritetextlayout_SetReadingDirection,
3657 dwritetextlayout_SetFlowDirection,
3658 dwritetextlayout_SetIncrementalTabStop,
3659 dwritetextlayout_SetTrimming,
3660 dwritetextlayout_SetLineSpacing,
3661 dwritetextlayout_GetTextAlignment,
3662 dwritetextlayout_GetParagraphAlignment,
3663 dwritetextlayout_GetWordWrapping,
3664 dwritetextlayout_GetReadingDirection,
3665 dwritetextlayout_GetFlowDirection,
3666 dwritetextlayout_GetIncrementalTabStop,
3667 dwritetextlayout_GetTrimming,
3668 dwritetextlayout_GetLineSpacing,
3669 dwritetextlayout_GetFontCollection,
3670 dwritetextlayout_GetFontFamilyNameLength,
3671 dwritetextlayout_GetFontFamilyName,
3672 dwritetextlayout_GetFontWeight,
3673 dwritetextlayout_GetFontStyle,
3674 dwritetextlayout_GetFontStretch,
3675 dwritetextlayout_GetFontSize,
3676 dwritetextlayout_GetLocaleNameLength,
3677 dwritetextlayout_GetLocaleName,
3678 dwritetextlayout_SetMaxWidth,
3679 dwritetextlayout_SetMaxHeight,
3680 dwritetextlayout_SetFontCollection,
3681 dwritetextlayout_SetFontFamilyName,
3682 dwritetextlayout_SetFontWeight,
3683 dwritetextlayout_SetFontStyle,
3684 dwritetextlayout_SetFontStretch,
3685 dwritetextlayout_SetFontSize,
3686 dwritetextlayout_SetUnderline,
3687 dwritetextlayout_SetStrikethrough,
3688 dwritetextlayout_SetDrawingEffect,
3689 dwritetextlayout_SetInlineObject,
3690 dwritetextlayout_SetTypography,
3691 dwritetextlayout_SetLocaleName,
3692 dwritetextlayout_GetMaxWidth,
3693 dwritetextlayout_GetMaxHeight,
3694 dwritetextlayout_layout_GetFontCollection,
3695 dwritetextlayout_layout_GetFontFamilyNameLength,
3696 dwritetextlayout_layout_GetFontFamilyName,
3697 dwritetextlayout_layout_GetFontWeight,
3698 dwritetextlayout_layout_GetFontStyle,
3699 dwritetextlayout_layout_GetFontStretch,
3700 dwritetextlayout_layout_GetFontSize,
3701 dwritetextlayout_GetUnderline,
3702 dwritetextlayout_GetStrikethrough,
3703 dwritetextlayout_GetDrawingEffect,
3704 dwritetextlayout_GetInlineObject,
3705 dwritetextlayout_GetTypography,
3706 dwritetextlayout_layout_GetLocaleNameLength,
3707 dwritetextlayout_layout_GetLocaleName,
3708 dwritetextlayout_Draw,
3709 dwritetextlayout_GetLineMetrics,
3710 dwritetextlayout_GetMetrics,
3711 dwritetextlayout_GetOverhangMetrics,
3712 dwritetextlayout_GetClusterMetrics,
3713 dwritetextlayout_DetermineMinWidth,
3714 dwritetextlayout_HitTestPoint,
3715 dwritetextlayout_HitTestTextPosition,
3716 dwritetextlayout_HitTestTextRange,
3717 dwritetextlayout1_SetPairKerning,
3718 dwritetextlayout1_GetPairKerning,
3719 dwritetextlayout1_SetCharacterSpacing,
3720 dwritetextlayout1_GetCharacterSpacing,
3721 dwritetextlayout2_GetMetrics,
3722 dwritetextlayout2_SetVerticalGlyphOrientation,
3723 dwritetextlayout2_GetVerticalGlyphOrientation,
3724 dwritetextlayout2_SetLastLineWrapping,
3725 dwritetextlayout2_GetLastLineWrapping,
3726 dwritetextlayout2_SetOpticalAlignment,
3727 dwritetextlayout2_GetOpticalAlignment,
3728 dwritetextlayout2_SetFontFallback,
3729 dwritetextlayout2_GetFontFallback,
3730 dwritetextlayout3_InvalidateLayout,
3731 dwritetextlayout3_SetLineSpacing,
3732 dwritetextlayout3_GetLineSpacing,
3733 dwritetextlayout3_GetLineMetrics
3736 static HRESULT WINAPI dwritetextformat_layout_QueryInterface(IDWriteTextFormat1 *iface, REFIID riid, void **obj)
3738 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3739 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3740 return IDWriteTextLayout3_QueryInterface(&This->IDWriteTextLayout3_iface, riid, obj);
3743 static ULONG WINAPI dwritetextformat_layout_AddRef(IDWriteTextFormat1 *iface)
3745 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3746 return IDWriteTextLayout3_AddRef(&This->IDWriteTextLayout3_iface);
3749 static ULONG WINAPI dwritetextformat_layout_Release(IDWriteTextFormat1 *iface)
3751 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3752 return IDWriteTextLayout3_Release(&This->IDWriteTextLayout3_iface);
3755 static HRESULT WINAPI dwritetextformat_layout_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
3757 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3758 BOOL changed;
3759 HRESULT hr;
3761 TRACE("(%p)->(%d)\n", This, alignment);
3763 hr = format_set_textalignment(&This->format, alignment, &changed);
3764 if (FAILED(hr))
3765 return hr;
3767 /* if layout is not ready there's nothing to align */
3768 if (changed && !(This->recompute & RECOMPUTE_EFFECTIVE_RUNS))
3769 layout_apply_text_alignment(This);
3771 return S_OK;
3774 static HRESULT WINAPI dwritetextformat_layout_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
3776 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3777 BOOL changed;
3778 HRESULT hr;
3780 TRACE("(%p)->(%d)\n", This, alignment);
3782 hr = format_set_paralignment(&This->format, alignment, &changed);
3783 if (FAILED(hr))
3784 return hr;
3786 /* if layout is not ready there's nothing to align */
3787 if (changed && !(This->recompute & RECOMPUTE_EFFECTIVE_RUNS))
3788 layout_apply_par_alignment(This);
3790 return S_OK;
3793 static HRESULT WINAPI dwritetextformat_layout_SetWordWrapping(IDWriteTextFormat1 *iface, DWRITE_WORD_WRAPPING wrapping)
3795 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3796 BOOL changed;
3797 HRESULT hr;
3799 TRACE("(%p)->(%d)\n", This, wrapping);
3801 hr = format_set_wordwrapping(&This->format, wrapping, &changed);
3802 if (FAILED(hr))
3803 return hr;
3805 if (changed)
3806 This->recompute |= RECOMPUTE_EFFECTIVE_RUNS;
3808 return S_OK;
3811 static HRESULT WINAPI dwritetextformat_layout_SetReadingDirection(IDWriteTextFormat1 *iface, DWRITE_READING_DIRECTION direction)
3813 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3814 BOOL changed;
3815 HRESULT hr;
3817 TRACE("(%p)->(%d)\n", This, direction);
3819 hr = format_set_readingdirection(&This->format, direction, &changed);
3820 if (FAILED(hr))
3821 return hr;
3823 if (changed)
3824 This->recompute = RECOMPUTE_EVERYTHING;
3826 return S_OK;
3829 static HRESULT WINAPI dwritetextformat_layout_SetFlowDirection(IDWriteTextFormat1 *iface, DWRITE_FLOW_DIRECTION direction)
3831 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3832 BOOL changed;
3833 HRESULT hr;
3835 TRACE("(%p)->(%d)\n", This, direction);
3837 hr = format_set_flowdirection(&This->format, direction, &changed);
3838 if (FAILED(hr))
3839 return hr;
3841 if (changed)
3842 This->recompute = RECOMPUTE_EVERYTHING;
3844 return S_OK;
3847 static HRESULT WINAPI dwritetextformat_layout_SetIncrementalTabStop(IDWriteTextFormat1 *iface, FLOAT tabstop)
3849 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3850 FIXME("(%p)->(%f): stub\n", This, tabstop);
3851 return E_NOTIMPL;
3854 static HRESULT WINAPI dwritetextformat_layout_SetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING const *trimming,
3855 IDWriteInlineObject *trimming_sign)
3857 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3858 FIXME("(%p)->(%p %p): stub\n", This, trimming, trimming_sign);
3859 return E_NOTIMPL;
3862 static HRESULT WINAPI dwritetextformat_layout_SetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD method,
3863 FLOAT spacing, FLOAT baseline)
3865 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3866 BOOL changed;
3867 HRESULT hr;
3869 TRACE("(%p)->(%d %f %f)\n", This, method, spacing, baseline);
3871 hr = format_set_linespacing(&This->format, method, spacing, baseline, &changed);
3872 if (FAILED(hr))
3873 return hr;
3875 if (changed)
3876 This->recompute = RECOMPUTE_EVERYTHING;
3878 return S_OK;
3881 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_layout_GetTextAlignment(IDWriteTextFormat1 *iface)
3883 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3884 TRACE("(%p)\n", This);
3885 return This->format.textalignment;
3888 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_layout_GetParagraphAlignment(IDWriteTextFormat1 *iface)
3890 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3891 TRACE("(%p)\n", This);
3892 return This->format.paralign;
3895 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_layout_GetWordWrapping(IDWriteTextFormat1 *iface)
3897 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3898 TRACE("(%p)\n", This);
3899 return This->format.wrapping;
3902 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_layout_GetReadingDirection(IDWriteTextFormat1 *iface)
3904 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3905 TRACE("(%p)\n", This);
3906 return This->format.readingdir;
3909 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_layout_GetFlowDirection(IDWriteTextFormat1 *iface)
3911 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3912 TRACE("(%p)\n", This);
3913 return This->format.flow;
3916 static FLOAT WINAPI dwritetextformat_layout_GetIncrementalTabStop(IDWriteTextFormat1 *iface)
3918 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3919 FIXME("(%p): stub\n", This);
3920 return 0.0f;
3923 static HRESULT WINAPI dwritetextformat_layout_GetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING *options,
3924 IDWriteInlineObject **trimming_sign)
3926 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3928 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
3930 *options = This->format.trimming;
3931 *trimming_sign = This->format.trimmingsign;
3932 if (*trimming_sign)
3933 IDWriteInlineObject_AddRef(*trimming_sign);
3934 return S_OK;
3937 static HRESULT WINAPI dwritetextformat_layout_GetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD *method,
3938 FLOAT *spacing, FLOAT *baseline)
3940 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3942 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
3944 *method = This->format.spacingmethod;
3945 *spacing = This->format.spacing;
3946 *baseline = This->format.baseline;
3947 return S_OK;
3950 static HRESULT WINAPI dwritetextformat_layout_GetFontCollection(IDWriteTextFormat1 *iface, IDWriteFontCollection **collection)
3952 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3954 TRACE("(%p)->(%p)\n", This, collection);
3956 *collection = This->format.collection;
3957 if (*collection)
3958 IDWriteFontCollection_AddRef(*collection);
3959 return S_OK;
3962 static UINT32 WINAPI dwritetextformat_layout_GetFontFamilyNameLength(IDWriteTextFormat1 *iface)
3964 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3965 TRACE("(%p)\n", This);
3966 return This->format.family_len;
3969 static HRESULT WINAPI dwritetextformat_layout_GetFontFamilyName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
3971 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3973 TRACE("(%p)->(%p %u)\n", This, name, size);
3975 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
3976 strcpyW(name, This->format.family_name);
3977 return S_OK;
3980 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_layout_GetFontWeight(IDWriteTextFormat1 *iface)
3982 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3983 TRACE("(%p)\n", This);
3984 return This->format.weight;
3987 static DWRITE_FONT_STYLE WINAPI dwritetextformat_layout_GetFontStyle(IDWriteTextFormat1 *iface)
3989 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3990 TRACE("(%p)\n", This);
3991 return This->format.style;
3994 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_layout_GetFontStretch(IDWriteTextFormat1 *iface)
3996 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3997 TRACE("(%p)\n", This);
3998 return This->format.stretch;
4001 static FLOAT WINAPI dwritetextformat_layout_GetFontSize(IDWriteTextFormat1 *iface)
4003 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4004 TRACE("(%p)\n", This);
4005 return This->format.fontsize;
4008 static UINT32 WINAPI dwritetextformat_layout_GetLocaleNameLength(IDWriteTextFormat1 *iface)
4010 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4011 TRACE("(%p)\n", This);
4012 return This->format.locale_len;
4015 static HRESULT WINAPI dwritetextformat_layout_GetLocaleName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
4017 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4019 TRACE("(%p)->(%p %u)\n", This, name, size);
4021 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
4022 strcpyW(name, This->format.locale);
4023 return S_OK;
4026 static HRESULT WINAPI dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat1 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4028 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4029 FIXME("(%p)->(%d): stub\n", This, orientation);
4030 return E_NOTIMPL;
4033 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat1 *iface)
4035 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4036 FIXME("(%p): stub\n", This);
4037 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
4040 static HRESULT WINAPI dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat1 *iface, BOOL lastline_wrapping_enabled)
4042 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4044 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
4046 This->format.last_line_wrapping = !!lastline_wrapping_enabled;
4047 return S_OK;
4050 static BOOL WINAPI dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat1 *iface)
4052 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4053 TRACE("(%p)\n", This);
4054 return This->format.last_line_wrapping;
4057 static HRESULT WINAPI dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat1 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
4059 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4060 TRACE("(%p)->(%d)\n", This, alignment);
4061 return format_set_optical_alignment(&This->format, alignment);
4064 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat1 *iface)
4066 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4067 TRACE("(%p)\n", This);
4068 return This->format.optical_alignment;
4071 static HRESULT WINAPI dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback *fallback)
4073 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4074 TRACE("(%p)->(%p)\n", This, fallback);
4075 return IDWriteTextLayout3_SetFontFallback(&This->IDWriteTextLayout3_iface, fallback);
4078 static HRESULT WINAPI dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback **fallback)
4080 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4081 TRACE("(%p)->(%p)\n", This, fallback);
4082 return IDWriteTextLayout3_GetFontFallback(&This->IDWriteTextLayout3_iface, fallback);
4085 static const IDWriteTextFormat1Vtbl dwritetextformat1_layout_vtbl = {
4086 dwritetextformat_layout_QueryInterface,
4087 dwritetextformat_layout_AddRef,
4088 dwritetextformat_layout_Release,
4089 dwritetextformat_layout_SetTextAlignment,
4090 dwritetextformat_layout_SetParagraphAlignment,
4091 dwritetextformat_layout_SetWordWrapping,
4092 dwritetextformat_layout_SetReadingDirection,
4093 dwritetextformat_layout_SetFlowDirection,
4094 dwritetextformat_layout_SetIncrementalTabStop,
4095 dwritetextformat_layout_SetTrimming,
4096 dwritetextformat_layout_SetLineSpacing,
4097 dwritetextformat_layout_GetTextAlignment,
4098 dwritetextformat_layout_GetParagraphAlignment,
4099 dwritetextformat_layout_GetWordWrapping,
4100 dwritetextformat_layout_GetReadingDirection,
4101 dwritetextformat_layout_GetFlowDirection,
4102 dwritetextformat_layout_GetIncrementalTabStop,
4103 dwritetextformat_layout_GetTrimming,
4104 dwritetextformat_layout_GetLineSpacing,
4105 dwritetextformat_layout_GetFontCollection,
4106 dwritetextformat_layout_GetFontFamilyNameLength,
4107 dwritetextformat_layout_GetFontFamilyName,
4108 dwritetextformat_layout_GetFontWeight,
4109 dwritetextformat_layout_GetFontStyle,
4110 dwritetextformat_layout_GetFontStretch,
4111 dwritetextformat_layout_GetFontSize,
4112 dwritetextformat_layout_GetLocaleNameLength,
4113 dwritetextformat_layout_GetLocaleName,
4114 dwritetextformat1_layout_SetVerticalGlyphOrientation,
4115 dwritetextformat1_layout_GetVerticalGlyphOrientation,
4116 dwritetextformat1_layout_SetLastLineWrapping,
4117 dwritetextformat1_layout_GetLastLineWrapping,
4118 dwritetextformat1_layout_SetOpticalAlignment,
4119 dwritetextformat1_layout_GetOpticalAlignment,
4120 dwritetextformat1_layout_SetFontFallback,
4121 dwritetextformat1_layout_GetFontFallback,
4124 static HRESULT WINAPI dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink1 *iface,
4125 REFIID riid, void **obj)
4127 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink1) ||
4128 IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) ||
4129 IsEqualIID(riid, &IID_IUnknown))
4131 *obj = iface;
4132 IDWriteTextAnalysisSink1_AddRef(iface);
4133 return S_OK;
4136 *obj = NULL;
4137 return E_NOINTERFACE;
4140 static ULONG WINAPI dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink1 *iface)
4142 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4143 return IDWriteTextLayout3_AddRef(&layout->IDWriteTextLayout3_iface);
4146 static ULONG WINAPI dwritetextlayout_sink_Release(IDWriteTextAnalysisSink1 *iface)
4148 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4149 return IDWriteTextLayout3_Release(&layout->IDWriteTextLayout3_iface);
4152 static HRESULT WINAPI dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink1 *iface,
4153 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
4155 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4156 struct layout_run *run;
4158 TRACE("[%u,%u) script=%u:%s\n", position, position + length, sa->script, debugstr_sa_script(sa->script));
4160 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
4161 if (!run)
4162 return E_OUTOFMEMORY;
4164 run->u.regular.descr.string = &layout->str[position];
4165 run->u.regular.descr.stringLength = length;
4166 run->u.regular.descr.textPosition = position;
4167 run->u.regular.sa = *sa;
4168 list_add_tail(&layout->runs, &run->entry);
4169 return S_OK;
4172 static HRESULT WINAPI dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink1 *iface,
4173 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
4175 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4177 if (position + length > layout->len)
4178 return E_FAIL;
4180 memcpy(&layout->nominal_breakpoints[position], breakpoints, length*sizeof(DWRITE_LINE_BREAKPOINT));
4181 return S_OK;
4184 static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink1 *iface, UINT32 position,
4185 UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
4187 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4188 struct layout_run *cur_run;
4190 TRACE("[%u,%u) %u %u\n", position, position + length, explicitLevel, resolvedLevel);
4192 LIST_FOR_EACH_ENTRY(cur_run, &layout->runs, struct layout_run, entry) {
4193 struct regular_layout_run *cur = &cur_run->u.regular;
4194 struct layout_run *run;
4196 if (cur_run->kind == LAYOUT_RUN_INLINE)
4197 continue;
4199 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
4200 if (position < cur->descr.textPosition || position >= cur->descr.textPosition + cur->descr.stringLength)
4201 continue;
4203 /* full hit - just set run level */
4204 if (cur->descr.textPosition == position && cur->descr.stringLength == length) {
4205 cur->run.bidiLevel = resolvedLevel;
4206 break;
4209 /* current run is fully covered, move to next one */
4210 if (cur->descr.textPosition == position && cur->descr.stringLength < length) {
4211 cur->run.bidiLevel = resolvedLevel;
4212 position += cur->descr.stringLength;
4213 length -= cur->descr.stringLength;
4214 continue;
4217 /* all fully covered runs are processed at this point, reuse existing run for remaining
4218 reported bidi range and add another run for the rest of original one */
4220 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
4221 if (!run)
4222 return E_OUTOFMEMORY;
4224 *run = *cur_run;
4225 run->u.regular.descr.textPosition = position + length;
4226 run->u.regular.descr.stringLength = cur->descr.stringLength - length;
4227 run->u.regular.descr.string = &layout->str[position + length];
4229 /* reduce existing run */
4230 cur->run.bidiLevel = resolvedLevel;
4231 cur->descr.stringLength = length;
4233 list_add_after(&cur_run->entry, &run->entry);
4234 break;
4237 return S_OK;
4240 static HRESULT WINAPI dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink1 *iface,
4241 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
4243 return E_NOTIMPL;
4246 static HRESULT WINAPI dwritetextlayout_sink_SetGlyphOrientation(IDWriteTextAnalysisSink1 *iface,
4247 UINT32 position, UINT32 length, DWRITE_GLYPH_ORIENTATION_ANGLE angle, UINT8 adjusted_bidi_level,
4248 BOOL is_sideways, BOOL is_rtl)
4250 return E_NOTIMPL;
4253 static const IDWriteTextAnalysisSink1Vtbl dwritetextlayoutsinkvtbl = {
4254 dwritetextlayout_sink_QueryInterface,
4255 dwritetextlayout_sink_AddRef,
4256 dwritetextlayout_sink_Release,
4257 dwritetextlayout_sink_SetScriptAnalysis,
4258 dwritetextlayout_sink_SetLineBreakpoints,
4259 dwritetextlayout_sink_SetBidiLevel,
4260 dwritetextlayout_sink_SetNumberSubstitution,
4261 dwritetextlayout_sink_SetGlyphOrientation
4264 static HRESULT WINAPI dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource1 *iface,
4265 REFIID riid, void **obj)
4267 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource1) ||
4268 IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) ||
4269 IsEqualIID(riid, &IID_IUnknown))
4271 *obj = iface;
4272 IDWriteTextAnalysisSource1_AddRef(iface);
4273 return S_OK;
4276 *obj = NULL;
4277 return E_NOINTERFACE;
4280 static ULONG WINAPI dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource1 *iface)
4282 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4283 return IDWriteTextLayout3_AddRef(&layout->IDWriteTextLayout3_iface);
4286 static ULONG WINAPI dwritetextlayout_source_Release(IDWriteTextAnalysisSource1 *iface)
4288 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4289 return IDWriteTextLayout3_Release(&layout->IDWriteTextLayout3_iface);
4292 static HRESULT WINAPI dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource1 *iface,
4293 UINT32 position, WCHAR const** text, UINT32* text_len)
4295 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4297 TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
4299 if (position < layout->len) {
4300 *text = &layout->str[position];
4301 *text_len = layout->len - position;
4303 else {
4304 *text = NULL;
4305 *text_len = 0;
4308 return S_OK;
4311 static HRESULT WINAPI dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource1 *iface,
4312 UINT32 position, WCHAR const** text, UINT32* text_len)
4314 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4316 TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
4318 if (position > 0 && position < layout->len) {
4319 *text = layout->str;
4320 *text_len = position;
4322 else {
4323 *text = NULL;
4324 *text_len = 0;
4327 return S_OK;
4330 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource1 *iface)
4332 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4333 return IDWriteTextLayout3_GetReadingDirection(&layout->IDWriteTextLayout3_iface);
4336 static HRESULT WINAPI dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource1 *iface,
4337 UINT32 position, UINT32* text_len, WCHAR const** locale)
4339 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4340 struct layout_range *range = get_layout_range_by_pos(layout, position);
4342 if (position < layout->len) {
4343 struct layout_range *next;
4345 *locale = range->locale;
4346 *text_len = range->h.range.length - position;
4348 next = LIST_ENTRY(list_next(&layout->ranges, &range->h.entry), struct layout_range, h.entry);
4349 while (next && next->h.range.startPosition < layout->len && !strcmpW(range->locale, next->locale)) {
4350 *text_len += next->h.range.length;
4351 next = LIST_ENTRY(list_next(&layout->ranges, &next->h.entry), struct layout_range, h.entry);
4354 *text_len = min(*text_len, layout->len - position);
4356 else {
4357 *locale = NULL;
4358 *text_len = 0;
4361 return S_OK;
4364 static HRESULT WINAPI dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource1 *iface,
4365 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
4367 FIXME("%u %p %p: stub\n", position, text_len, substitution);
4368 return E_NOTIMPL;
4371 static HRESULT WINAPI dwritetextlayout_source_GetVerticalGlyphOrientation(IDWriteTextAnalysisSource1 *iface,
4372 UINT32 position, UINT32 *length, DWRITE_VERTICAL_GLYPH_ORIENTATION *orientation, UINT8 *bidi_level)
4374 FIXME("%u %p %p %p: stub\n", position, length, orientation, bidi_level);
4375 return E_NOTIMPL;
4378 static const IDWriteTextAnalysisSource1Vtbl dwritetextlayoutsourcevtbl = {
4379 dwritetextlayout_source_QueryInterface,
4380 dwritetextlayout_source_AddRef,
4381 dwritetextlayout_source_Release,
4382 dwritetextlayout_source_GetTextAtPosition,
4383 dwritetextlayout_source_GetTextBeforePosition,
4384 dwritetextlayout_source_GetParagraphReadingDirection,
4385 dwritetextlayout_source_GetLocaleName,
4386 dwritetextlayout_source_GetNumberSubstitution,
4387 dwritetextlayout_source_GetVerticalGlyphOrientation
4390 static HRESULT layout_format_from_textformat(struct dwrite_textlayout *layout, IDWriteTextFormat *format)
4392 struct dwrite_textformat *textformat;
4393 IDWriteTextFormat1 *format1;
4394 UINT32 len;
4395 HRESULT hr;
4397 if ((textformat = unsafe_impl_from_IDWriteTextFormat(format))) {
4398 layout->format = textformat->format;
4400 layout->format.locale = heap_strdupW(textformat->format.locale);
4401 layout->format.family_name = heap_strdupW(textformat->format.family_name);
4402 if (!layout->format.locale || !layout->format.family_name)
4404 heap_free(layout->format.locale);
4405 heap_free(layout->format.family_name);
4406 return E_OUTOFMEMORY;
4409 if (layout->format.trimmingsign)
4410 IDWriteInlineObject_AddRef(layout->format.trimmingsign);
4411 if (layout->format.collection)
4412 IDWriteFontCollection_AddRef(layout->format.collection);
4413 if (layout->format.fallback)
4414 IDWriteFontFallback_AddRef(layout->format.fallback);
4416 return S_OK;
4419 layout->format.weight = IDWriteTextFormat_GetFontWeight(format);
4420 layout->format.style = IDWriteTextFormat_GetFontStyle(format);
4421 layout->format.stretch = IDWriteTextFormat_GetFontStretch(format);
4422 layout->format.fontsize= IDWriteTextFormat_GetFontSize(format);
4423 layout->format.textalignment = IDWriteTextFormat_GetTextAlignment(format);
4424 layout->format.paralign = IDWriteTextFormat_GetParagraphAlignment(format);
4425 layout->format.wrapping = IDWriteTextFormat_GetWordWrapping(format);
4426 layout->format.readingdir = IDWriteTextFormat_GetReadingDirection(format);
4427 layout->format.flow = IDWriteTextFormat_GetFlowDirection(format);
4428 layout->format.fallback = NULL;
4429 hr = IDWriteTextFormat_GetLineSpacing(format, &layout->format.spacingmethod,
4430 &layout->format.spacing, &layout->format.baseline);
4431 if (FAILED(hr))
4432 return hr;
4434 hr = IDWriteTextFormat_GetTrimming(format, &layout->format.trimming, &layout->format.trimmingsign);
4435 if (FAILED(hr))
4436 return hr;
4438 /* locale name and length */
4439 len = IDWriteTextFormat_GetLocaleNameLength(format);
4440 layout->format.locale = heap_alloc((len+1)*sizeof(WCHAR));
4441 if (!layout->format.locale)
4442 return E_OUTOFMEMORY;
4444 hr = IDWriteTextFormat_GetLocaleName(format, layout->format.locale, len+1);
4445 if (FAILED(hr))
4446 return hr;
4447 layout->format.locale_len = len;
4449 /* font family name and length */
4450 len = IDWriteTextFormat_GetFontFamilyNameLength(format);
4451 layout->format.family_name = heap_alloc((len+1)*sizeof(WCHAR));
4452 if (!layout->format.family_name)
4453 return E_OUTOFMEMORY;
4455 hr = IDWriteTextFormat_GetFontFamilyName(format, layout->format.family_name, len+1);
4456 if (FAILED(hr))
4457 return hr;
4458 layout->format.family_len = len;
4460 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
4461 if (hr == S_OK) {
4462 layout->format.vertical_orientation = IDWriteTextFormat1_GetVerticalGlyphOrientation(format1);
4463 layout->format.optical_alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
4464 IDWriteTextFormat1_GetFontFallback(format1, &layout->format.fallback);
4465 IDWriteTextFormat1_Release(format1);
4467 else {
4468 layout->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
4469 layout->format.optical_alignment = DWRITE_OPTICAL_ALIGNMENT_NONE;
4472 return IDWriteTextFormat_GetFontCollection(format, &layout->format.collection);
4475 static HRESULT init_textlayout(const struct textlayout_desc *desc, struct dwrite_textlayout *layout)
4477 struct layout_range_header *range, *strike, *underline, *effect, *spacing, *typography;
4478 static const DWRITE_TEXT_RANGE r = { 0, ~0u };
4479 HRESULT hr;
4481 layout->IDWriteTextLayout3_iface.lpVtbl = &dwritetextlayoutvtbl;
4482 layout->IDWriteTextFormat1_iface.lpVtbl = &dwritetextformat1_layout_vtbl;
4483 layout->IDWriteTextAnalysisSink1_iface.lpVtbl = &dwritetextlayoutsinkvtbl;
4484 layout->IDWriteTextAnalysisSource1_iface.lpVtbl = &dwritetextlayoutsourcevtbl;
4485 layout->ref = 1;
4486 layout->len = desc->length;
4487 layout->recompute = RECOMPUTE_EVERYTHING;
4488 layout->nominal_breakpoints = NULL;
4489 layout->actual_breakpoints = NULL;
4490 layout->cluster_count = 0;
4491 layout->clustermetrics = NULL;
4492 layout->clusters = NULL;
4493 layout->lines = NULL;
4494 layout->line_alloc = 0;
4495 layout->minwidth = 0.0f;
4496 list_init(&layout->eruns);
4497 list_init(&layout->inlineobjects);
4498 list_init(&layout->underlines);
4499 list_init(&layout->strikethrough);
4500 list_init(&layout->runs);
4501 list_init(&layout->ranges);
4502 list_init(&layout->strike_ranges);
4503 list_init(&layout->underline_ranges);
4504 list_init(&layout->effects);
4505 list_init(&layout->spacing);
4506 list_init(&layout->typographies);
4507 memset(&layout->format, 0, sizeof(layout->format));
4508 memset(&layout->metrics, 0, sizeof(layout->metrics));
4509 layout->metrics.layoutWidth = desc->max_width;
4510 layout->metrics.layoutHeight = desc->max_height;
4511 layout->measuringmode = DWRITE_MEASURING_MODE_NATURAL;
4513 layout->ppdip = 0.0f;
4514 memset(&layout->transform, 0, sizeof(layout->transform));
4516 layout->str = heap_strdupnW(desc->string, desc->length);
4517 if (desc->length && !layout->str) {
4518 hr = E_OUTOFMEMORY;
4519 goto fail;
4522 hr = layout_format_from_textformat(layout, desc->format);
4523 if (FAILED(hr))
4524 goto fail;
4526 range = alloc_layout_range(layout, &r, LAYOUT_RANGE_REGULAR);
4527 strike = alloc_layout_range(layout, &r, LAYOUT_RANGE_STRIKETHROUGH);
4528 underline = alloc_layout_range(layout, &r, LAYOUT_RANGE_UNDERLINE);
4529 effect = alloc_layout_range(layout, &r, LAYOUT_RANGE_EFFECT);
4530 spacing = alloc_layout_range(layout, &r, LAYOUT_RANGE_SPACING);
4531 typography = alloc_layout_range(layout, &r, LAYOUT_RANGE_TYPOGRAPHY);
4532 if (!range || !strike || !effect || !spacing || !typography || !underline) {
4533 free_layout_range(range);
4534 free_layout_range(strike);
4535 free_layout_range(underline);
4536 free_layout_range(effect);
4537 free_layout_range(spacing);
4538 free_layout_range(typography);
4539 hr = E_OUTOFMEMORY;
4540 goto fail;
4543 if (desc->is_gdi_compatible)
4544 layout->measuringmode = desc->use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
4545 else
4546 layout->measuringmode = DWRITE_MEASURING_MODE_NATURAL;
4547 layout->ppdip = desc->ppdip;
4548 layout->transform = desc->transform ? *desc->transform : identity;
4550 layout->factory = desc->factory;
4551 IDWriteFactory3_AddRef(layout->factory);
4552 list_add_head(&layout->ranges, &range->entry);
4553 list_add_head(&layout->strike_ranges, &strike->entry);
4554 list_add_head(&layout->underline_ranges, &underline->entry);
4555 list_add_head(&layout->effects, &effect->entry);
4556 list_add_head(&layout->spacing, &spacing->entry);
4557 list_add_head(&layout->typographies, &typography->entry);
4558 return S_OK;
4560 fail:
4561 IDWriteTextLayout3_Release(&layout->IDWriteTextLayout3_iface);
4562 return hr;
4565 HRESULT create_textlayout(const struct textlayout_desc *desc, IDWriteTextLayout **ret)
4567 struct dwrite_textlayout *layout;
4568 HRESULT hr;
4570 *ret = NULL;
4572 if (!desc->format || !desc->string)
4573 return E_INVALIDARG;
4575 layout = heap_alloc(sizeof(struct dwrite_textlayout));
4576 if (!layout) return E_OUTOFMEMORY;
4578 hr = init_textlayout(desc, layout);
4579 if (hr == S_OK)
4580 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout3_iface;
4582 return hr;
4585 static HRESULT WINAPI dwritetrimmingsign_QueryInterface(IDWriteInlineObject *iface, REFIID riid, void **obj)
4587 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4589 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4591 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteInlineObject)) {
4592 *obj = iface;
4593 IDWriteInlineObject_AddRef(iface);
4594 return S_OK;
4597 *obj = NULL;
4598 return E_NOINTERFACE;
4601 static ULONG WINAPI dwritetrimmingsign_AddRef(IDWriteInlineObject *iface)
4603 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4604 ULONG ref = InterlockedIncrement(&This->ref);
4605 TRACE("(%p)->(%d)\n", This, ref);
4606 return ref;
4609 static ULONG WINAPI dwritetrimmingsign_Release(IDWriteInlineObject *iface)
4611 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4612 ULONG ref = InterlockedDecrement(&This->ref);
4614 TRACE("(%p)->(%d)\n", This, ref);
4616 if (!ref) {
4617 IDWriteTextLayout_Release(This->layout);
4618 heap_free(This);
4621 return ref;
4624 static HRESULT WINAPI dwritetrimmingsign_Draw(IDWriteInlineObject *iface, void *context, IDWriteTextRenderer *renderer,
4625 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *effect)
4627 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4628 DWRITE_TEXT_RANGE range = { 0, ~0u };
4629 HRESULT hr;
4631 TRACE("(%p)->(%p %p %.2f %.2f %d %d %p)\n", This, context, renderer, originX, originY, is_sideways, is_rtl, effect);
4633 IDWriteTextLayout_SetDrawingEffect(This->layout, effect, range);
4634 hr = IDWriteTextLayout_Draw(This->layout, context, renderer, originX, originY);
4635 IDWriteTextLayout_SetDrawingEffect(This->layout, NULL, range);
4636 return hr;
4639 static HRESULT WINAPI dwritetrimmingsign_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *ret)
4641 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4642 DWRITE_TEXT_METRICS metrics;
4643 HRESULT hr;
4645 TRACE("(%p)->(%p)\n", This, ret);
4647 hr = IDWriteTextLayout_GetMetrics(This->layout, &metrics);
4648 if (FAILED(hr)) {
4649 memset(ret, 0, sizeof(*ret));
4650 return hr;
4653 ret->width = metrics.width;
4654 ret->height = 0.0f;
4655 ret->baseline = 0.0f;
4656 ret->supportsSideways = FALSE;
4657 return S_OK;
4660 static HRESULT WINAPI dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
4662 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4663 FIXME("(%p)->(%p): stub\n", This, overhangs);
4664 return E_NOTIMPL;
4667 static HRESULT WINAPI dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
4668 DWRITE_BREAK_CONDITION *after)
4670 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4672 TRACE("(%p)->(%p %p)\n", This, before, after);
4674 *before = *after = DWRITE_BREAK_CONDITION_NEUTRAL;
4675 return S_OK;
4678 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl = {
4679 dwritetrimmingsign_QueryInterface,
4680 dwritetrimmingsign_AddRef,
4681 dwritetrimmingsign_Release,
4682 dwritetrimmingsign_Draw,
4683 dwritetrimmingsign_GetMetrics,
4684 dwritetrimmingsign_GetOverhangMetrics,
4685 dwritetrimmingsign_GetBreakConditions
4688 static inline BOOL is_reading_direction_horz(DWRITE_READING_DIRECTION direction)
4690 return (direction == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT) ||
4691 (direction == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
4694 static inline BOOL is_reading_direction_vert(DWRITE_READING_DIRECTION direction)
4696 return (direction == DWRITE_READING_DIRECTION_TOP_TO_BOTTOM) ||
4697 (direction == DWRITE_READING_DIRECTION_BOTTOM_TO_TOP);
4700 static inline BOOL is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction)
4702 return (direction == DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT) ||
4703 (direction == DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT);
4706 static inline BOOL is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction)
4708 return (direction == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM) ||
4709 (direction == DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP);
4712 HRESULT create_trimmingsign(IDWriteFactory3 *factory, IDWriteTextFormat *format, IDWriteInlineObject **sign)
4714 static const WCHAR ellipsisW = 0x2026;
4715 struct dwrite_trimmingsign *This;
4716 DWRITE_READING_DIRECTION reading;
4717 DWRITE_FLOW_DIRECTION flow;
4718 HRESULT hr;
4720 *sign = NULL;
4722 /* Validate reading/flow direction here, layout creation won't complain about
4723 invalid combinations. */
4724 reading = IDWriteTextFormat_GetReadingDirection(format);
4725 flow = IDWriteTextFormat_GetFlowDirection(format);
4727 if ((is_reading_direction_horz(reading) && is_flow_direction_horz(flow)) ||
4728 (is_reading_direction_vert(reading) && is_flow_direction_vert(flow)))
4729 return DWRITE_E_FLOWDIRECTIONCONFLICTS;
4731 This = heap_alloc(sizeof(*This));
4732 if (!This)
4733 return E_OUTOFMEMORY;
4735 This->IDWriteInlineObject_iface.lpVtbl = &dwritetrimmingsignvtbl;
4736 This->ref = 1;
4738 hr = IDWriteFactory3_CreateTextLayout(factory, &ellipsisW, 1, format, 0.0f, 0.0f, &This->layout);
4739 if (FAILED(hr)) {
4740 heap_free(This);
4741 return hr;
4744 IDWriteTextLayout_SetWordWrapping(This->layout, DWRITE_WORD_WRAPPING_NO_WRAP);
4745 *sign = &This->IDWriteInlineObject_iface;
4747 return S_OK;
4750 static HRESULT WINAPI dwritetextformat_QueryInterface(IDWriteTextFormat2 *iface, REFIID riid, void **obj)
4752 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4754 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4756 if (IsEqualIID(riid, &IID_IDWriteTextFormat2) ||
4757 IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
4758 IsEqualIID(riid, &IID_IDWriteTextFormat) ||
4759 IsEqualIID(riid, &IID_IUnknown))
4761 *obj = iface;
4762 IDWriteTextFormat2_AddRef(iface);
4763 return S_OK;
4766 *obj = NULL;
4768 return E_NOINTERFACE;
4771 static ULONG WINAPI dwritetextformat_AddRef(IDWriteTextFormat2 *iface)
4773 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4774 ULONG ref = InterlockedIncrement(&This->ref);
4775 TRACE("(%p)->(%d)\n", This, ref);
4776 return ref;
4779 static ULONG WINAPI dwritetextformat_Release(IDWriteTextFormat2 *iface)
4781 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4782 ULONG ref = InterlockedDecrement(&This->ref);
4784 TRACE("(%p)->(%d)\n", This, ref);
4786 if (!ref)
4788 release_format_data(&This->format);
4789 heap_free(This);
4792 return ref;
4795 static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat2 *iface, DWRITE_TEXT_ALIGNMENT alignment)
4797 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4798 TRACE("(%p)->(%d)\n", This, alignment);
4799 return format_set_textalignment(&This->format, alignment, NULL);
4802 static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat2 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
4804 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4805 TRACE("(%p)->(%d)\n", This, alignment);
4806 return format_set_paralignment(&This->format, alignment, NULL);
4809 static HRESULT WINAPI dwritetextformat_SetWordWrapping(IDWriteTextFormat2 *iface, DWRITE_WORD_WRAPPING wrapping)
4811 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4812 TRACE("(%p)->(%d)\n", This, wrapping);
4813 return format_set_wordwrapping(&This->format, wrapping, NULL);
4816 static HRESULT WINAPI dwritetextformat_SetReadingDirection(IDWriteTextFormat2 *iface, DWRITE_READING_DIRECTION direction)
4818 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4819 TRACE("(%p)->(%d)\n", This, direction);
4820 return format_set_readingdirection(&This->format, direction, NULL);
4823 static HRESULT WINAPI dwritetextformat_SetFlowDirection(IDWriteTextFormat2 *iface, DWRITE_FLOW_DIRECTION direction)
4825 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4826 TRACE("(%p)->(%d)\n", This, direction);
4827 return format_set_flowdirection(&This->format, direction, NULL);
4830 static HRESULT WINAPI dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat2 *iface, FLOAT tabstop)
4832 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4833 FIXME("(%p)->(%f): stub\n", This, tabstop);
4834 return E_NOTIMPL;
4837 static HRESULT WINAPI dwritetextformat_SetTrimming(IDWriteTextFormat2 *iface, DWRITE_TRIMMING const *trimming,
4838 IDWriteInlineObject *trimming_sign)
4840 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4841 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
4843 This->format.trimming = *trimming;
4844 if (This->format.trimmingsign)
4845 IDWriteInlineObject_Release(This->format.trimmingsign);
4846 This->format.trimmingsign = trimming_sign;
4847 if (This->format.trimmingsign)
4848 IDWriteInlineObject_AddRef(This->format.trimmingsign);
4849 return S_OK;
4852 static HRESULT WINAPI dwritetextformat_SetLineSpacing(IDWriteTextFormat2 *iface, DWRITE_LINE_SPACING_METHOD method,
4853 FLOAT spacing, FLOAT baseline)
4855 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4856 TRACE("(%p)->(%d %f %f)\n", This, method, spacing, baseline);
4857 return format_set_linespacing(&This->format, method, spacing, baseline, NULL);
4860 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_GetTextAlignment(IDWriteTextFormat2 *iface)
4862 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4863 TRACE("(%p)\n", This);
4864 return This->format.textalignment;
4867 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_GetParagraphAlignment(IDWriteTextFormat2 *iface)
4869 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4870 TRACE("(%p)\n", This);
4871 return This->format.paralign;
4874 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_GetWordWrapping(IDWriteTextFormat2 *iface)
4876 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4877 TRACE("(%p)\n", This);
4878 return This->format.wrapping;
4881 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_GetReadingDirection(IDWriteTextFormat2 *iface)
4883 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4884 TRACE("(%p)\n", This);
4885 return This->format.readingdir;
4888 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_GetFlowDirection(IDWriteTextFormat2 *iface)
4890 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4891 TRACE("(%p)\n", This);
4892 return This->format.flow;
4895 static FLOAT WINAPI dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat2 *iface)
4897 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4898 FIXME("(%p): stub\n", This);
4899 return 0.0f;
4902 static HRESULT WINAPI dwritetextformat_GetTrimming(IDWriteTextFormat2 *iface, DWRITE_TRIMMING *options,
4903 IDWriteInlineObject **trimming_sign)
4905 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4906 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
4908 *options = This->format.trimming;
4909 if ((*trimming_sign = This->format.trimmingsign))
4910 IDWriteInlineObject_AddRef(*trimming_sign);
4912 return S_OK;
4915 static HRESULT WINAPI dwritetextformat_GetLineSpacing(IDWriteTextFormat2 *iface, DWRITE_LINE_SPACING_METHOD *method,
4916 FLOAT *spacing, FLOAT *baseline)
4918 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4919 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
4921 *method = This->format.spacingmethod;
4922 *spacing = This->format.spacing;
4923 *baseline = This->format.baseline;
4924 return S_OK;
4927 static HRESULT WINAPI dwritetextformat_GetFontCollection(IDWriteTextFormat2 *iface, IDWriteFontCollection **collection)
4929 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4931 TRACE("(%p)->(%p)\n", This, collection);
4933 *collection = This->format.collection;
4934 IDWriteFontCollection_AddRef(*collection);
4936 return S_OK;
4939 static UINT32 WINAPI dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat2 *iface)
4941 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4942 TRACE("(%p)\n", This);
4943 return This->format.family_len;
4946 static HRESULT WINAPI dwritetextformat_GetFontFamilyName(IDWriteTextFormat2 *iface, WCHAR *name, UINT32 size)
4948 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4950 TRACE("(%p)->(%p %u)\n", This, name, size);
4952 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
4953 strcpyW(name, This->format.family_name);
4954 return S_OK;
4957 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_GetFontWeight(IDWriteTextFormat2 *iface)
4959 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4960 TRACE("(%p)\n", This);
4961 return This->format.weight;
4964 static DWRITE_FONT_STYLE WINAPI dwritetextformat_GetFontStyle(IDWriteTextFormat2 *iface)
4966 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4967 TRACE("(%p)\n", This);
4968 return This->format.style;
4971 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_GetFontStretch(IDWriteTextFormat2 *iface)
4973 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4974 TRACE("(%p)\n", This);
4975 return This->format.stretch;
4978 static FLOAT WINAPI dwritetextformat_GetFontSize(IDWriteTextFormat2 *iface)
4980 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4981 TRACE("(%p)\n", This);
4982 return This->format.fontsize;
4985 static UINT32 WINAPI dwritetextformat_GetLocaleNameLength(IDWriteTextFormat2 *iface)
4987 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4988 TRACE("(%p)\n", This);
4989 return This->format.locale_len;
4992 static HRESULT WINAPI dwritetextformat_GetLocaleName(IDWriteTextFormat2 *iface, WCHAR *name, UINT32 size)
4994 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4996 TRACE("(%p)->(%p %u)\n", This, name, size);
4998 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
4999 strcpyW(name, This->format.locale);
5000 return S_OK;
5003 static HRESULT WINAPI dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat2 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
5005 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5007 TRACE("(%p)->(%d)\n", This, orientation);
5009 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
5010 return E_INVALIDARG;
5012 This->format.vertical_orientation = orientation;
5013 return S_OK;
5016 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat2 *iface)
5018 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5019 TRACE("(%p)\n", This);
5020 return This->format.vertical_orientation;
5023 static HRESULT WINAPI dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat2 *iface, BOOL lastline_wrapping_enabled)
5025 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5027 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
5029 This->format.last_line_wrapping = !!lastline_wrapping_enabled;
5030 return S_OK;
5033 static BOOL WINAPI dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat2 *iface)
5035 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5036 TRACE("(%p)\n", This);
5037 return This->format.last_line_wrapping;
5040 static HRESULT WINAPI dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat2 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
5042 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5043 TRACE("(%p)->(%d)\n", This, alignment);
5044 return format_set_optical_alignment(&This->format, alignment);
5047 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat2 *iface)
5049 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5050 TRACE("(%p)\n", This);
5051 return This->format.optical_alignment;
5054 static HRESULT WINAPI dwritetextformat1_SetFontFallback(IDWriteTextFormat2 *iface, IDWriteFontFallback *fallback)
5056 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5057 TRACE("(%p)->(%p)\n", This, fallback);
5058 return set_fontfallback_for_format(&This->format, fallback);
5061 static HRESULT WINAPI dwritetextformat1_GetFontFallback(IDWriteTextFormat2 *iface, IDWriteFontFallback **fallback)
5063 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5064 TRACE("(%p)->(%p)\n", This, fallback);
5065 return get_fontfallback_from_format(&This->format, fallback);
5068 static HRESULT WINAPI dwritetextformat2_SetLineSpacing(IDWriteTextFormat2 *iface, DWRITE_LINE_SPACING const *spacing)
5070 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5071 FIXME("(%p)->(%p): stub\n", This, spacing);
5072 return E_NOTIMPL;
5075 static HRESULT WINAPI dwritetextformat2_GetLineSpacing(IDWriteTextFormat2 *iface, DWRITE_LINE_SPACING *spacing)
5077 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5078 FIXME("(%p)->(%p): stub\n", This, spacing);
5079 return E_NOTIMPL;
5082 static const IDWriteTextFormat2Vtbl dwritetextformatvtbl = {
5083 dwritetextformat_QueryInterface,
5084 dwritetextformat_AddRef,
5085 dwritetextformat_Release,
5086 dwritetextformat_SetTextAlignment,
5087 dwritetextformat_SetParagraphAlignment,
5088 dwritetextformat_SetWordWrapping,
5089 dwritetextformat_SetReadingDirection,
5090 dwritetextformat_SetFlowDirection,
5091 dwritetextformat_SetIncrementalTabStop,
5092 dwritetextformat_SetTrimming,
5093 dwritetextformat_SetLineSpacing,
5094 dwritetextformat_GetTextAlignment,
5095 dwritetextformat_GetParagraphAlignment,
5096 dwritetextformat_GetWordWrapping,
5097 dwritetextformat_GetReadingDirection,
5098 dwritetextformat_GetFlowDirection,
5099 dwritetextformat_GetIncrementalTabStop,
5100 dwritetextformat_GetTrimming,
5101 dwritetextformat_GetLineSpacing,
5102 dwritetextformat_GetFontCollection,
5103 dwritetextformat_GetFontFamilyNameLength,
5104 dwritetextformat_GetFontFamilyName,
5105 dwritetextformat_GetFontWeight,
5106 dwritetextformat_GetFontStyle,
5107 dwritetextformat_GetFontStretch,
5108 dwritetextformat_GetFontSize,
5109 dwritetextformat_GetLocaleNameLength,
5110 dwritetextformat_GetLocaleName,
5111 dwritetextformat1_SetVerticalGlyphOrientation,
5112 dwritetextformat1_GetVerticalGlyphOrientation,
5113 dwritetextformat1_SetLastLineWrapping,
5114 dwritetextformat1_GetLastLineWrapping,
5115 dwritetextformat1_SetOpticalAlignment,
5116 dwritetextformat1_GetOpticalAlignment,
5117 dwritetextformat1_SetFontFallback,
5118 dwritetextformat1_GetFontFallback,
5119 dwritetextformat2_SetLineSpacing,
5120 dwritetextformat2_GetLineSpacing
5123 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat *iface)
5125 return (iface->lpVtbl == (IDWriteTextFormatVtbl*)&dwritetextformatvtbl) ?
5126 CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat2_iface) : NULL;
5129 HRESULT create_textformat(const WCHAR *family_name, IDWriteFontCollection *collection, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style,
5130 DWRITE_FONT_STRETCH stretch, FLOAT size, const WCHAR *locale, IDWriteTextFormat **format)
5132 struct dwrite_textformat *This;
5134 *format = NULL;
5136 This = heap_alloc(sizeof(struct dwrite_textformat));
5137 if (!This) return E_OUTOFMEMORY;
5139 This->IDWriteTextFormat2_iface.lpVtbl = &dwritetextformatvtbl;
5140 This->ref = 1;
5141 This->format.family_name = heap_strdupW(family_name);
5142 This->format.family_len = strlenW(family_name);
5143 This->format.locale = heap_strdupW(locale);
5144 This->format.locale_len = strlenW(locale);
5145 /* force locale name to lower case, layout will inherit this modified value */
5146 strlwrW(This->format.locale);
5147 This->format.weight = weight;
5148 This->format.style = style;
5149 This->format.fontsize = size;
5150 This->format.stretch = stretch;
5151 This->format.textalignment = DWRITE_TEXT_ALIGNMENT_LEADING;
5152 This->format.optical_alignment = DWRITE_OPTICAL_ALIGNMENT_NONE;
5153 This->format.paralign = DWRITE_PARAGRAPH_ALIGNMENT_NEAR;
5154 This->format.wrapping = DWRITE_WORD_WRAPPING_WRAP;
5155 This->format.last_line_wrapping = TRUE;
5156 This->format.readingdir = DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
5157 This->format.flow = DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM;
5158 This->format.spacingmethod = DWRITE_LINE_SPACING_METHOD_DEFAULT;
5159 This->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
5160 This->format.spacing = 0.0f;
5161 This->format.baseline = 0.0f;
5162 This->format.trimming.granularity = DWRITE_TRIMMING_GRANULARITY_NONE;
5163 This->format.trimming.delimiter = 0;
5164 This->format.trimming.delimiterCount = 0;
5165 This->format.trimmingsign = NULL;
5166 This->format.collection = collection;
5167 This->format.fallback = NULL;
5168 IDWriteFontCollection_AddRef(collection);
5170 *format = (IDWriteTextFormat*)&This->IDWriteTextFormat2_iface;
5172 return S_OK;
5175 static HRESULT WINAPI dwritetypography_QueryInterface(IDWriteTypography *iface, REFIID riid, void **obj)
5177 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5179 TRACE("(%p)->(%s %p)\n", typography, debugstr_guid(riid), obj);
5181 if (IsEqualIID(riid, &IID_IDWriteTypography) || IsEqualIID(riid, &IID_IUnknown)) {
5182 *obj = iface;
5183 IDWriteTypography_AddRef(iface);
5184 return S_OK;
5187 *obj = NULL;
5189 return E_NOINTERFACE;
5192 static ULONG WINAPI dwritetypography_AddRef(IDWriteTypography *iface)
5194 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5195 ULONG ref = InterlockedIncrement(&typography->ref);
5196 TRACE("(%p)->(%d)\n", typography, ref);
5197 return ref;
5200 static ULONG WINAPI dwritetypography_Release(IDWriteTypography *iface)
5202 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5203 ULONG ref = InterlockedDecrement(&typography->ref);
5205 TRACE("(%p)->(%d)\n", typography, ref);
5207 if (!ref) {
5208 heap_free(typography->features);
5209 heap_free(typography);
5212 return ref;
5215 static HRESULT WINAPI dwritetypography_AddFontFeature(IDWriteTypography *iface, DWRITE_FONT_FEATURE feature)
5217 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5219 TRACE("(%p)->(%x %u)\n", typography, feature.nameTag, feature.parameter);
5221 if (typography->count == typography->allocated) {
5222 DWRITE_FONT_FEATURE *ptr = heap_realloc(typography->features, 2*typography->allocated*sizeof(DWRITE_FONT_FEATURE));
5223 if (!ptr)
5224 return E_OUTOFMEMORY;
5226 typography->features = ptr;
5227 typography->allocated *= 2;
5230 typography->features[typography->count++] = feature;
5231 return S_OK;
5234 static UINT32 WINAPI dwritetypography_GetFontFeatureCount(IDWriteTypography *iface)
5236 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5237 TRACE("(%p)\n", typography);
5238 return typography->count;
5241 static HRESULT WINAPI dwritetypography_GetFontFeature(IDWriteTypography *iface, UINT32 index, DWRITE_FONT_FEATURE *feature)
5243 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5245 TRACE("(%p)->(%u %p)\n", typography, index, feature);
5247 if (index >= typography->count)
5248 return E_INVALIDARG;
5250 *feature = typography->features[index];
5251 return S_OK;
5254 static const IDWriteTypographyVtbl dwritetypographyvtbl = {
5255 dwritetypography_QueryInterface,
5256 dwritetypography_AddRef,
5257 dwritetypography_Release,
5258 dwritetypography_AddFontFeature,
5259 dwritetypography_GetFontFeatureCount,
5260 dwritetypography_GetFontFeature
5263 HRESULT create_typography(IDWriteTypography **ret)
5265 struct dwrite_typography *typography;
5267 *ret = NULL;
5269 typography = heap_alloc(sizeof(*typography));
5270 if (!typography)
5271 return E_OUTOFMEMORY;
5273 typography->IDWriteTypography_iface.lpVtbl = &dwritetypographyvtbl;
5274 typography->ref = 1;
5275 typography->allocated = 2;
5276 typography->count = 0;
5278 typography->features = heap_alloc(typography->allocated*sizeof(DWRITE_FONT_FEATURE));
5279 if (!typography->features) {
5280 heap_free(typography);
5281 return E_OUTOFMEMORY;
5284 *ret = &typography->IDWriteTypography_iface;
5285 return S_OK;