mshtml: Don't crash creating a URI if we have no document.
[wine.git] / dlls / dwrite / layout.c
blobb95dffa49b3a2edd3098dbdad2116140a5de2898
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_VERTICAL_GLYPH_ORIENTATION vertical_orientation;
51 DWRITE_OPTICAL_ALIGNMENT optical_alignment;
52 DWRITE_LINE_SPACING spacing;
54 FLOAT fontsize;
56 DWRITE_TRIMMING trimming;
57 IDWriteInlineObject *trimmingsign;
59 IDWriteFontCollection *collection;
60 IDWriteFontFallback *fallback;
63 enum layout_range_attr_kind {
64 LAYOUT_RANGE_ATTR_WEIGHT,
65 LAYOUT_RANGE_ATTR_STYLE,
66 LAYOUT_RANGE_ATTR_STRETCH,
67 LAYOUT_RANGE_ATTR_FONTSIZE,
68 LAYOUT_RANGE_ATTR_EFFECT,
69 LAYOUT_RANGE_ATTR_INLINE,
70 LAYOUT_RANGE_ATTR_UNDERLINE,
71 LAYOUT_RANGE_ATTR_STRIKETHROUGH,
72 LAYOUT_RANGE_ATTR_PAIR_KERNING,
73 LAYOUT_RANGE_ATTR_FONTCOLL,
74 LAYOUT_RANGE_ATTR_LOCALE,
75 LAYOUT_RANGE_ATTR_FONTFAMILY,
76 LAYOUT_RANGE_ATTR_SPACING,
77 LAYOUT_RANGE_ATTR_TYPOGRAPHY
80 struct layout_range_attr_value {
81 DWRITE_TEXT_RANGE range;
82 union {
83 DWRITE_FONT_WEIGHT weight;
84 DWRITE_FONT_STYLE style;
85 DWRITE_FONT_STRETCH stretch;
86 FLOAT fontsize;
87 IDWriteInlineObject *object;
88 IUnknown *effect;
89 BOOL underline;
90 BOOL strikethrough;
91 BOOL pair_kerning;
92 IDWriteFontCollection *collection;
93 const WCHAR *locale;
94 const WCHAR *fontfamily;
95 FLOAT spacing[3]; /* in arguments order - leading, trailing, advance */
96 IDWriteTypography *typography;
97 } u;
100 enum layout_range_kind {
101 LAYOUT_RANGE_REGULAR,
102 LAYOUT_RANGE_UNDERLINE,
103 LAYOUT_RANGE_STRIKETHROUGH,
104 LAYOUT_RANGE_EFFECT,
105 LAYOUT_RANGE_SPACING,
106 LAYOUT_RANGE_TYPOGRAPHY
109 struct layout_range_header {
110 struct list entry;
111 enum layout_range_kind kind;
112 DWRITE_TEXT_RANGE range;
115 struct layout_range {
116 struct layout_range_header h;
117 DWRITE_FONT_WEIGHT weight;
118 DWRITE_FONT_STYLE style;
119 FLOAT fontsize;
120 DWRITE_FONT_STRETCH stretch;
121 IDWriteInlineObject *object;
122 BOOL pair_kerning;
123 IDWriteFontCollection *collection;
124 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
125 WCHAR *fontfamily;
128 struct layout_range_bool {
129 struct layout_range_header h;
130 BOOL value;
133 struct layout_range_iface {
134 struct layout_range_header h;
135 IUnknown *iface;
138 struct layout_range_spacing {
139 struct layout_range_header h;
140 FLOAT leading;
141 FLOAT trailing;
142 FLOAT min_advance;
145 enum layout_run_kind {
146 LAYOUT_RUN_REGULAR,
147 LAYOUT_RUN_INLINE
150 struct inline_object_run {
151 IDWriteInlineObject *object;
152 UINT16 length;
155 struct regular_layout_run {
156 DWRITE_GLYPH_RUN_DESCRIPTION descr;
157 DWRITE_GLYPH_RUN run;
158 DWRITE_SCRIPT_ANALYSIS sa;
159 UINT16 *glyphs;
160 UINT16 *clustermap;
161 FLOAT *advances;
162 DWRITE_GLYPH_OFFSET *offsets;
163 /* this is actual glyph count after shaping, it's not necessary the same as reported to Draw() */
164 UINT32 glyphcount;
167 struct layout_run {
168 struct list entry;
169 enum layout_run_kind kind;
170 union {
171 struct inline_object_run object;
172 struct regular_layout_run regular;
173 } u;
174 FLOAT baseline;
175 FLOAT height;
178 struct layout_effective_run {
179 struct list entry;
180 const struct layout_run *run; /* nominal run this one is based on */
181 UINT32 start; /* relative text position, 0 means first text position of a nominal run */
182 UINT32 length; /* length in codepoints that this run covers */
183 UINT32 glyphcount; /* total glyph count in this run */
184 IUnknown *effect; /* original reference is kept only at range level */
185 FLOAT origin_x; /* baseline X position */
186 FLOAT origin_y; /* baseline Y position */
187 FLOAT align_dx; /* adjustment from text alignment */
188 FLOAT width; /* run width */
189 UINT16 *clustermap; /* effective clustermap, allocated separately, is not reused from nominal map */
190 UINT32 line; /* 0-based line index in line metrics array */
191 BOOL underlined; /* set if this run is underlined */
194 struct layout_effective_inline {
195 struct list entry;
196 const struct layout_run *run; /* nominal run this one is based on */
197 IUnknown *effect; /* original reference is kept only at range level */
198 FLOAT origin_x; /* left X position */
199 FLOAT origin_y; /* left top corner Y position */
200 FLOAT align_dx; /* adjustment from text alignment */
201 FLOAT width; /* object width as it's reported it */
202 BOOL is_sideways; /* vertical flow direction flag passed to Draw */
203 BOOL is_rtl; /* bidi flag passed to Draw */
204 UINT32 line; /* 0-based line index in line metrics array */
207 struct layout_underline {
208 struct list entry;
209 const struct layout_effective_run *run;
210 DWRITE_UNDERLINE u;
213 struct layout_strikethrough {
214 struct list entry;
215 const struct layout_effective_run *run;
216 DWRITE_STRIKETHROUGH s;
219 struct layout_cluster {
220 const struct layout_run *run; /* link to nominal run this cluster belongs to */
221 UINT32 position; /* relative to run, first cluster has 0 position */
224 enum layout_recompute_mask {
225 RECOMPUTE_CLUSTERS = 1 << 0,
226 RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
227 RECOMPUTE_LINES = 1 << 2,
228 RECOMPUTE_EVERYTHING = 0xffff
231 struct dwrite_textlayout {
232 IDWriteTextLayout3 IDWriteTextLayout3_iface;
233 IDWriteTextFormat1 IDWriteTextFormat1_iface;
234 IDWriteTextAnalysisSink1 IDWriteTextAnalysisSink1_iface;
235 IDWriteTextAnalysisSource1 IDWriteTextAnalysisSource1_iface;
236 LONG ref;
238 IDWriteFactory3 *factory;
240 WCHAR *str;
241 UINT32 len;
242 struct dwrite_textformat_data format;
243 struct list strike_ranges;
244 struct list underline_ranges;
245 struct list typographies;
246 struct list effects;
247 struct list spacing;
248 struct list ranges;
249 struct list runs;
250 /* lists ready to use by Draw() */
251 struct list eruns;
252 struct list inlineobjects;
253 struct list underlines;
254 struct list strikethrough;
255 USHORT recompute;
257 DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
258 DWRITE_LINE_BREAKPOINT *actual_breakpoints;
260 struct layout_cluster *clusters;
261 DWRITE_CLUSTER_METRICS *clustermetrics;
262 UINT32 cluster_count;
263 FLOAT minwidth;
265 DWRITE_LINE_METRICS1 *lines;
266 UINT32 line_alloc;
268 DWRITE_TEXT_METRICS1 metrics;
270 DWRITE_MEASURING_MODE measuringmode;
272 /* gdi-compatible layout specifics */
273 FLOAT ppdip;
274 DWRITE_MATRIX transform;
277 struct dwrite_textformat {
278 IDWriteTextFormat2 IDWriteTextFormat2_iface;
279 LONG ref;
280 struct dwrite_textformat_data format;
283 struct dwrite_trimmingsign {
284 IDWriteInlineObject IDWriteInlineObject_iface;
285 LONG ref;
287 IDWriteTextLayout *layout;
290 struct dwrite_typography {
291 IDWriteTypography IDWriteTypography_iface;
292 LONG ref;
294 DWRITE_FONT_FEATURE *features;
295 UINT32 allocated;
296 UINT32 count;
299 struct dwrite_vec {
300 FLOAT x;
301 FLOAT y;
304 static const IDWriteTextFormat2Vtbl dwritetextformatvtbl;
306 static void release_format_data(struct dwrite_textformat_data *data)
308 if (data->collection) IDWriteFontCollection_Release(data->collection);
309 if (data->fallback) IDWriteFontFallback_Release(data->fallback);
310 if (data->trimmingsign) IDWriteInlineObject_Release(data->trimmingsign);
311 heap_free(data->family_name);
312 heap_free(data->locale);
315 static inline struct dwrite_textlayout *impl_from_IDWriteTextLayout3(IDWriteTextLayout3 *iface)
317 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextLayout3_iface);
320 static inline struct dwrite_textlayout *impl_layout_from_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
322 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextFormat1_iface);
325 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSink1(IDWriteTextAnalysisSink1 *iface)
327 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSink1_iface);
330 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSource1(IDWriteTextAnalysisSource1 *iface)
332 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSource1_iface);
335 static inline struct dwrite_textformat *impl_from_IDWriteTextFormat2(IDWriteTextFormat2 *iface)
337 return CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat2_iface);
340 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat*);
342 static inline struct dwrite_trimmingsign *impl_from_IDWriteInlineObject(IDWriteInlineObject *iface)
344 return CONTAINING_RECORD(iface, struct dwrite_trimmingsign, IDWriteInlineObject_iface);
347 static inline struct dwrite_typography *impl_from_IDWriteTypography(IDWriteTypography *iface)
349 return CONTAINING_RECORD(iface, struct dwrite_typography, IDWriteTypography_iface);
352 static inline const char *debugstr_rundescr(const DWRITE_GLYPH_RUN_DESCRIPTION *descr)
354 return wine_dbg_sprintf("[%u,%u)", descr->textPosition, descr->textPosition + descr->stringLength);
357 static inline BOOL is_layout_gdi_compatible(struct dwrite_textlayout *layout)
359 return layout->measuringmode != DWRITE_MEASURING_MODE_NATURAL;
362 static inline HRESULT format_set_textalignment(struct dwrite_textformat_data *format, DWRITE_TEXT_ALIGNMENT alignment,
363 BOOL *changed)
365 if ((UINT32)alignment > DWRITE_TEXT_ALIGNMENT_JUSTIFIED)
366 return E_INVALIDARG;
367 if (changed) *changed = format->textalignment != alignment;
368 format->textalignment = alignment;
369 return S_OK;
372 static inline HRESULT format_set_paralignment(struct dwrite_textformat_data *format,
373 DWRITE_PARAGRAPH_ALIGNMENT alignment, BOOL *changed)
375 if ((UINT32)alignment > DWRITE_PARAGRAPH_ALIGNMENT_CENTER)
376 return E_INVALIDARG;
377 if (changed) *changed = format->paralign != alignment;
378 format->paralign = alignment;
379 return S_OK;
382 static inline HRESULT format_set_readingdirection(struct dwrite_textformat_data *format,
383 DWRITE_READING_DIRECTION direction, BOOL *changed)
385 if ((UINT32)direction > DWRITE_READING_DIRECTION_BOTTOM_TO_TOP)
386 return E_INVALIDARG;
387 if (changed) *changed = format->readingdir != direction;
388 format->readingdir = direction;
389 return S_OK;
392 static inline HRESULT format_set_wordwrapping(struct dwrite_textformat_data *format,
393 DWRITE_WORD_WRAPPING wrapping, BOOL *changed)
395 if ((UINT32)wrapping > DWRITE_WORD_WRAPPING_CHARACTER)
396 return E_INVALIDARG;
397 if (changed) *changed = format->wrapping != wrapping;
398 format->wrapping = wrapping;
399 return S_OK;
402 static inline HRESULT format_set_flowdirection(struct dwrite_textformat_data *format,
403 DWRITE_FLOW_DIRECTION direction, BOOL *changed)
405 if ((UINT32)direction > DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT)
406 return E_INVALIDARG;
407 if (changed) *changed = format->flow != direction;
408 format->flow = direction;
409 return S_OK;
412 static inline HRESULT format_set_trimming(struct dwrite_textformat_data *format,
413 DWRITE_TRIMMING const *trimming, IDWriteInlineObject *trimming_sign, BOOL *changed)
415 if (changed)
416 *changed = FALSE;
418 if ((UINT32)trimming->granularity > DWRITE_TRIMMING_GRANULARITY_WORD)
419 return E_INVALIDARG;
421 if (changed) {
422 *changed = !!memcmp(&format->trimming, trimming, sizeof(*trimming));
423 if (format->trimmingsign != trimming_sign)
424 *changed = TRUE;
427 format->trimming = *trimming;
428 if (format->trimmingsign)
429 IDWriteInlineObject_Release(format->trimmingsign);
430 format->trimmingsign = trimming_sign;
431 if (format->trimmingsign)
432 IDWriteInlineObject_AddRef(format->trimmingsign);
433 return S_OK;
436 static inline HRESULT format_set_linespacing(struct dwrite_textformat_data *format,
437 DWRITE_LINE_SPACING const *spacing, BOOL *changed)
439 if (spacing->height < 0.0f || spacing->leadingBefore < 0.0f || spacing->leadingBefore > 1.0f ||
440 (UINT32)spacing->method > DWRITE_LINE_SPACING_METHOD_PROPORTIONAL)
441 return E_INVALIDARG;
443 if (changed)
444 *changed = memcmp(spacing, &format->spacing, sizeof(*spacing));
446 format->spacing = *spacing;
447 return S_OK;
450 static HRESULT get_fontfallback_from_format(const struct dwrite_textformat_data *format, IDWriteFontFallback **fallback)
452 *fallback = format->fallback;
453 if (*fallback)
454 IDWriteFontFallback_AddRef(*fallback);
455 return S_OK;
458 static HRESULT set_fontfallback_for_format(struct dwrite_textformat_data *format, IDWriteFontFallback *fallback)
460 if (format->fallback)
461 IDWriteFontFallback_Release(format->fallback);
462 format->fallback = fallback;
463 if (fallback)
464 IDWriteFontFallback_AddRef(fallback);
465 return S_OK;
468 static HRESULT format_set_optical_alignment(struct dwrite_textformat_data *format,
469 DWRITE_OPTICAL_ALIGNMENT alignment)
471 if ((UINT32)alignment > DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS)
472 return E_INVALIDARG;
473 format->optical_alignment = alignment;
474 return S_OK;
477 static BOOL is_run_rtl(const struct layout_effective_run *run)
479 return run->run->u.regular.run.bidiLevel & 1;
482 static struct layout_run *alloc_layout_run(enum layout_run_kind kind)
484 struct layout_run *ret;
486 ret = heap_alloc(sizeof(*ret));
487 if (!ret) return NULL;
489 memset(ret, 0, sizeof(*ret));
490 ret->kind = kind;
491 if (kind == LAYOUT_RUN_REGULAR) {
492 ret->u.regular.sa.script = Script_Unknown;
493 ret->u.regular.sa.shapes = DWRITE_SCRIPT_SHAPES_DEFAULT;
496 return ret;
499 static void free_layout_runs(struct dwrite_textlayout *layout)
501 struct layout_run *cur, *cur2;
502 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->runs, struct layout_run, entry) {
503 list_remove(&cur->entry);
504 if (cur->kind == LAYOUT_RUN_REGULAR) {
505 if (cur->u.regular.run.fontFace)
506 IDWriteFontFace_Release(cur->u.regular.run.fontFace);
507 heap_free(cur->u.regular.glyphs);
508 heap_free(cur->u.regular.clustermap);
509 heap_free(cur->u.regular.advances);
510 heap_free(cur->u.regular.offsets);
512 heap_free(cur);
516 static void free_layout_eruns(struct dwrite_textlayout *layout)
518 struct layout_effective_inline *in, *in2;
519 struct layout_effective_run *cur, *cur2;
520 struct layout_strikethrough *s, *s2;
521 struct layout_underline *u, *u2;
523 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->eruns, struct layout_effective_run, entry) {
524 list_remove(&cur->entry);
525 heap_free(cur->clustermap);
526 heap_free(cur);
529 LIST_FOR_EACH_ENTRY_SAFE(in, in2, &layout->inlineobjects, struct layout_effective_inline, entry) {
530 list_remove(&in->entry);
531 heap_free(in);
534 LIST_FOR_EACH_ENTRY_SAFE(u, u2, &layout->underlines, struct layout_underline, entry) {
535 list_remove(&u->entry);
536 heap_free(u);
539 LIST_FOR_EACH_ENTRY_SAFE(s, s2, &layout->strikethrough, struct layout_strikethrough, entry) {
540 list_remove(&s->entry);
541 heap_free(s);
545 /* Used to resolve break condition by forcing stronger condition over weaker. */
546 static inline DWRITE_BREAK_CONDITION override_break_condition(DWRITE_BREAK_CONDITION existingbreak, DWRITE_BREAK_CONDITION newbreak)
548 switch (existingbreak) {
549 case DWRITE_BREAK_CONDITION_NEUTRAL:
550 return newbreak;
551 case DWRITE_BREAK_CONDITION_CAN_BREAK:
552 return newbreak == DWRITE_BREAK_CONDITION_NEUTRAL ? existingbreak : newbreak;
553 /* let's keep stronger conditions as is */
554 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK:
555 case DWRITE_BREAK_CONDITION_MUST_BREAK:
556 break;
557 default:
558 ERR("unknown break condition %d\n", existingbreak);
561 return existingbreak;
564 /* This helper should be used to get effective range length, in other words it returns number of text
565 positions from range starting point to the end of the range, limited by layout text length */
566 static inline UINT32 get_clipped_range_length(const struct dwrite_textlayout *layout, const struct layout_range *range)
568 if (range->h.range.startPosition + range->h.range.length <= layout->len)
569 return range->h.range.length;
570 return layout->len - range->h.range.startPosition;
573 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
574 static HRESULT layout_update_breakpoints_range(struct dwrite_textlayout *layout, const struct layout_range *cur)
576 DWRITE_BREAK_CONDITION before, after;
577 UINT32 i, length;
578 HRESULT hr;
580 /* ignore returned conditions if failed */
581 hr = IDWriteInlineObject_GetBreakConditions(cur->object, &before, &after);
582 if (FAILED(hr))
583 after = before = DWRITE_BREAK_CONDITION_NEUTRAL;
585 if (!layout->actual_breakpoints) {
586 layout->actual_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
587 if (!layout->actual_breakpoints)
588 return E_OUTOFMEMORY;
589 memcpy(layout->actual_breakpoints, layout->nominal_breakpoints, sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
592 length = get_clipped_range_length(layout, cur);
593 for (i = cur->h.range.startPosition; i < length + cur->h.range.startPosition; i++) {
594 /* for first codepoint check if there's anything before it and update accordingly */
595 if (i == cur->h.range.startPosition) {
596 if (i > 0)
597 layout->actual_breakpoints[i].breakConditionBefore = layout->actual_breakpoints[i-1].breakConditionAfter =
598 override_break_condition(layout->actual_breakpoints[i-1].breakConditionAfter, before);
599 else
600 layout->actual_breakpoints[i].breakConditionBefore = before;
601 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
603 /* similar check for last codepoint */
604 else if (i == cur->h.range.startPosition + length - 1) {
605 if (i == layout->len - 1)
606 layout->actual_breakpoints[i].breakConditionAfter = after;
607 else
608 layout->actual_breakpoints[i].breakConditionAfter = layout->actual_breakpoints[i+1].breakConditionBefore =
609 override_break_condition(layout->actual_breakpoints[i+1].breakConditionBefore, after);
610 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
612 /* for all positions within a range disable breaks */
613 else {
614 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
615 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
618 layout->actual_breakpoints[i].isWhitespace = 0;
619 layout->actual_breakpoints[i].isSoftHyphen = 0;
622 return S_OK;
625 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos);
627 static inline DWRITE_LINE_BREAKPOINT get_effective_breakpoint(const struct dwrite_textlayout *layout, UINT32 pos)
629 if (layout->actual_breakpoints)
630 return layout->actual_breakpoints[pos];
631 return layout->nominal_breakpoints[pos];
634 static inline void init_cluster_metrics(const struct dwrite_textlayout *layout, const struct regular_layout_run *run,
635 UINT16 start_glyph, UINT16 stop_glyph, UINT32 stop_position, UINT16 length, DWRITE_CLUSTER_METRICS *metrics)
637 UINT8 breakcondition;
638 UINT32 position;
639 UINT16 j;
641 /* For clusters made of control chars we report zero glyphs, and we need zero cluster
642 width as well; advances are already computed at this point and are not necessary zero. */
643 metrics->width = 0.0f;
644 if (run->run.glyphCount) {
645 for (j = start_glyph; j < stop_glyph; j++)
646 metrics->width += run->run.glyphAdvances[j];
648 metrics->length = length;
650 position = run->descr.textPosition + stop_position;
651 if (stop_glyph == run->glyphcount)
652 breakcondition = get_effective_breakpoint(layout, position).breakConditionAfter;
653 else {
654 breakcondition = get_effective_breakpoint(layout, position).breakConditionBefore;
655 if (stop_position) position -= 1;
658 metrics->canWrapLineAfter = breakcondition == DWRITE_BREAK_CONDITION_CAN_BREAK ||
659 breakcondition == DWRITE_BREAK_CONDITION_MUST_BREAK;
660 if (metrics->length == 1) {
661 DWRITE_LINE_BREAKPOINT bp = get_effective_breakpoint(layout, position);
662 metrics->isWhitespace = bp.isWhitespace;
663 metrics->isNewline = metrics->canWrapLineAfter && lb_is_newline_char(layout->str[position]);
664 metrics->isSoftHyphen = bp.isSoftHyphen;
666 else {
667 metrics->isWhitespace = 0;
668 metrics->isNewline = 0;
669 metrics->isSoftHyphen = 0;
671 metrics->isRightToLeft = run->run.bidiLevel & 1;
672 metrics->padding = 0;
677 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
678 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
679 Note that there's no need to reallocate anything at this point as we allocate one cluster per
680 codepoint initially.
683 static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 *cluster)
685 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[*cluster];
686 struct layout_cluster *c = &layout->clusters[*cluster];
687 const struct regular_layout_run *run = &r->u.regular;
688 UINT32 i, start = 0;
690 for (i = 0; i < run->descr.stringLength; i++) {
691 BOOL end = i == run->descr.stringLength - 1;
693 if (run->descr.clusterMap[start] != run->descr.clusterMap[i]) {
694 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->descr.clusterMap[i], i,
695 i - start, metrics);
696 c->position = start;
697 c->run = r;
699 *cluster += 1;
700 metrics++;
701 c++;
702 start = i;
705 if (end) {
706 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->glyphcount, i,
707 i - start + 1, metrics);
708 c->position = start;
709 c->run = r;
711 *cluster += 1;
712 return;
717 #define SCALE_FONT_METRIC(metric, emSize, metrics) ((FLOAT)(metric) * (emSize) / (FLOAT)(metrics)->designUnitsPerEm)
719 static void layout_get_font_metrics(struct dwrite_textlayout *layout, IDWriteFontFace *fontface, FLOAT emsize,
720 DWRITE_FONT_METRICS *fontmetrics)
722 if (is_layout_gdi_compatible(layout)) {
723 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(fontface, emsize, layout->ppdip, &layout->transform, fontmetrics);
724 if (FAILED(hr))
725 WARN("failed to get compat metrics, 0x%08x\n", hr);
727 else
728 IDWriteFontFace_GetMetrics(fontface, fontmetrics);
731 static void layout_get_font_height(FLOAT emsize, DWRITE_FONT_METRICS *fontmetrics, FLOAT *baseline, FLOAT *height)
733 *baseline = SCALE_FONT_METRIC(fontmetrics->ascent + fontmetrics->lineGap, emsize, fontmetrics);
734 *height = SCALE_FONT_METRIC(fontmetrics->ascent + fontmetrics->descent + fontmetrics->lineGap, emsize, fontmetrics);
737 static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
739 IDWriteFontFallback *fallback;
740 IDWriteTextAnalyzer *analyzer;
741 struct layout_range *range;
742 struct layout_run *r;
743 UINT32 cluster = 0;
744 HRESULT hr;
746 free_layout_eruns(layout);
747 free_layout_runs(layout);
749 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
750 if (!layout->clustermetrics && layout->len) {
751 layout->clustermetrics = heap_alloc(layout->len*sizeof(*layout->clustermetrics));
752 layout->clusters = heap_alloc(layout->len*sizeof(*layout->clusters));
753 if (!layout->clustermetrics || !layout->clusters) {
754 heap_free(layout->clustermetrics);
755 heap_free(layout->clusters);
756 return E_OUTOFMEMORY;
759 layout->cluster_count = 0;
761 hr = get_textanalyzer(&analyzer);
762 if (FAILED(hr))
763 return hr;
765 LIST_FOR_EACH_ENTRY(range, &layout->ranges, struct layout_range, h.entry) {
766 /* we don't care about ranges that don't contain any text */
767 if (range->h.range.startPosition >= layout->len)
768 break;
770 /* inline objects override actual text in a range */
771 if (range->object) {
772 hr = layout_update_breakpoints_range(layout, range);
773 if (FAILED(hr))
774 return hr;
776 r = alloc_layout_run(LAYOUT_RUN_INLINE);
777 if (!r)
778 return E_OUTOFMEMORY;
780 r->u.object.object = range->object;
781 r->u.object.length = get_clipped_range_length(layout, range);
782 list_add_tail(&layout->runs, &r->entry);
783 continue;
786 /* initial splitting by script */
787 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, (IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
788 range->h.range.startPosition, get_clipped_range_length(layout, range), (IDWriteTextAnalysisSink*)&layout->IDWriteTextAnalysisSink1_iface);
789 if (FAILED(hr))
790 break;
792 /* this splits it further */
793 hr = IDWriteTextAnalyzer_AnalyzeBidi(analyzer, (IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
794 range->h.range.startPosition, get_clipped_range_length(layout, range), (IDWriteTextAnalysisSink*)&layout->IDWriteTextAnalysisSink1_iface);
795 if (FAILED(hr))
796 break;
799 if (layout->format.fallback) {
800 fallback = layout->format.fallback;
801 IDWriteFontFallback_AddRef(fallback);
803 else {
804 hr = IDWriteFactory3_GetSystemFontFallback(layout->factory, &fallback);
805 if (FAILED(hr))
806 return hr;
809 /* resolve run fonts */
810 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
811 struct regular_layout_run *run = &r->u.regular;
812 IDWriteFont *font;
813 UINT32 length;
815 if (r->kind == LAYOUT_RUN_INLINE)
816 continue;
818 range = get_layout_range_by_pos(layout, run->descr.textPosition);
820 if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL) {
821 IDWriteFontCollection *collection;
823 if (range->collection) {
824 collection = range->collection;
825 IDWriteFontCollection_AddRef(collection);
827 else
828 IDWriteFactory3_GetSystemFontCollection(layout->factory, FALSE, (IDWriteFontCollection1**)&collection, FALSE);
830 hr = create_matching_font(collection, range->fontfamily, range->weight,
831 range->style, range->stretch, &font);
833 IDWriteFontCollection_Release(collection);
835 if (FAILED(hr)) {
836 WARN("%s: failed to create a font for non visual run, %s, collection %p\n", debugstr_rundescr(&run->descr),
837 debugstr_w(range->fontfamily), range->collection);
838 return hr;
841 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
842 IDWriteFont_Release(font);
843 if (FAILED(hr))
844 return hr;
846 run->run.fontEmSize = range->fontsize;
847 continue;
850 length = run->descr.stringLength;
852 while (length) {
853 UINT32 mapped_length;
854 FLOAT scale;
856 run = &r->u.regular;
858 hr = IDWriteFontFallback_MapCharacters(fallback,
859 (IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
860 run->descr.textPosition,
861 run->descr.stringLength,
862 range->collection,
863 range->fontfamily,
864 range->weight,
865 range->style,
866 range->stretch,
867 &mapped_length,
868 &font,
869 &scale);
870 if (FAILED(hr)) {
871 WARN("%s: failed to map family %s, collection %p\n", debugstr_rundescr(&run->descr), debugstr_w(range->fontfamily), range->collection);
872 return hr;
875 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
876 IDWriteFont_Release(font);
877 if (FAILED(hr))
878 return hr;
879 run->run.fontEmSize = range->fontsize * scale;
881 if (mapped_length < length) {
882 struct regular_layout_run *nextrun = &r->u.regular;
883 struct layout_run *nextr;
885 /* keep mapped part for current run, add another run for the rest */
886 nextr = alloc_layout_run(LAYOUT_RUN_REGULAR);
887 if (!nextr)
888 return E_OUTOFMEMORY;
890 *nextr = *r;
891 nextrun = &nextr->u.regular;
892 nextrun->descr.textPosition = run->descr.textPosition + mapped_length;
893 nextrun->descr.stringLength = run->descr.stringLength - mapped_length;
894 nextrun->descr.string = &layout->str[nextrun->descr.textPosition];
895 run->descr.stringLength = mapped_length;
896 list_add_after(&r->entry, &nextr->entry);
897 r = nextr;
900 length -= mapped_length;
904 IDWriteFontFallback_Release(fallback);
906 /* fill run info */
907 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
908 DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props = NULL;
909 DWRITE_SHAPING_TEXT_PROPERTIES *text_props = NULL;
910 struct regular_layout_run *run = &r->u.regular;
911 DWRITE_FONT_METRICS fontmetrics = { 0 };
912 UINT32 max_count;
914 /* we need to do very little in case of inline objects */
915 if (r->kind == LAYOUT_RUN_INLINE) {
916 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[cluster];
917 struct layout_cluster *c = &layout->clusters[cluster];
918 DWRITE_INLINE_OBJECT_METRICS inlinemetrics;
920 metrics->width = 0.0f;
921 metrics->length = r->u.object.length;
922 metrics->canWrapLineAfter = 0;
923 metrics->isWhitespace = 0;
924 metrics->isNewline = 0;
925 metrics->isSoftHyphen = 0;
926 metrics->isRightToLeft = 0;
927 metrics->padding = 0;
928 c->run = r;
929 c->position = 0; /* there's always one cluster per inline object, so 0 is valid value */
930 cluster++;
932 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
933 hr = IDWriteInlineObject_GetMetrics(r->u.object.object, &inlinemetrics);
934 if (FAILED(hr)) {
935 memset(&inlinemetrics, 0, sizeof(inlinemetrics));
936 hr = S_OK;
938 metrics->width = inlinemetrics.width;
939 r->baseline = inlinemetrics.baseline;
940 r->height = inlinemetrics.height;
942 /* FIXME: use resolved breakpoints in this case too */
944 continue;
947 range = get_layout_range_by_pos(layout, run->descr.textPosition);
948 run->descr.localeName = range->locale;
949 run->clustermap = heap_alloc(run->descr.stringLength*sizeof(UINT16));
951 max_count = 3*run->descr.stringLength/2 + 16;
952 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
953 if (!run->clustermap || !run->glyphs)
954 goto memerr;
956 text_props = heap_alloc(run->descr.stringLength*sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
957 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
958 if (!text_props || !glyph_props)
959 goto memerr;
961 while (1) {
962 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, run->descr.string, run->descr.stringLength,
963 run->run.fontFace, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
964 NULL /* FIXME */, NULL, NULL, 0, max_count, run->clustermap, text_props, run->glyphs, glyph_props,
965 &run->glyphcount);
966 if (hr == E_NOT_SUFFICIENT_BUFFER) {
967 heap_free(run->glyphs);
968 heap_free(glyph_props);
970 max_count = run->glyphcount;
972 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
973 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
974 if (!run->glyphs || !glyph_props)
975 goto memerr;
977 continue;
980 break;
983 if (FAILED(hr)) {
984 heap_free(text_props);
985 heap_free(glyph_props);
986 WARN("%s: shaping failed 0x%08x\n", debugstr_rundescr(&run->descr), hr);
987 continue;
990 run->run.glyphIndices = run->glyphs;
991 run->descr.clusterMap = run->clustermap;
993 run->advances = heap_alloc(run->glyphcount*sizeof(FLOAT));
994 run->offsets = heap_alloc(run->glyphcount*sizeof(DWRITE_GLYPH_OFFSET));
995 if (!run->advances || !run->offsets)
996 goto memerr;
998 /* now set advances and offsets */
999 if (is_layout_gdi_compatible(layout))
1000 hr = IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap,
1001 text_props, run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount,
1002 run->run.fontFace, run->run.fontEmSize, layout->ppdip, &layout->transform,
1003 layout->measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->run.isSideways,
1004 run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL, NULL, 0, run->advances, run->offsets);
1005 else
1006 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap, text_props,
1007 run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount, run->run.fontFace,
1008 run->run.fontEmSize, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
1009 NULL, NULL, 0, run->advances, run->offsets);
1011 heap_free(text_props);
1012 heap_free(glyph_props);
1013 if (FAILED(hr))
1014 WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_rundescr(&run->descr), hr);
1016 run->run.glyphAdvances = run->advances;
1017 run->run.glyphOffsets = run->offsets;
1019 /* Special treatment for runs that don't produce visual output, shaping code adds normal glyphs for them,
1020 with valid cluster map and potentially with non-zero advances; layout code exposes those as zero width clusters. */
1021 if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL)
1022 run->run.glyphCount = 0;
1023 else
1024 run->run.glyphCount = run->glyphcount;
1026 /* baseline derived from font metrics */
1027 layout_get_font_metrics(layout, run->run.fontFace, run->run.fontEmSize, &fontmetrics);
1028 layout_get_font_height(run->run.fontEmSize, &fontmetrics, &r->baseline, &r->height);
1030 layout_set_cluster_metrics(layout, r, &cluster);
1031 continue;
1033 memerr:
1034 heap_free(text_props);
1035 heap_free(glyph_props);
1036 heap_free(run->clustermap);
1037 heap_free(run->glyphs);
1038 heap_free(run->advances);
1039 heap_free(run->offsets);
1040 run->advances = NULL;
1041 run->offsets = NULL;
1042 run->clustermap = run->glyphs = NULL;
1043 hr = E_OUTOFMEMORY;
1044 break;
1047 if (hr == S_OK) {
1048 layout->cluster_count = cluster;
1049 if (cluster)
1050 layout->clustermetrics[cluster-1].canWrapLineAfter = 1;
1053 IDWriteTextAnalyzer_Release(analyzer);
1054 return hr;
1057 static HRESULT layout_compute(struct dwrite_textlayout *layout)
1059 HRESULT hr;
1061 if (!(layout->recompute & RECOMPUTE_CLUSTERS))
1062 return S_OK;
1064 /* nominal breakpoints are evaluated only once, because string never changes */
1065 if (!layout->nominal_breakpoints) {
1066 IDWriteTextAnalyzer *analyzer;
1067 HRESULT hr;
1069 layout->nominal_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
1070 if (!layout->nominal_breakpoints)
1071 return E_OUTOFMEMORY;
1073 hr = get_textanalyzer(&analyzer);
1074 if (FAILED(hr))
1075 return hr;
1077 hr = IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer, (IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
1078 0, layout->len, (IDWriteTextAnalysisSink*)&layout->IDWriteTextAnalysisSink1_iface);
1079 IDWriteTextAnalyzer_Release(analyzer);
1081 if (layout->actual_breakpoints) {
1082 heap_free(layout->actual_breakpoints);
1083 layout->actual_breakpoints = NULL;
1086 hr = layout_compute_runs(layout);
1088 if (TRACE_ON(dwrite)) {
1089 struct layout_run *cur;
1091 LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
1092 if (cur->kind == LAYOUT_RUN_INLINE)
1093 TRACE("run inline object %p, len %u\n", cur->u.object.object, cur->u.object.length);
1094 else
1095 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur->u.regular.descr.textPosition, cur->u.regular.descr.textPosition +
1096 cur->u.regular.descr.stringLength-1, cur->u.regular.descr.stringLength, cur->u.regular.run.bidiLevel);
1100 layout->recompute &= ~RECOMPUTE_CLUSTERS;
1101 return hr;
1104 static inline FLOAT get_cluster_range_width(struct dwrite_textlayout *layout, UINT32 start, UINT32 end)
1106 FLOAT width = 0.0f;
1107 for (; start < end; start++)
1108 width += layout->clustermetrics[start].width;
1109 return width;
1112 static struct layout_range_header *get_layout_range_header_by_pos(struct list *ranges, UINT32 pos)
1114 struct layout_range_header *cur;
1116 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
1117 DWRITE_TEXT_RANGE *r = &cur->range;
1118 if (r->startPosition <= pos && pos < r->startPosition + r->length)
1119 return cur;
1122 return NULL;
1125 static inline IUnknown *layout_get_effect_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1127 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->effects, pos);
1128 return ((struct layout_range_iface*)h)->iface;
1131 static inline BOOL layout_is_erun_rtl(const struct layout_effective_run *erun)
1133 return erun->run->u.regular.run.bidiLevel & 1;
1136 /* A set of parameters that additionally splits resulting runs. It happens after shaping and all text processing,
1137 no glyph changes are possible. It's understandable for drawing effects, because DrawGlyphRun() reports them as
1138 one of the arguments, but it also happens for decorations, so every effective run has uniform
1139 underline/strikethough/effect tuple. */
1140 struct layout_final_splitting_params {
1141 BOOL strikethrough;
1142 BOOL underline;
1143 IUnknown *effect;
1146 static inline BOOL layout_get_strikethrough_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1148 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->strike_ranges, pos);
1149 return ((struct layout_range_bool*)h)->value;
1152 static inline BOOL layout_get_underline_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1154 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->underline_ranges, pos);
1155 return ((struct layout_range_bool*)h)->value;
1158 static void layout_splitting_params_from_pos(struct dwrite_textlayout *layout, UINT32 pos,
1159 struct layout_final_splitting_params *params)
1161 params->strikethrough = layout_get_strikethrough_from_pos(layout, pos);
1162 params->underline = layout_get_underline_from_pos(layout, pos);
1163 params->effect = layout_get_effect_from_pos(layout, pos);
1166 static BOOL is_same_splitting_params(const struct layout_final_splitting_params *left,
1167 const struct layout_final_splitting_params *right)
1169 return left->strikethrough == right->strikethrough &&
1170 left->underline == right->underline &&
1171 left->effect == right->effect;
1174 static void layout_get_erun_font_metrics(struct dwrite_textlayout *layout, struct layout_effective_run *erun,
1175 DWRITE_FONT_METRICS *metrics)
1177 memset(metrics, 0, sizeof(*metrics));
1178 if (is_layout_gdi_compatible(layout)) {
1179 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(
1180 erun->run->u.regular.run.fontFace,
1181 erun->run->u.regular.run.fontEmSize,
1182 layout->ppdip,
1183 &layout->transform,
1184 metrics);
1185 if (FAILED(hr))
1186 WARN("failed to get font metrics, 0x%08x\n", hr);
1188 else
1189 IDWriteFontFace_GetMetrics(erun->run->u.regular.run.fontFace, metrics);
1192 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
1193 'cluster_count' indicates how many clusters to add, including first one. */
1194 static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 first_cluster,
1195 UINT32 cluster_count, UINT32 line, FLOAT origin_x, struct layout_final_splitting_params *params)
1197 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1198 UINT32 i, start, length, last_cluster;
1199 struct layout_effective_run *run;
1201 if (r->kind == LAYOUT_RUN_INLINE) {
1202 struct layout_effective_inline *inlineobject;
1204 inlineobject = heap_alloc(sizeof(*inlineobject));
1205 if (!inlineobject)
1206 return E_OUTOFMEMORY;
1208 inlineobject->run = r;
1209 inlineobject->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1210 inlineobject->origin_x = is_rtl ? origin_x - inlineobject->width : origin_x;
1211 inlineobject->origin_y = 0.0f; /* set after line is built */
1212 inlineobject->align_dx = 0.0f;
1214 /* It's not clear how these two are set, possibly directionality
1215 is derived from surrounding text (replaced text could have
1216 different ranges which differ in reading direction). */
1217 inlineobject->is_sideways = FALSE;
1218 inlineobject->is_rtl = FALSE;
1219 inlineobject->line = line;
1221 /* effect assigned from start position and on is used for inline objects */
1222 inlineobject->effect = layout_get_effect_from_pos(layout, layout->clusters[first_cluster].position);
1224 list_add_tail(&layout->inlineobjects, &inlineobject->entry);
1225 return S_OK;
1228 run = heap_alloc(sizeof(*run));
1229 if (!run)
1230 return E_OUTOFMEMORY;
1232 /* No need to iterate for that, use simple fact that:
1233 <last cluster position> = first cluster position> + <sum of cluster lengths not including last one> */
1234 last_cluster = first_cluster + cluster_count - 1;
1235 length = layout->clusters[last_cluster].position - layout->clusters[first_cluster].position +
1236 layout->clustermetrics[last_cluster].length;
1238 run->clustermap = heap_alloc(sizeof(UINT16)*length);
1239 if (!run->clustermap) {
1240 heap_free(run);
1241 return E_OUTOFMEMORY;
1244 run->run = r;
1245 run->start = start = layout->clusters[first_cluster].position;
1246 run->length = length;
1247 run->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1249 /* Check if run direction matches paragraph direction, if it doesn't adjust by
1250 run width */
1251 if (layout_is_erun_rtl(run) ^ is_rtl)
1252 run->origin_x = is_rtl ? origin_x - run->width : origin_x + run->width;
1253 else
1254 run->origin_x = origin_x;
1256 run->origin_y = 0.0f; /* set after line is built */
1257 run->align_dx = 0.0f;
1258 run->line = line;
1260 if (r->u.regular.run.glyphCount) {
1261 /* trim from the left */
1262 run->glyphcount = r->u.regular.run.glyphCount - r->u.regular.clustermap[start];
1263 /* trim from the right */
1264 if (start + length < r->u.regular.descr.stringLength - 1)
1265 run->glyphcount -= r->u.regular.run.glyphCount - r->u.regular.clustermap[start + length];
1267 else
1268 run->glyphcount = 0;
1270 /* cluster map needs to be shifted */
1271 for (i = 0; i < length; i++)
1272 run->clustermap[i] = r->u.regular.clustermap[start + i] - r->u.regular.clustermap[start];
1274 run->effect = params->effect;
1275 run->underlined = params->underline;
1276 list_add_tail(&layout->eruns, &run->entry);
1278 /* Strikethrough style is guaranteed to be consistent within effective run,
1279 its width equals to run width, thickness and offset are derived from
1280 font metrics, rest of the values are from layout or run itself */
1281 if (params->strikethrough) {
1282 struct layout_strikethrough *s;
1283 DWRITE_FONT_METRICS metrics;
1285 s = heap_alloc(sizeof(*s));
1286 if (!s)
1287 return E_OUTOFMEMORY;
1289 layout_get_erun_font_metrics(layout, run, &metrics);
1290 s->s.width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1291 s->s.thickness = SCALE_FONT_METRIC(metrics.strikethroughThickness, r->u.regular.run.fontEmSize, &metrics);
1292 /* Negative offset moves it above baseline as Y coordinate grows downward. */
1293 s->s.offset = -SCALE_FONT_METRIC(metrics.strikethroughPosition, r->u.regular.run.fontEmSize, &metrics);
1294 s->s.readingDirection = layout->format.readingdir;
1295 s->s.flowDirection = layout->format.flow;
1296 s->s.localeName = r->u.regular.descr.localeName;
1297 s->s.measuringMode = layout->measuringmode;
1298 s->run = run;
1300 list_add_tail(&layout->strikethrough, &s->entry);
1303 return S_OK;
1306 static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_LINE_METRICS1 *metrics, UINT32 *line)
1308 if (!layout->line_alloc) {
1309 layout->line_alloc = 5;
1310 layout->lines = heap_alloc(layout->line_alloc*sizeof(*layout->lines));
1311 if (!layout->lines)
1312 return E_OUTOFMEMORY;
1315 if (layout->metrics.lineCount == layout->line_alloc) {
1316 DWRITE_LINE_METRICS1 *l = heap_realloc(layout->lines, layout->line_alloc*2*sizeof(*layout->lines));
1317 if (!l)
1318 return E_OUTOFMEMORY;
1319 layout->lines = l;
1320 layout->line_alloc *= 2;
1323 layout->lines[*line] = *metrics;
1324 layout->metrics.lineCount += 1;
1325 *line += 1;
1326 return S_OK;
1330 static inline struct layout_effective_run *layout_get_next_erun(struct dwrite_textlayout *layout,
1331 const struct layout_effective_run *cur)
1333 struct list *e;
1335 if (!cur)
1336 e = list_head(&layout->eruns);
1337 else
1338 e = list_next(&layout->eruns, &cur->entry);
1339 if (!e)
1340 return NULL;
1341 return LIST_ENTRY(e, struct layout_effective_run, entry);
1344 static inline struct layout_effective_run *layout_get_prev_erun(struct dwrite_textlayout *layout,
1345 const struct layout_effective_run *cur)
1347 struct list *e;
1349 if (!cur)
1350 e = list_tail(&layout->eruns);
1351 else
1352 e = list_prev(&layout->eruns, &cur->entry);
1353 if (!e)
1354 return NULL;
1355 return LIST_ENTRY(e, struct layout_effective_run, entry);
1358 static inline struct layout_effective_inline *layout_get_next_inline_run(struct dwrite_textlayout *layout,
1359 const struct layout_effective_inline *cur)
1361 struct list *e;
1363 if (!cur)
1364 e = list_head(&layout->inlineobjects);
1365 else
1366 e = list_next(&layout->inlineobjects, &cur->entry);
1367 if (!e)
1368 return NULL;
1369 return LIST_ENTRY(e, struct layout_effective_inline, entry);
1372 static FLOAT layout_get_line_width(struct dwrite_textlayout *layout,
1373 struct layout_effective_run *erun, struct layout_effective_inline *inrun, UINT32 line)
1375 FLOAT width = 0.0f;
1377 while (erun && erun->line == line) {
1378 width += erun->width;
1379 erun = layout_get_next_erun(layout, erun);
1380 if (!erun)
1381 break;
1384 while (inrun && inrun->line == line) {
1385 width += inrun->width;
1386 inrun = layout_get_next_inline_run(layout, inrun);
1387 if (!inrun)
1388 break;
1391 return width;
1394 static inline BOOL should_skip_transform(const DWRITE_MATRIX *m, FLOAT *det)
1396 *det = m->m11 * m->m22 - m->m12 * m->m21;
1397 /* on certain conditions we can skip transform */
1398 return (!memcmp(m, &identity, sizeof(*m)) || fabsf(*det) <= 1e-10f);
1401 static inline void layout_apply_snapping(struct dwrite_vec *vec, BOOL skiptransform, FLOAT ppdip,
1402 const DWRITE_MATRIX *m, FLOAT det)
1404 if (!skiptransform) {
1405 FLOAT vec2[2];
1407 /* apply transform */
1408 vec->x *= ppdip;
1409 vec->y *= ppdip;
1411 vec2[0] = m->m11 * vec->x + m->m21 * vec->y + m->dx;
1412 vec2[1] = m->m12 * vec->x + m->m22 * vec->y + m->dy;
1414 /* snap */
1415 vec2[0] = floorf(vec2[0] + 0.5f);
1416 vec2[1] = floorf(vec2[1] + 0.5f);
1418 /* apply inverted transform, we don't care about X component at this point */
1419 vec->x = (m->m22 * vec2[0] - m->m21 * vec2[1] + m->m21 * m->dy - m->m22 * m->dx) / det;
1420 vec->x /= ppdip;
1422 vec->y = (-m->m12 * vec2[0] + m->m11 * vec2[1] - (m->m11 * m->dy - m->m12 * m->dx)) / det;
1423 vec->y /= ppdip;
1425 else {
1426 vec->x = floorf(vec->x * ppdip + 0.5f) / ppdip;
1427 vec->y = floorf(vec->y * ppdip + 0.5f) / ppdip;
1431 static void layout_apply_leading_alignment(struct dwrite_textlayout *layout)
1433 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1434 struct layout_effective_inline *inrun;
1435 struct layout_effective_run *erun;
1437 erun = layout_get_next_erun(layout, NULL);
1438 inrun = layout_get_next_inline_run(layout, NULL);
1440 while (erun) {
1441 erun->align_dx = 0.0f;
1442 erun = layout_get_next_erun(layout, erun);
1445 while (inrun) {
1446 inrun->align_dx = 0.0f;
1447 inrun = layout_get_next_inline_run(layout, inrun);
1450 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
1453 static void layout_apply_trailing_alignment(struct dwrite_textlayout *layout)
1455 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1456 struct layout_effective_inline *inrun;
1457 struct layout_effective_run *erun;
1458 UINT32 line;
1460 erun = layout_get_next_erun(layout, NULL);
1461 inrun = layout_get_next_inline_run(layout, NULL);
1463 for (line = 0; line < layout->metrics.lineCount; line++) {
1464 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1465 FLOAT shift = layout->metrics.layoutWidth - width;
1467 if (is_rtl)
1468 shift *= -1.0f;
1470 while (erun && erun->line == line) {
1471 erun->align_dx = shift;
1472 erun = layout_get_next_erun(layout, erun);
1475 while (inrun && inrun->line == line) {
1476 inrun->align_dx = shift;
1477 inrun = layout_get_next_inline_run(layout, inrun);
1481 layout->metrics.left = is_rtl ? 0.0f : layout->metrics.layoutWidth - layout->metrics.width;
1484 static inline FLOAT layout_get_centered_shift(struct dwrite_textlayout *layout, BOOL skiptransform,
1485 FLOAT width, FLOAT det)
1487 if (is_layout_gdi_compatible(layout)) {
1488 struct dwrite_vec vec = { layout->metrics.layoutWidth - width, 0.0f};
1489 layout_apply_snapping(&vec, skiptransform, layout->ppdip, &layout->transform, det);
1490 return floorf(vec.x / 2.0f);
1492 else
1493 return (layout->metrics.layoutWidth - width) / 2.0f;
1496 static void layout_apply_centered_alignment(struct dwrite_textlayout *layout)
1498 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1499 struct layout_effective_inline *inrun;
1500 struct layout_effective_run *erun;
1501 BOOL skiptransform;
1502 UINT32 line;
1503 FLOAT det;
1505 erun = layout_get_next_erun(layout, NULL);
1506 inrun = layout_get_next_inline_run(layout, NULL);
1508 skiptransform = should_skip_transform(&layout->transform, &det);
1510 for (line = 0; line < layout->metrics.lineCount; line++) {
1511 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1512 FLOAT shift = layout_get_centered_shift(layout, skiptransform, width, det);
1514 if (is_rtl)
1515 shift *= -1.0f;
1517 while (erun && erun->line == line) {
1518 erun->align_dx = shift;
1519 erun = layout_get_next_erun(layout, erun);
1522 while (inrun && inrun->line == line) {
1523 inrun->align_dx = shift;
1524 inrun = layout_get_next_inline_run(layout, inrun);
1528 layout->metrics.left = (layout->metrics.layoutWidth - layout->metrics.width) / 2.0f;
1531 static void layout_apply_text_alignment(struct dwrite_textlayout *layout)
1533 switch (layout->format.textalignment)
1535 case DWRITE_TEXT_ALIGNMENT_LEADING:
1536 layout_apply_leading_alignment(layout);
1537 break;
1538 case DWRITE_TEXT_ALIGNMENT_TRAILING:
1539 layout_apply_trailing_alignment(layout);
1540 break;
1541 case DWRITE_TEXT_ALIGNMENT_CENTER:
1542 layout_apply_centered_alignment(layout);
1543 break;
1544 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED:
1545 FIXME("alignment %d not implemented\n", layout->format.textalignment);
1546 break;
1547 default:
1552 static void layout_apply_par_alignment(struct dwrite_textlayout *layout)
1554 struct layout_effective_inline *inrun;
1555 struct layout_effective_run *erun;
1556 FLOAT origin_y = 0.0f;
1557 UINT32 line;
1559 /* alignment mode defines origin, after that all run origins are updated
1560 the same way */
1562 switch (layout->format.paralign)
1564 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR:
1565 origin_y = 0.0f;
1566 break;
1567 case DWRITE_PARAGRAPH_ALIGNMENT_FAR:
1568 origin_y = layout->metrics.layoutHeight - layout->metrics.height;
1569 break;
1570 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER:
1571 origin_y = (layout->metrics.layoutHeight - layout->metrics.height) / 2.0f;
1572 break;
1573 default:
1577 layout->metrics.top = origin_y;
1579 erun = layout_get_next_erun(layout, NULL);
1580 inrun = layout_get_next_inline_run(layout, NULL);
1581 for (line = 0; line < layout->metrics.lineCount; line++) {
1582 origin_y += layout->lines[line].baseline;
1584 while (erun && erun->line == line) {
1585 erun->origin_y = origin_y;
1586 erun = layout_get_next_erun(layout, erun);
1589 while (inrun && inrun->line == line) {
1590 inrun->origin_y = origin_y - inrun->run->baseline;
1591 inrun = layout_get_next_inline_run(layout, inrun);
1596 struct layout_underline_splitting_params {
1597 const WCHAR *locale; /* points to range data, no additional allocation */
1598 IUnknown *effect; /* does not hold another reference */
1601 static void init_u_splitting_params_from_erun(struct layout_effective_run *erun,
1602 struct layout_underline_splitting_params *params)
1604 params->locale = erun->run->u.regular.descr.localeName;
1605 params->effect = erun->effect;
1608 static BOOL is_same_u_splitting(struct layout_underline_splitting_params *left,
1609 struct layout_underline_splitting_params *right)
1611 return left->effect == right->effect && !strcmpiW(left->locale, right->locale);
1614 static HRESULT layout_add_underline(struct dwrite_textlayout *layout, struct layout_effective_run *first,
1615 struct layout_effective_run *last)
1617 struct layout_effective_run *cur;
1618 DWRITE_FONT_METRICS metrics;
1619 FLOAT thickness, offset;
1621 if (first == layout_get_prev_erun(layout, last)) {
1622 layout_get_erun_font_metrics(layout, first, &metrics);
1623 thickness = SCALE_FONT_METRIC(metrics.underlineThickness, first->run->u.regular.run.fontEmSize, &metrics);
1624 offset = SCALE_FONT_METRIC(metrics.underlinePosition, first->run->u.regular.run.fontEmSize, &metrics);
1626 else {
1627 FLOAT width = 0.0f;
1629 /* Single underline is added for consecutive underlined runs. In this case underline parameters are
1630 calculated as weighted average, where run width acts as a weight. */
1631 thickness = offset = 0.0f;
1632 cur = first;
1633 do {
1634 layout_get_erun_font_metrics(layout, cur, &metrics);
1636 thickness += SCALE_FONT_METRIC(metrics.underlineThickness, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
1637 offset += SCALE_FONT_METRIC(metrics.underlinePosition, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
1638 width += cur->width;
1640 cur = layout_get_next_erun(layout, cur);
1641 } while (cur != last);
1643 thickness /= width;
1644 offset /= width;
1647 cur = first;
1648 do {
1649 struct layout_underline_splitting_params params, prev_params;
1650 struct layout_effective_run *next, *w;
1651 struct layout_underline *u;
1653 init_u_splitting_params_from_erun(cur, &prev_params);
1654 while ((next = layout_get_next_erun(layout, cur)) != last) {
1655 init_u_splitting_params_from_erun(next, &params);
1656 if (!is_same_u_splitting(&prev_params, &params))
1657 break;
1658 cur = next;
1661 u = heap_alloc(sizeof(*u));
1662 if (!u)
1663 return E_OUTOFMEMORY;
1665 w = cur;
1666 u->u.width = 0.0f;
1667 while (w != next) {
1668 u->u.width += w->width;
1669 w = layout_get_next_erun(layout, w);
1672 u->u.thickness = thickness;
1673 /* Font metrics convention is to have it negative when below baseline, for rendering
1674 however Y grows from baseline down for horizontal baseline. */
1675 u->u.offset = -offset;
1676 u->u.runHeight = 0.0f; /* FIXME */
1677 u->u.readingDirection = is_run_rtl(cur) ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
1678 DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
1679 u->u.flowDirection = layout->format.flow;
1680 u->u.localeName = cur->run->u.regular.descr.localeName;
1681 u->u.measuringMode = layout->measuringmode;
1682 u->run = cur;
1683 list_add_tail(&layout->underlines, &u->entry);
1685 cur = next;
1686 } while (cur != last);
1688 return S_OK;
1691 /* Adds zero width line, metrics are derived from font at specified text position. */
1692 static HRESULT layout_set_dummy_line_metrics(struct dwrite_textlayout *layout, UINT32 pos, UINT32 *line)
1694 DWRITE_FONT_METRICS fontmetrics;
1695 DWRITE_LINE_METRICS1 metrics;
1696 struct layout_range *range;
1697 IDWriteFontFace *fontface;
1698 IDWriteFont *font;
1699 HRESULT hr;
1701 range = get_layout_range_by_pos(layout, pos);
1702 hr = create_matching_font(range->collection,
1703 range->fontfamily,
1704 range->weight,
1705 range->style,
1706 range->stretch,
1707 &font);
1708 if (FAILED(hr))
1709 return hr;
1710 hr = IDWriteFont_CreateFontFace(font, &fontface);
1711 IDWriteFont_Release(font);
1712 if (FAILED(hr))
1713 return hr;
1715 layout_get_font_metrics(layout, fontface, range->fontsize, &fontmetrics);
1716 layout_get_font_height(range->fontsize, &fontmetrics, &metrics.baseline, &metrics.height);
1717 IDWriteFontFace_Release(fontface);
1719 metrics.length = 0;
1720 metrics.trailingWhitespaceLength = 0;
1721 metrics.newlineLength = 0;
1722 metrics.isTrimmed = FALSE;
1723 metrics.leadingBefore = 0.0f;
1724 metrics.leadingAfter = 0.0f;
1725 return layout_set_line_metrics(layout, &metrics, line);
1728 static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
1730 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1731 struct layout_final_splitting_params prev_params, params;
1732 struct layout_effective_run *erun, *first_underlined;
1733 struct layout_effective_inline *inrun;
1734 const struct layout_run *run;
1735 DWRITE_LINE_METRICS1 metrics;
1736 FLOAT width, origin_x, origin_y;
1737 UINT32 i, start, line, textpos;
1738 HRESULT hr;
1740 if (!(layout->recompute & RECOMPUTE_LINES))
1741 return S_OK;
1743 hr = layout_compute(layout);
1744 if (FAILED(hr))
1745 return hr;
1747 layout->metrics.lineCount = 0;
1748 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0f;
1749 line = 0;
1750 memset(&metrics, 0, sizeof(metrics));
1752 layout_splitting_params_from_pos(layout, 0, &params);
1753 prev_params = params;
1755 if (layout->cluster_count)
1756 run = layout->clusters[0].run;
1757 for (i = 0, start = 0, textpos = 0, width = 0.0f; i < layout->cluster_count; i++) {
1758 BOOL overflow;
1760 layout_splitting_params_from_pos(layout, textpos, &params);
1762 /* switched to next nominal run, at this point all previous pending clusters are already
1763 checked for layout line overflow, so new effective run will fit in current line */
1764 if (run != layout->clusters[i].run || !is_same_splitting_params(&prev_params, &params)) {
1765 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, &prev_params);
1766 if (FAILED(hr))
1767 return hr;
1768 origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) :
1769 get_cluster_range_width(layout, start, i);
1770 run = layout->clusters[i].run;
1771 start = i;
1774 overflow = layout->clustermetrics[i].canWrapLineAfter &&
1775 (width + layout->clustermetrics[i].width > layout->metrics.layoutWidth) &&
1776 (layout->format.wrapping != DWRITE_WORD_WRAPPING_NO_WRAP);
1777 /* check if we got new */
1778 if (overflow ||
1779 layout->clustermetrics[i].isNewline || /* always wrap on new line */
1780 i == layout->cluster_count - 1) /* end of the text */ {
1782 UINT32 strlength, last_cluster, index;
1783 FLOAT descent, trailingspacewidth;
1784 struct layout_final_splitting_params *p;
1786 if (!overflow) {
1787 width += layout->clustermetrics[i].width;
1788 metrics.length += layout->clustermetrics[i].length;
1789 last_cluster = i;
1790 p = &params;
1792 else {
1793 last_cluster = i ? i - 1 : i;
1794 p = &prev_params;
1797 if (i >= start) {
1798 hr = layout_add_effective_run(layout, run, start, last_cluster - start + 1, line, origin_x, p);
1799 if (FAILED(hr))
1800 return hr;
1801 /* we don't need to update origin for next run as we're going to wrap */
1804 /* take a look at clusters we got for this line in reverse order to set
1805 trailing properties for current line */
1806 strlength = metrics.length;
1807 index = last_cluster;
1808 trailingspacewidth = 0.0f;
1809 while (strlength) {
1810 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1811 struct layout_cluster *lc = &layout->clusters[index];
1812 WCHAR ch;
1814 /* This also filters out clusters added from inline objects, those are never
1815 treated as a white space. */
1816 if (!cluster->isWhitespace)
1817 break;
1819 /* Every isNewline cluster is also isWhitespace, but not every
1820 newline character cluster has isNewline set, so go back to original string. */
1821 ch = lc->run->u.regular.descr.string[lc->position];
1822 if (cluster->length == 1 && lb_is_newline_char(ch))
1823 metrics.newlineLength += cluster->length;
1825 metrics.trailingWhitespaceLength += cluster->length;
1826 trailingspacewidth += cluster->width;
1828 strlength -= cluster->length;
1829 index--;
1832 /* look for max baseline and descent for this line */
1833 strlength = metrics.length;
1834 index = last_cluster;
1835 metrics.baseline = 0.0f;
1836 descent = 0.0f;
1837 while (strlength) {
1838 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1839 const struct layout_run *cur = layout->clusters[index].run;
1840 FLOAT cur_descent = cur->height - cur->baseline;
1842 if (cur->baseline > metrics.baseline)
1843 metrics.baseline = cur->baseline;
1845 if (cur_descent > descent)
1846 descent = cur_descent;
1848 strlength -= cluster->length;
1849 index--;
1851 metrics.height = descent + metrics.baseline;
1853 if (width > layout->metrics.widthIncludingTrailingWhitespace)
1854 layout->metrics.widthIncludingTrailingWhitespace = width;
1855 if (width - trailingspacewidth > layout->metrics.width)
1856 layout->metrics.width = width - trailingspacewidth;
1858 metrics.isTrimmed = width > layout->metrics.layoutWidth;
1859 hr = layout_set_line_metrics(layout, &metrics, &line);
1860 if (FAILED(hr))
1861 return hr;
1863 width = layout->clustermetrics[i].width;
1864 memset(&metrics, 0, sizeof(metrics));
1865 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0f;
1866 start = i;
1868 else {
1869 metrics.length += layout->clustermetrics[i].length;
1870 width += layout->clustermetrics[i].width;
1873 prev_params = params;
1874 textpos += layout->clustermetrics[i].length;
1877 /* Add dummy line if:
1878 - there's no text, metrics come from first range in this case;
1879 - last ended with a mandatory break, metrics come from last text position.
1881 if (layout->len == 0)
1882 hr = layout_set_dummy_line_metrics(layout, 0, &line);
1883 else if (layout->clustermetrics[layout->cluster_count-1].isNewline)
1884 hr = layout_set_dummy_line_metrics(layout, layout->len-1, &line);
1885 if (FAILED(hr))
1886 return hr;
1888 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
1889 layout->metrics.top = 0.0f;
1890 layout->metrics.maxBidiReorderingDepth = 1; /* FIXME */
1891 layout->metrics.height = 0.0f;
1893 /* Now all line info is here, update effective runs positions in flow direction */
1894 erun = layout_get_next_erun(layout, NULL);
1895 first_underlined = erun && erun->underlined ? erun : NULL;
1897 inrun = layout_get_next_inline_run(layout, NULL);
1899 origin_y = 0.0f;
1900 for (line = 0; line < layout->metrics.lineCount; line++) {
1902 origin_y += layout->lines[line].baseline;
1904 /* For all runs on this line */
1905 while (erun && erun->line == line) {
1906 erun->origin_y = origin_y;
1907 erun = layout_get_next_erun(layout, erun);
1909 if (first_underlined && (!erun || !erun->underlined)) {
1910 layout_add_underline(layout, first_underlined, erun);
1911 first_underlined = NULL;
1913 else if (!first_underlined && erun && erun->underlined)
1914 first_underlined = erun;
1917 /* Same for inline runs */
1918 while (inrun && inrun->line == line) {
1919 inrun->origin_y = origin_y - inrun->run->baseline;
1920 inrun = layout_get_next_inline_run(layout, inrun);
1923 layout->metrics.height += layout->lines[line].height;
1926 /* initial alignment is always leading */
1927 if (layout->format.textalignment != DWRITE_TEXT_ALIGNMENT_LEADING)
1928 layout_apply_text_alignment(layout);
1930 /* initial paragraph alignment is always near */
1931 if (layout->format.paralign != DWRITE_PARAGRAPH_ALIGNMENT_NEAR)
1932 layout_apply_par_alignment(layout);
1934 layout->metrics.heightIncludingTrailingWhitespace = layout->metrics.height; /* FIXME: not true for vertical text */
1936 layout->recompute &= ~RECOMPUTE_LINES;
1937 return hr;
1940 static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
1942 struct layout_range_spacing const *range_spacing = (struct layout_range_spacing*)h;
1943 struct layout_range_iface const *range_iface = (struct layout_range_iface*)h;
1944 struct layout_range_bool const *range_bool = (struct layout_range_bool*)h;
1945 struct layout_range const *range = (struct layout_range*)h;
1947 switch (attr) {
1948 case LAYOUT_RANGE_ATTR_WEIGHT:
1949 return range->weight == value->u.weight;
1950 case LAYOUT_RANGE_ATTR_STYLE:
1951 return range->style == value->u.style;
1952 case LAYOUT_RANGE_ATTR_STRETCH:
1953 return range->stretch == value->u.stretch;
1954 case LAYOUT_RANGE_ATTR_FONTSIZE:
1955 return range->fontsize == value->u.fontsize;
1956 case LAYOUT_RANGE_ATTR_INLINE:
1957 return range->object == value->u.object;
1958 case LAYOUT_RANGE_ATTR_EFFECT:
1959 return range_iface->iface == value->u.effect;
1960 case LAYOUT_RANGE_ATTR_UNDERLINE:
1961 return range_bool->value == value->u.underline;
1962 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
1963 return range_bool->value == value->u.strikethrough;
1964 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
1965 return range->pair_kerning == value->u.pair_kerning;
1966 case LAYOUT_RANGE_ATTR_FONTCOLL:
1967 return range->collection == value->u.collection;
1968 case LAYOUT_RANGE_ATTR_LOCALE:
1969 return strcmpiW(range->locale, value->u.locale) == 0;
1970 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1971 return strcmpW(range->fontfamily, value->u.fontfamily) == 0;
1972 case LAYOUT_RANGE_ATTR_SPACING:
1973 return range_spacing->leading == value->u.spacing[0] &&
1974 range_spacing->trailing == value->u.spacing[1] &&
1975 range_spacing->min_advance == value->u.spacing[2];
1976 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
1977 return range_iface->iface == (IUnknown*)value->u.typography;
1978 default:
1982 return FALSE;
1985 static inline BOOL is_same_layout_attributes(struct layout_range_header const *hleft, struct layout_range_header const *hright)
1987 switch (hleft->kind)
1989 case LAYOUT_RANGE_REGULAR:
1991 struct layout_range const *left = (struct layout_range const*)hleft;
1992 struct layout_range const *right = (struct layout_range const*)hright;
1993 return left->weight == right->weight &&
1994 left->style == right->style &&
1995 left->stretch == right->stretch &&
1996 left->fontsize == right->fontsize &&
1997 left->object == right->object &&
1998 left->pair_kerning == right->pair_kerning &&
1999 left->collection == right->collection &&
2000 !strcmpiW(left->locale, right->locale) &&
2001 !strcmpW(left->fontfamily, right->fontfamily);
2003 case LAYOUT_RANGE_UNDERLINE:
2004 case LAYOUT_RANGE_STRIKETHROUGH:
2006 struct layout_range_bool const *left = (struct layout_range_bool const*)hleft;
2007 struct layout_range_bool const *right = (struct layout_range_bool const*)hright;
2008 return left->value == right->value;
2010 case LAYOUT_RANGE_EFFECT:
2011 case LAYOUT_RANGE_TYPOGRAPHY:
2013 struct layout_range_iface const *left = (struct layout_range_iface const*)hleft;
2014 struct layout_range_iface const *right = (struct layout_range_iface const*)hright;
2015 return left->iface == right->iface;
2017 case LAYOUT_RANGE_SPACING:
2019 struct layout_range_spacing const *left = (struct layout_range_spacing const*)hleft;
2020 struct layout_range_spacing const *right = (struct layout_range_spacing const*)hright;
2021 return left->leading == right->leading &&
2022 left->trailing == right->trailing &&
2023 left->min_advance == right->min_advance;
2025 default:
2026 FIXME("unknown range kind %d\n", hleft->kind);
2027 return FALSE;
2031 static inline BOOL is_same_text_range(const DWRITE_TEXT_RANGE *left, const DWRITE_TEXT_RANGE *right)
2033 return left->startPosition == right->startPosition && left->length == right->length;
2036 /* Allocates range and inits it with default values from text format. */
2037 static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout *layout, const DWRITE_TEXT_RANGE *r,
2038 enum layout_range_kind kind)
2040 struct layout_range_header *h;
2042 switch (kind)
2044 case LAYOUT_RANGE_REGULAR:
2046 struct layout_range *range;
2048 range = heap_alloc(sizeof(*range));
2049 if (!range) return NULL;
2051 range->weight = layout->format.weight;
2052 range->style = layout->format.style;
2053 range->stretch = layout->format.stretch;
2054 range->fontsize = layout->format.fontsize;
2055 range->object = NULL;
2056 range->pair_kerning = FALSE;
2058 range->fontfamily = heap_strdupW(layout->format.family_name);
2059 if (!range->fontfamily) {
2060 heap_free(range);
2061 return NULL;
2064 range->collection = layout->format.collection;
2065 if (range->collection)
2066 IDWriteFontCollection_AddRef(range->collection);
2067 strcpyW(range->locale, layout->format.locale);
2069 h = &range->h;
2070 break;
2072 case LAYOUT_RANGE_UNDERLINE:
2073 case LAYOUT_RANGE_STRIKETHROUGH:
2075 struct layout_range_bool *range;
2077 range = heap_alloc(sizeof(*range));
2078 if (!range) return NULL;
2080 range->value = FALSE;
2081 h = &range->h;
2082 break;
2084 case LAYOUT_RANGE_EFFECT:
2085 case LAYOUT_RANGE_TYPOGRAPHY:
2087 struct layout_range_iface *range;
2089 range = heap_alloc(sizeof(*range));
2090 if (!range) return NULL;
2092 range->iface = NULL;
2093 h = &range->h;
2094 break;
2096 case LAYOUT_RANGE_SPACING:
2098 struct layout_range_spacing *range;
2100 range = heap_alloc(sizeof(*range));
2101 if (!range) return NULL;
2103 range->leading = 0.0f;
2104 range->trailing = 0.0f;
2105 range->min_advance = 0.0f;
2106 h = &range->h;
2107 break;
2109 default:
2110 FIXME("unknown range kind %d\n", kind);
2111 return NULL;
2114 h->kind = kind;
2115 h->range = *r;
2116 return h;
2119 static struct layout_range_header *alloc_layout_range_from(struct layout_range_header *h, const DWRITE_TEXT_RANGE *r)
2121 struct layout_range_header *ret;
2123 switch (h->kind)
2125 case LAYOUT_RANGE_REGULAR:
2127 struct layout_range *from = (struct layout_range*)h;
2129 struct layout_range *range = heap_alloc(sizeof(*range));
2130 if (!range) return NULL;
2132 *range = *from;
2133 range->fontfamily = heap_strdupW(from->fontfamily);
2134 if (!range->fontfamily) {
2135 heap_free(range);
2136 return NULL;
2139 /* update refcounts */
2140 if (range->object)
2141 IDWriteInlineObject_AddRef(range->object);
2142 if (range->collection)
2143 IDWriteFontCollection_AddRef(range->collection);
2144 ret = &range->h;
2145 break;
2147 case LAYOUT_RANGE_UNDERLINE:
2148 case LAYOUT_RANGE_STRIKETHROUGH:
2150 struct layout_range_bool *strike = heap_alloc(sizeof(*strike));
2151 if (!strike) return NULL;
2153 *strike = *(struct layout_range_bool*)h;
2154 ret = &strike->h;
2155 break;
2157 case LAYOUT_RANGE_EFFECT:
2158 case LAYOUT_RANGE_TYPOGRAPHY:
2160 struct layout_range_iface *effect = heap_alloc(sizeof(*effect));
2161 if (!effect) return NULL;
2163 *effect = *(struct layout_range_iface*)h;
2164 if (effect->iface)
2165 IUnknown_AddRef(effect->iface);
2166 ret = &effect->h;
2167 break;
2169 case LAYOUT_RANGE_SPACING:
2171 struct layout_range_spacing *spacing = heap_alloc(sizeof(*spacing));
2172 if (!spacing) return NULL;
2174 *spacing = *(struct layout_range_spacing*)h;
2175 ret = &spacing->h;
2176 break;
2178 default:
2179 FIXME("unknown range kind %d\n", h->kind);
2180 return NULL;
2183 ret->range = *r;
2184 return ret;
2187 static void free_layout_range(struct layout_range_header *h)
2189 if (!h)
2190 return;
2192 switch (h->kind)
2194 case LAYOUT_RANGE_REGULAR:
2196 struct layout_range *range = (struct layout_range*)h;
2198 if (range->object)
2199 IDWriteInlineObject_Release(range->object);
2200 if (range->collection)
2201 IDWriteFontCollection_Release(range->collection);
2202 heap_free(range->fontfamily);
2203 break;
2205 case LAYOUT_RANGE_EFFECT:
2206 case LAYOUT_RANGE_TYPOGRAPHY:
2208 struct layout_range_iface *range = (struct layout_range_iface*)h;
2209 if (range->iface)
2210 IUnknown_Release(range->iface);
2211 break;
2213 default:
2217 heap_free(h);
2220 static void free_layout_ranges_list(struct dwrite_textlayout *layout)
2222 struct layout_range_header *cur, *cur2;
2224 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->ranges, struct layout_range_header, entry) {
2225 list_remove(&cur->entry);
2226 free_layout_range(cur);
2229 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->underline_ranges, struct layout_range_header, entry) {
2230 list_remove(&cur->entry);
2231 free_layout_range(cur);
2234 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->strike_ranges, struct layout_range_header, entry) {
2235 list_remove(&cur->entry);
2236 free_layout_range(cur);
2239 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->effects, struct layout_range_header, entry) {
2240 list_remove(&cur->entry);
2241 free_layout_range(cur);
2244 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->spacing, struct layout_range_header, entry) {
2245 list_remove(&cur->entry);
2246 free_layout_range(cur);
2249 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->typographies, struct layout_range_header, entry) {
2250 list_remove(&cur->entry);
2251 free_layout_range(cur);
2255 static struct layout_range_header *find_outer_range(struct list *ranges, const DWRITE_TEXT_RANGE *range)
2257 struct layout_range_header *cur;
2259 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
2261 if (cur->range.startPosition > range->startPosition)
2262 return NULL;
2264 if ((cur->range.startPosition + cur->range.length < range->startPosition + range->length) &&
2265 (range->startPosition < cur->range.startPosition + cur->range.length))
2266 return NULL;
2267 if (cur->range.startPosition + cur->range.length >= range->startPosition + range->length)
2268 return cur;
2271 return NULL;
2274 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos)
2276 struct layout_range *cur;
2278 LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, h.entry) {
2279 DWRITE_TEXT_RANGE *r = &cur->h.range;
2280 if (r->startPosition <= pos && pos < r->startPosition + r->length)
2281 return cur;
2284 return NULL;
2287 static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
2289 if (*dest == value) return FALSE;
2291 if (*dest)
2292 IUnknown_Release(*dest);
2293 *dest = value;
2294 if (*dest)
2295 IUnknown_AddRef(*dest);
2297 return TRUE;
2300 static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2302 struct layout_range_spacing *dest_spacing = (struct layout_range_spacing*)h;
2303 struct layout_range_iface *dest_iface = (struct layout_range_iface*)h;
2304 struct layout_range_bool *dest_bool = (struct layout_range_bool*)h;
2305 struct layout_range *dest = (struct layout_range*)h;
2307 BOOL changed = FALSE;
2309 switch (attr) {
2310 case LAYOUT_RANGE_ATTR_WEIGHT:
2311 changed = dest->weight != value->u.weight;
2312 dest->weight = value->u.weight;
2313 break;
2314 case LAYOUT_RANGE_ATTR_STYLE:
2315 changed = dest->style != value->u.style;
2316 dest->style = value->u.style;
2317 break;
2318 case LAYOUT_RANGE_ATTR_STRETCH:
2319 changed = dest->stretch != value->u.stretch;
2320 dest->stretch = value->u.stretch;
2321 break;
2322 case LAYOUT_RANGE_ATTR_FONTSIZE:
2323 changed = dest->fontsize != value->u.fontsize;
2324 dest->fontsize = value->u.fontsize;
2325 break;
2326 case LAYOUT_RANGE_ATTR_INLINE:
2327 changed = set_layout_range_iface_attr((IUnknown**)&dest->object, (IUnknown*)value->u.object);
2328 break;
2329 case LAYOUT_RANGE_ATTR_EFFECT:
2330 changed = set_layout_range_iface_attr((IUnknown**)&dest_iface->iface, (IUnknown*)value->u.effect);
2331 break;
2332 case LAYOUT_RANGE_ATTR_UNDERLINE:
2333 changed = dest_bool->value != value->u.underline;
2334 dest_bool->value = value->u.underline;
2335 break;
2336 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2337 changed = dest_bool->value != value->u.strikethrough;
2338 dest_bool->value = value->u.strikethrough;
2339 break;
2340 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2341 changed = dest->pair_kerning != value->u.pair_kerning;
2342 dest->pair_kerning = value->u.pair_kerning;
2343 break;
2344 case LAYOUT_RANGE_ATTR_FONTCOLL:
2345 changed = set_layout_range_iface_attr((IUnknown**)&dest->collection, (IUnknown*)value->u.collection);
2346 break;
2347 case LAYOUT_RANGE_ATTR_LOCALE:
2348 changed = strcmpiW(dest->locale, value->u.locale) != 0;
2349 if (changed) {
2350 strcpyW(dest->locale, value->u.locale);
2351 strlwrW(dest->locale);
2353 break;
2354 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2355 changed = strcmpW(dest->fontfamily, value->u.fontfamily) != 0;
2356 if (changed) {
2357 heap_free(dest->fontfamily);
2358 dest->fontfamily = heap_strdupW(value->u.fontfamily);
2360 break;
2361 case LAYOUT_RANGE_ATTR_SPACING:
2362 changed = dest_spacing->leading != value->u.spacing[0] ||
2363 dest_spacing->trailing != value->u.spacing[1] ||
2364 dest_spacing->min_advance != value->u.spacing[2];
2365 dest_spacing->leading = value->u.spacing[0];
2366 dest_spacing->trailing = value->u.spacing[1];
2367 dest_spacing->min_advance = value->u.spacing[2];
2368 break;
2369 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2370 changed = set_layout_range_iface_attr((IUnknown**)&dest_iface->iface, (IUnknown*)value->u.typography);
2371 break;
2372 default:
2376 return changed;
2379 static inline BOOL is_in_layout_range(const DWRITE_TEXT_RANGE *outer, const DWRITE_TEXT_RANGE *inner)
2381 return (inner->startPosition >= outer->startPosition) &&
2382 (inner->startPosition + inner->length <= outer->startPosition + outer->length);
2385 static inline HRESULT return_range(const struct layout_range_header *h, DWRITE_TEXT_RANGE *r)
2387 if (r) *r = h->range;
2388 return S_OK;
2391 /* Sets attribute value for given range, does all needed splitting/merging of existing ranges. */
2392 static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2394 struct layout_range_header *cur, *right, *left, *outer;
2395 BOOL changed = FALSE;
2396 struct list *ranges;
2397 DWRITE_TEXT_RANGE r;
2399 /* ignore zero length ranges */
2400 if (value->range.length == 0)
2401 return S_OK;
2403 /* select from ranges lists */
2404 switch (attr)
2406 case LAYOUT_RANGE_ATTR_WEIGHT:
2407 case LAYOUT_RANGE_ATTR_STYLE:
2408 case LAYOUT_RANGE_ATTR_STRETCH:
2409 case LAYOUT_RANGE_ATTR_FONTSIZE:
2410 case LAYOUT_RANGE_ATTR_INLINE:
2411 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2412 case LAYOUT_RANGE_ATTR_FONTCOLL:
2413 case LAYOUT_RANGE_ATTR_LOCALE:
2414 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2415 ranges = &layout->ranges;
2416 break;
2417 case LAYOUT_RANGE_ATTR_UNDERLINE:
2418 ranges = &layout->underline_ranges;
2419 break;
2420 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2421 ranges = &layout->strike_ranges;
2422 break;
2423 case LAYOUT_RANGE_ATTR_EFFECT:
2424 ranges = &layout->effects;
2425 break;
2426 case LAYOUT_RANGE_ATTR_SPACING:
2427 ranges = &layout->spacing;
2428 break;
2429 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2430 ranges = &layout->typographies;
2431 break;
2432 default:
2433 FIXME("unknown attr kind %d\n", attr);
2434 return E_FAIL;
2437 /* If new range is completely within existing range, split existing range in two */
2438 if ((outer = find_outer_range(ranges, &value->range))) {
2440 /* no need to add same range */
2441 if (is_same_layout_attrvalue(outer, attr, value))
2442 return S_OK;
2444 /* for matching range bounds just replace data */
2445 if (is_same_text_range(&outer->range, &value->range)) {
2446 changed = set_layout_range_attrval(outer, attr, value);
2447 goto done;
2450 /* add new range to the left */
2451 if (value->range.startPosition == outer->range.startPosition) {
2452 left = alloc_layout_range_from(outer, &value->range);
2453 if (!left) return E_OUTOFMEMORY;
2455 changed = set_layout_range_attrval(left, attr, value);
2456 list_add_before(&outer->entry, &left->entry);
2457 outer->range.startPosition += value->range.length;
2458 outer->range.length -= value->range.length;
2459 goto done;
2462 /* add new range to the right */
2463 if (value->range.startPosition + value->range.length == outer->range.startPosition + outer->range.length) {
2464 right = alloc_layout_range_from(outer, &value->range);
2465 if (!right) return E_OUTOFMEMORY;
2467 changed = set_layout_range_attrval(right, attr, value);
2468 list_add_after(&outer->entry, &right->entry);
2469 outer->range.length -= value->range.length;
2470 goto done;
2473 r.startPosition = value->range.startPosition + value->range.length;
2474 r.length = outer->range.length + outer->range.startPosition - r.startPosition;
2476 /* right part */
2477 right = alloc_layout_range_from(outer, &r);
2478 /* new range in the middle */
2479 cur = alloc_layout_range_from(outer, &value->range);
2480 if (!right || !cur) {
2481 free_layout_range(right);
2482 free_layout_range(cur);
2483 return E_OUTOFMEMORY;
2486 /* reuse container range as a left part */
2487 outer->range.length = value->range.startPosition - outer->range.startPosition;
2489 /* new part */
2490 set_layout_range_attrval(cur, attr, value);
2492 list_add_after(&outer->entry, &cur->entry);
2493 list_add_after(&cur->entry, &right->entry);
2495 layout->recompute = RECOMPUTE_EVERYTHING;
2496 return S_OK;
2499 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2500 Update all of them. */
2501 left = get_layout_range_header_by_pos(ranges, value->range.startPosition);
2502 if (left->range.startPosition == value->range.startPosition)
2503 changed = set_layout_range_attrval(left, attr, value);
2504 else /* need to split */ {
2505 r.startPosition = value->range.startPosition;
2506 r.length = left->range.length - value->range.startPosition + left->range.startPosition;
2507 left->range.length -= r.length;
2508 cur = alloc_layout_range_from(left, &r);
2509 changed = set_layout_range_attrval(cur, attr, value);
2510 list_add_after(&left->entry, &cur->entry);
2512 cur = LIST_ENTRY(list_next(ranges, &left->entry), struct layout_range_header, entry);
2514 /* for all existing ranges covered by new one update value */
2515 while (cur && is_in_layout_range(&value->range, &cur->range)) {
2516 changed |= set_layout_range_attrval(cur, attr, value);
2517 cur = LIST_ENTRY(list_next(ranges, &cur->entry), struct layout_range_header, entry);
2520 /* it's possible rightmost range intersects */
2521 if (cur && (cur->range.startPosition < value->range.startPosition + value->range.length)) {
2522 r.startPosition = cur->range.startPosition;
2523 r.length = value->range.startPosition + value->range.length - cur->range.startPosition;
2524 left = alloc_layout_range_from(cur, &r);
2525 changed |= set_layout_range_attrval(left, attr, value);
2526 cur->range.startPosition += left->range.length;
2527 cur->range.length -= left->range.length;
2528 list_add_before(&cur->entry, &left->entry);
2531 done:
2532 if (changed) {
2533 struct list *next, *i;
2535 layout->recompute = RECOMPUTE_EVERYTHING;
2536 i = list_head(ranges);
2537 while ((next = list_next(ranges, i))) {
2538 struct layout_range_header *next_range = LIST_ENTRY(next, struct layout_range_header, entry);
2540 cur = LIST_ENTRY(i, struct layout_range_header, entry);
2541 if (is_same_layout_attributes(cur, next_range)) {
2542 /* remove similar range */
2543 cur->range.length += next_range->range.length;
2544 list_remove(next);
2545 free_layout_range(next_range);
2547 else
2548 i = list_next(ranges, i);
2552 return S_OK;
2555 static inline const WCHAR *get_string_attribute_ptr(struct layout_range *range, enum layout_range_attr_kind kind)
2557 const WCHAR *str;
2559 switch (kind) {
2560 case LAYOUT_RANGE_ATTR_LOCALE:
2561 str = range->locale;
2562 break;
2563 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2564 str = range->fontfamily;
2565 break;
2566 default:
2567 str = NULL;
2570 return str;
2573 static HRESULT get_string_attribute_length(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2574 UINT32 *length, DWRITE_TEXT_RANGE *r)
2576 struct layout_range *range;
2577 const WCHAR *str;
2579 range = get_layout_range_by_pos(layout, position);
2580 if (!range) {
2581 *length = 0;
2582 return S_OK;
2585 str = get_string_attribute_ptr(range, kind);
2586 *length = strlenW(str);
2587 return return_range(&range->h, r);
2590 static HRESULT get_string_attribute_value(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2591 WCHAR *ret, UINT32 length, DWRITE_TEXT_RANGE *r)
2593 struct layout_range *range;
2594 const WCHAR *str;
2596 if (length == 0)
2597 return E_INVALIDARG;
2599 ret[0] = 0;
2600 range = get_layout_range_by_pos(layout, position);
2601 if (!range)
2602 return E_INVALIDARG;
2604 str = get_string_attribute_ptr(range, kind);
2605 if (length < strlenW(str) + 1)
2606 return E_NOT_SUFFICIENT_BUFFER;
2608 strcpyW(ret, str);
2609 return return_range(&range->h, r);
2612 static HRESULT WINAPI dwritetextlayout_QueryInterface(IDWriteTextLayout3 *iface, REFIID riid, void **obj)
2614 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2616 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2618 *obj = NULL;
2620 if (IsEqualIID(riid, &IID_IDWriteTextLayout3) ||
2621 IsEqualIID(riid, &IID_IDWriteTextLayout2) ||
2622 IsEqualIID(riid, &IID_IDWriteTextLayout1) ||
2623 IsEqualIID(riid, &IID_IDWriteTextLayout) ||
2624 IsEqualIID(riid, &IID_IUnknown))
2626 *obj = iface;
2628 else if (IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
2629 IsEqualIID(riid, &IID_IDWriteTextFormat))
2630 *obj = &This->IDWriteTextFormat1_iface;
2632 if (*obj) {
2633 IDWriteTextLayout3_AddRef(iface);
2634 return S_OK;
2637 return E_NOINTERFACE;
2640 static ULONG WINAPI dwritetextlayout_AddRef(IDWriteTextLayout3 *iface)
2642 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2643 ULONG ref = InterlockedIncrement(&This->ref);
2644 TRACE("(%p)->(%d)\n", This, ref);
2645 return ref;
2648 static ULONG WINAPI dwritetextlayout_Release(IDWriteTextLayout3 *iface)
2650 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2651 ULONG ref = InterlockedDecrement(&This->ref);
2653 TRACE("(%p)->(%d)\n", This, ref);
2655 if (!ref) {
2656 IDWriteFactory3_Release(This->factory);
2657 free_layout_ranges_list(This);
2658 free_layout_eruns(This);
2659 free_layout_runs(This);
2660 release_format_data(&This->format);
2661 heap_free(This->nominal_breakpoints);
2662 heap_free(This->actual_breakpoints);
2663 heap_free(This->clustermetrics);
2664 heap_free(This->clusters);
2665 heap_free(This->lines);
2666 heap_free(This->str);
2667 heap_free(This);
2670 return ref;
2673 static HRESULT WINAPI dwritetextlayout_SetTextAlignment(IDWriteTextLayout3 *iface, DWRITE_TEXT_ALIGNMENT alignment)
2675 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2676 return IDWriteTextFormat1_SetTextAlignment(&This->IDWriteTextFormat1_iface, alignment);
2679 static HRESULT WINAPI dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout3 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
2681 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2682 return IDWriteTextFormat1_SetParagraphAlignment(&This->IDWriteTextFormat1_iface, alignment);
2685 static HRESULT WINAPI dwritetextlayout_SetWordWrapping(IDWriteTextLayout3 *iface, DWRITE_WORD_WRAPPING wrapping)
2687 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2688 return IDWriteTextFormat1_SetWordWrapping(&This->IDWriteTextFormat1_iface, wrapping);
2691 static HRESULT WINAPI dwritetextlayout_SetReadingDirection(IDWriteTextLayout3 *iface, DWRITE_READING_DIRECTION direction)
2693 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2694 return IDWriteTextFormat1_SetReadingDirection(&This->IDWriteTextFormat1_iface, direction);
2697 static HRESULT WINAPI dwritetextlayout_SetFlowDirection(IDWriteTextLayout3 *iface, DWRITE_FLOW_DIRECTION direction)
2699 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2700 TRACE("(%p)->(%d)\n", This, direction);
2701 return IDWriteTextFormat1_SetFlowDirection(&This->IDWriteTextFormat1_iface, direction);
2704 static HRESULT WINAPI dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout3 *iface, FLOAT tabstop)
2706 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2707 TRACE("(%p)->(%.2f)\n", This, tabstop);
2708 return IDWriteTextFormat1_SetIncrementalTabStop(&This->IDWriteTextFormat1_iface, tabstop);
2711 static HRESULT WINAPI dwritetextlayout_SetTrimming(IDWriteTextLayout3 *iface, DWRITE_TRIMMING const *trimming,
2712 IDWriteInlineObject *trimming_sign)
2714 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2715 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
2716 return IDWriteTextFormat1_SetTrimming(&This->IDWriteTextFormat1_iface, trimming, trimming_sign);
2719 static HRESULT WINAPI dwritetextlayout_SetLineSpacing(IDWriteTextLayout3 *iface, DWRITE_LINE_SPACING_METHOD spacing,
2720 FLOAT line_spacing, FLOAT baseline)
2722 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2723 TRACE("(%p)->(%d %.2f %.2f)\n", This, spacing, line_spacing, baseline);
2724 return IDWriteTextFormat1_SetLineSpacing(&This->IDWriteTextFormat1_iface, spacing, line_spacing, baseline);
2727 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextlayout_GetTextAlignment(IDWriteTextLayout3 *iface)
2729 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2730 return IDWriteTextFormat1_GetTextAlignment(&This->IDWriteTextFormat1_iface);
2733 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout3 *iface)
2735 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2736 return IDWriteTextFormat1_GetParagraphAlignment(&This->IDWriteTextFormat1_iface);
2739 static DWRITE_WORD_WRAPPING WINAPI dwritetextlayout_GetWordWrapping(IDWriteTextLayout3 *iface)
2741 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2742 return IDWriteTextFormat1_GetWordWrapping(&This->IDWriteTextFormat1_iface);
2745 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_GetReadingDirection(IDWriteTextLayout3 *iface)
2747 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2748 return IDWriteTextFormat1_GetReadingDirection(&This->IDWriteTextFormat1_iface);
2751 static DWRITE_FLOW_DIRECTION WINAPI dwritetextlayout_GetFlowDirection(IDWriteTextLayout3 *iface)
2753 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2754 return IDWriteTextFormat1_GetFlowDirection(&This->IDWriteTextFormat1_iface);
2757 static FLOAT WINAPI dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout3 *iface)
2759 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2760 return IDWriteTextFormat1_GetIncrementalTabStop(&This->IDWriteTextFormat1_iface);
2763 static HRESULT WINAPI dwritetextlayout_GetTrimming(IDWriteTextLayout3 *iface, DWRITE_TRIMMING *options,
2764 IDWriteInlineObject **trimming_sign)
2766 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2767 return IDWriteTextFormat1_GetTrimming(&This->IDWriteTextFormat1_iface, options, trimming_sign);
2770 static HRESULT WINAPI dwritetextlayout_GetLineSpacing(IDWriteTextLayout3 *iface, DWRITE_LINE_SPACING_METHOD *method,
2771 FLOAT *spacing, FLOAT *baseline)
2773 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2774 return IDWriteTextFormat_GetLineSpacing((IDWriteTextFormat*)&This->IDWriteTextFormat1_iface, method, spacing, baseline);
2777 static HRESULT WINAPI dwritetextlayout_GetFontCollection(IDWriteTextLayout3 *iface, IDWriteFontCollection **collection)
2779 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2780 return IDWriteTextFormat1_GetFontCollection(&This->IDWriteTextFormat1_iface, collection);
2783 static UINT32 WINAPI dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout3 *iface)
2785 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2786 return IDWriteTextFormat1_GetFontFamilyNameLength(&This->IDWriteTextFormat1_iface);
2789 static HRESULT WINAPI dwritetextlayout_GetFontFamilyName(IDWriteTextLayout3 *iface, WCHAR *name, UINT32 size)
2791 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2792 return IDWriteTextFormat1_GetFontFamilyName(&This->IDWriteTextFormat1_iface, name, size);
2795 static DWRITE_FONT_WEIGHT WINAPI dwritetextlayout_GetFontWeight(IDWriteTextLayout3 *iface)
2797 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2798 return IDWriteTextFormat1_GetFontWeight(&This->IDWriteTextFormat1_iface);
2801 static DWRITE_FONT_STYLE WINAPI dwritetextlayout_GetFontStyle(IDWriteTextLayout3 *iface)
2803 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2804 return IDWriteTextFormat1_GetFontStyle(&This->IDWriteTextFormat1_iface);
2807 static DWRITE_FONT_STRETCH WINAPI dwritetextlayout_GetFontStretch(IDWriteTextLayout3 *iface)
2809 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2810 return IDWriteTextFormat1_GetFontStretch(&This->IDWriteTextFormat1_iface);
2813 static FLOAT WINAPI dwritetextlayout_GetFontSize(IDWriteTextLayout3 *iface)
2815 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2816 return IDWriteTextFormat1_GetFontSize(&This->IDWriteTextFormat1_iface);
2819 static UINT32 WINAPI dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout3 *iface)
2821 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2822 return IDWriteTextFormat1_GetLocaleNameLength(&This->IDWriteTextFormat1_iface);
2825 static HRESULT WINAPI dwritetextlayout_GetLocaleName(IDWriteTextLayout3 *iface, WCHAR *name, UINT32 size)
2827 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2828 return IDWriteTextFormat1_GetLocaleName(&This->IDWriteTextFormat1_iface, name, size);
2831 static HRESULT WINAPI dwritetextlayout_SetMaxWidth(IDWriteTextLayout3 *iface, FLOAT maxWidth)
2833 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2835 TRACE("(%p)->(%.2f)\n", This, maxWidth);
2837 if (maxWidth < 0.0f)
2838 return E_INVALIDARG;
2840 This->metrics.layoutWidth = maxWidth;
2841 return S_OK;
2844 static HRESULT WINAPI dwritetextlayout_SetMaxHeight(IDWriteTextLayout3 *iface, FLOAT maxHeight)
2846 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2848 TRACE("(%p)->(%.2f)\n", This, maxHeight);
2850 if (maxHeight < 0.0f)
2851 return E_INVALIDARG;
2853 This->metrics.layoutHeight = maxHeight;
2854 return S_OK;
2857 static HRESULT WINAPI dwritetextlayout_SetFontCollection(IDWriteTextLayout3 *iface, IDWriteFontCollection* collection, DWRITE_TEXT_RANGE range)
2859 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2860 struct layout_range_attr_value value;
2862 TRACE("(%p)->(%p %s)\n", This, collection, debugstr_range(&range));
2864 value.range = range;
2865 value.u.collection = collection;
2866 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTCOLL, &value);
2869 static HRESULT WINAPI dwritetextlayout_SetFontFamilyName(IDWriteTextLayout3 *iface, WCHAR const *name, DWRITE_TEXT_RANGE range)
2871 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2872 struct layout_range_attr_value value;
2874 TRACE("(%p)->(%s %s)\n", This, debugstr_w(name), debugstr_range(&range));
2876 if (!name)
2877 return E_INVALIDARG;
2879 value.range = range;
2880 value.u.fontfamily = name;
2881 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTFAMILY, &value);
2884 static HRESULT WINAPI dwritetextlayout_SetFontWeight(IDWriteTextLayout3 *iface, DWRITE_FONT_WEIGHT weight, DWRITE_TEXT_RANGE range)
2886 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2887 struct layout_range_attr_value value;
2889 TRACE("(%p)->(%d %s)\n", This, weight, debugstr_range(&range));
2891 if ((UINT32)weight > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
2892 return E_INVALIDARG;
2894 value.range = range;
2895 value.u.weight = weight;
2896 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_WEIGHT, &value);
2899 static HRESULT WINAPI dwritetextlayout_SetFontStyle(IDWriteTextLayout3 *iface, DWRITE_FONT_STYLE style, DWRITE_TEXT_RANGE range)
2901 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2902 struct layout_range_attr_value value;
2904 TRACE("(%p)->(%d %s)\n", This, style, debugstr_range(&range));
2906 if ((UINT32)style > DWRITE_FONT_STYLE_ITALIC)
2907 return E_INVALIDARG;
2909 value.range = range;
2910 value.u.style = style;
2911 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STYLE, &value);
2914 static HRESULT WINAPI dwritetextlayout_SetFontStretch(IDWriteTextLayout3 *iface, DWRITE_FONT_STRETCH stretch, DWRITE_TEXT_RANGE range)
2916 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2917 struct layout_range_attr_value value;
2919 TRACE("(%p)->(%d %s)\n", This, stretch, debugstr_range(&range));
2921 if (stretch == DWRITE_FONT_STRETCH_UNDEFINED || (UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
2922 return E_INVALIDARG;
2924 value.range = range;
2925 value.u.stretch = stretch;
2926 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRETCH, &value);
2929 static HRESULT WINAPI dwritetextlayout_SetFontSize(IDWriteTextLayout3 *iface, FLOAT size, DWRITE_TEXT_RANGE range)
2931 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2932 struct layout_range_attr_value value;
2934 TRACE("(%p)->(%.2f %s)\n", This, size, debugstr_range(&range));
2936 if (size <= 0.0f)
2937 return E_INVALIDARG;
2939 value.range = range;
2940 value.u.fontsize = size;
2941 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTSIZE, &value);
2944 static HRESULT WINAPI dwritetextlayout_SetUnderline(IDWriteTextLayout3 *iface, BOOL underline, DWRITE_TEXT_RANGE range)
2946 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2947 struct layout_range_attr_value value;
2949 TRACE("(%p)->(%d %s)\n", This, underline, debugstr_range(&range));
2951 value.range = range;
2952 value.u.underline = underline;
2953 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_UNDERLINE, &value);
2956 static HRESULT WINAPI dwritetextlayout_SetStrikethrough(IDWriteTextLayout3 *iface, BOOL strikethrough, DWRITE_TEXT_RANGE range)
2958 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2959 struct layout_range_attr_value value;
2961 TRACE("(%p)->(%d %s)\n", This, strikethrough, debugstr_range(&range));
2963 value.range = range;
2964 value.u.strikethrough = strikethrough;
2965 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRIKETHROUGH, &value);
2968 static HRESULT WINAPI dwritetextlayout_SetDrawingEffect(IDWriteTextLayout3 *iface, IUnknown* effect, DWRITE_TEXT_RANGE range)
2970 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2971 struct layout_range_attr_value value;
2973 TRACE("(%p)->(%p %s)\n", This, effect, debugstr_range(&range));
2975 value.range = range;
2976 value.u.effect = effect;
2977 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_EFFECT, &value);
2980 static HRESULT WINAPI dwritetextlayout_SetInlineObject(IDWriteTextLayout3 *iface, IDWriteInlineObject *object, DWRITE_TEXT_RANGE range)
2982 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2983 struct layout_range_attr_value value;
2985 TRACE("(%p)->(%p %s)\n", This, object, debugstr_range(&range));
2987 value.range = range;
2988 value.u.object = object;
2989 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_INLINE, &value);
2992 static HRESULT WINAPI dwritetextlayout_SetTypography(IDWriteTextLayout3 *iface, IDWriteTypography* typography, DWRITE_TEXT_RANGE range)
2994 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
2995 struct layout_range_attr_value value;
2997 TRACE("(%p)->(%p %s)\n", This, typography, debugstr_range(&range));
2999 value.range = range;
3000 value.u.typography = typography;
3001 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_TYPOGRAPHY, &value);
3004 static HRESULT WINAPI dwritetextlayout_SetLocaleName(IDWriteTextLayout3 *iface, WCHAR const* locale, DWRITE_TEXT_RANGE range)
3006 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3007 struct layout_range_attr_value value;
3009 TRACE("(%p)->(%s %s)\n", This, debugstr_w(locale), debugstr_range(&range));
3011 if (!locale || strlenW(locale) > LOCALE_NAME_MAX_LENGTH-1)
3012 return E_INVALIDARG;
3014 value.range = range;
3015 value.u.locale = locale;
3016 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_LOCALE, &value);
3019 static FLOAT WINAPI dwritetextlayout_GetMaxWidth(IDWriteTextLayout3 *iface)
3021 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3022 TRACE("(%p)\n", This);
3023 return This->metrics.layoutWidth;
3026 static FLOAT WINAPI dwritetextlayout_GetMaxHeight(IDWriteTextLayout3 *iface)
3028 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3029 TRACE("(%p)\n", This);
3030 return This->metrics.layoutHeight;
3033 static HRESULT WINAPI dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout3 *iface, UINT32 position,
3034 IDWriteFontCollection** collection, DWRITE_TEXT_RANGE *r)
3036 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3037 struct layout_range *range;
3039 TRACE("(%p)->(%u %p %p)\n", This, position, collection, r);
3041 if (position >= This->len)
3042 return S_OK;
3044 range = get_layout_range_by_pos(This, position);
3045 *collection = range->collection;
3046 if (*collection)
3047 IDWriteFontCollection_AddRef(*collection);
3049 return return_range(&range->h, r);
3052 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout3 *iface,
3053 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
3055 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3056 TRACE("(%p)->(%d %p %p)\n", This, position, length, r);
3057 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, length, r);
3060 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout3 *iface,
3061 UINT32 position, WCHAR *name, UINT32 length, DWRITE_TEXT_RANGE *r)
3063 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3064 TRACE("(%p)->(%u %p %u %p)\n", This, position, name, length, r);
3065 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, name, length, r);
3068 static HRESULT WINAPI dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout3 *iface,
3069 UINT32 position, DWRITE_FONT_WEIGHT *weight, DWRITE_TEXT_RANGE *r)
3071 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3072 struct layout_range *range;
3074 TRACE("(%p)->(%u %p %p)\n", This, position, weight, r);
3076 if (position >= This->len)
3077 return S_OK;
3079 range = get_layout_range_by_pos(This, position);
3080 *weight = range->weight;
3082 return return_range(&range->h, r);
3085 static HRESULT WINAPI dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout3 *iface,
3086 UINT32 position, DWRITE_FONT_STYLE *style, 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, style, r);
3093 range = get_layout_range_by_pos(This, position);
3094 *style = range->style;
3095 return return_range(&range->h, r);
3098 static HRESULT WINAPI dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout3 *iface,
3099 UINT32 position, DWRITE_FONT_STRETCH *stretch, DWRITE_TEXT_RANGE *r)
3101 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3102 struct layout_range *range;
3104 TRACE("(%p)->(%u %p %p)\n", This, position, stretch, r);
3106 range = get_layout_range_by_pos(This, position);
3107 *stretch = range->stretch;
3108 return return_range(&range->h, r);
3111 static HRESULT WINAPI dwritetextlayout_layout_GetFontSize(IDWriteTextLayout3 *iface,
3112 UINT32 position, FLOAT *size, DWRITE_TEXT_RANGE *r)
3114 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3115 struct layout_range *range;
3117 TRACE("(%p)->(%u %p %p)\n", This, position, size, r);
3119 range = get_layout_range_by_pos(This, position);
3120 *size = range->fontsize;
3121 return return_range(&range->h, r);
3124 static HRESULT WINAPI dwritetextlayout_GetUnderline(IDWriteTextLayout3 *iface,
3125 UINT32 position, BOOL *underline, DWRITE_TEXT_RANGE *r)
3127 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3128 struct layout_range_bool *range;
3130 TRACE("(%p)->(%u %p %p)\n", This, position, underline, r);
3132 range = (struct layout_range_bool*)get_layout_range_header_by_pos(&This->underline_ranges, position);
3133 *underline = range->value;
3135 return return_range(&range->h, r);
3138 static HRESULT WINAPI dwritetextlayout_GetStrikethrough(IDWriteTextLayout3 *iface,
3139 UINT32 position, BOOL *strikethrough, DWRITE_TEXT_RANGE *r)
3141 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3142 struct layout_range_bool *range;
3144 TRACE("(%p)->(%u %p %p)\n", This, position, strikethrough, r);
3146 range = (struct layout_range_bool*)get_layout_range_header_by_pos(&This->strike_ranges, position);
3147 *strikethrough = range->value;
3149 return return_range(&range->h, r);
3152 static HRESULT WINAPI dwritetextlayout_GetDrawingEffect(IDWriteTextLayout3 *iface,
3153 UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r)
3155 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3156 struct layout_range_iface *range;
3158 TRACE("(%p)->(%u %p %p)\n", This, position, effect, r);
3160 range = (struct layout_range_iface*)get_layout_range_header_by_pos(&This->effects, position);
3161 *effect = range->iface;
3162 if (*effect)
3163 IUnknown_AddRef(*effect);
3165 return return_range(&range->h, r);
3168 static HRESULT WINAPI dwritetextlayout_GetInlineObject(IDWriteTextLayout3 *iface,
3169 UINT32 position, IDWriteInlineObject **object, DWRITE_TEXT_RANGE *r)
3171 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3172 struct layout_range *range;
3174 TRACE("(%p)->(%u %p %p)\n", This, position, object, r);
3176 if (position >= This->len)
3177 return S_OK;
3179 range = get_layout_range_by_pos(This, position);
3180 *object = range->object;
3181 if (*object)
3182 IDWriteInlineObject_AddRef(*object);
3184 return return_range(&range->h, r);
3187 static HRESULT WINAPI dwritetextlayout_GetTypography(IDWriteTextLayout3 *iface,
3188 UINT32 position, IDWriteTypography** typography, DWRITE_TEXT_RANGE *r)
3190 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3191 struct layout_range_iface *range;
3193 TRACE("(%p)->(%u %p %p)\n", This, position, typography, r);
3195 range = (struct layout_range_iface*)get_layout_range_header_by_pos(&This->typographies, position);
3196 *typography = (IDWriteTypography*)range->iface;
3197 if (*typography)
3198 IDWriteTypography_AddRef(*typography);
3200 return return_range(&range->h, r);
3203 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout3 *iface,
3204 UINT32 position, UINT32* length, DWRITE_TEXT_RANGE *r)
3206 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3207 TRACE("(%p)->(%u %p %p)\n", This, position, length, r);
3208 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_LOCALE, position, length, r);
3211 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout3 *iface,
3212 UINT32 position, WCHAR* locale, UINT32 length, DWRITE_TEXT_RANGE *r)
3214 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3215 TRACE("(%p)->(%u %p %u %p)\n", This, position, locale, length, r);
3216 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_LOCALE, position, locale, length, r);
3219 static inline FLOAT renderer_apply_snapping(FLOAT coord, BOOL skiptransform, FLOAT ppdip, FLOAT det,
3220 const DWRITE_MATRIX *m)
3222 FLOAT vec[2], vec2[2];
3224 if (!skiptransform) {
3225 /* apply transform */
3226 vec[0] = 0.0f;
3227 vec[1] = coord * ppdip;
3229 vec2[0] = m->m11 * vec[0] + m->m21 * vec[1] + m->dx;
3230 vec2[1] = m->m12 * vec[0] + m->m22 * vec[1] + m->dy;
3232 /* snap */
3233 vec2[0] = floorf(vec2[0] + 0.5f);
3234 vec2[1] = floorf(vec2[1] + 0.5f);
3236 /* apply inverted transform, we don't care about X component at this point */
3237 vec[1] = (-m->m12 * vec2[0] + m->m11 * vec2[1] - (m->m11 * m->dy - m->m12 * m->dx)) / det;
3238 vec[1] /= ppdip;
3240 else
3241 vec[1] = floorf(coord * ppdip + 0.5f) / ppdip;
3243 return vec[1];
3246 static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout3 *iface,
3247 void *context, IDWriteTextRenderer* renderer, FLOAT origin_x, FLOAT origin_y)
3249 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3250 BOOL disabled = FALSE, skiptransform = FALSE;
3251 struct layout_effective_inline *inlineobject;
3252 struct layout_effective_run *run;
3253 struct layout_strikethrough *s;
3254 struct layout_underline *u;
3255 FLOAT det = 0.0f, ppdip = 0.0f;
3256 DWRITE_MATRIX m = { 0 };
3257 HRESULT hr;
3259 TRACE("(%p)->(%p %p %.2f %.2f)\n", This, context, renderer, origin_x, origin_y);
3261 hr = layout_compute_effective_runs(This);
3262 if (FAILED(hr))
3263 return hr;
3265 hr = IDWriteTextRenderer_IsPixelSnappingDisabled(renderer, context, &disabled);
3266 if (FAILED(hr))
3267 return hr;
3269 if (!disabled) {
3270 hr = IDWriteTextRenderer_GetPixelsPerDip(renderer, context, &ppdip);
3271 if (FAILED(hr))
3272 return hr;
3274 hr = IDWriteTextRenderer_GetCurrentTransform(renderer, context, &m);
3275 if (FAILED(hr))
3276 return hr;
3278 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
3279 if (ppdip <= 0.0f ||
3280 (m.m11 * m.m22 != 0.0f && (m.m12 != 0.0f || m.m21 != 0.0f)) ||
3281 (m.m12 * m.m21 != 0.0f && (m.m11 != 0.0f || m.m22 != 0.0f)))
3282 disabled = TRUE;
3283 else
3284 skiptransform = should_skip_transform(&m, &det);
3287 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
3288 /* 1. Regular runs */
3289 LIST_FOR_EACH_ENTRY(run, &This->eruns, struct layout_effective_run, entry) {
3290 const struct regular_layout_run *regular = &run->run->u.regular;
3291 UINT32 start_glyph = regular->clustermap[run->start];
3292 DWRITE_GLYPH_RUN_DESCRIPTION descr;
3293 DWRITE_GLYPH_RUN glyph_run;
3295 /* Everything but cluster map will be reused from nominal run, as we only need
3296 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
3297 it can't be reused because it has to start with 0 index for each reported run. */
3298 glyph_run = regular->run;
3299 glyph_run.glyphCount = run->glyphcount;
3301 /* fixup glyph data arrays */
3302 glyph_run.glyphIndices += start_glyph;
3303 glyph_run.glyphAdvances += start_glyph;
3304 glyph_run.glyphOffsets += start_glyph;
3306 /* description */
3307 descr = regular->descr;
3308 descr.stringLength = run->length;
3309 descr.string += run->start;
3310 descr.clusterMap = run->clustermap;
3311 descr.textPosition += run->start;
3313 /* return value is ignored */
3314 IDWriteTextRenderer_DrawGlyphRun(renderer,
3315 context,
3316 run->origin_x + run->align_dx + origin_x,
3317 SNAP_COORD(run->origin_y + origin_y),
3318 This->measuringmode,
3319 &glyph_run,
3320 &descr,
3321 run->effect);
3324 /* 2. Inline objects */
3325 LIST_FOR_EACH_ENTRY(inlineobject, &This->inlineobjects, struct layout_effective_inline, entry) {
3326 IDWriteTextRenderer_DrawInlineObject(renderer,
3327 context,
3328 inlineobject->origin_x + inlineobject->align_dx + origin_x,
3329 SNAP_COORD(inlineobject->origin_y + origin_y),
3330 inlineobject->run->u.object.object,
3331 inlineobject->is_sideways,
3332 inlineobject->is_rtl,
3333 inlineobject->effect);
3336 /* 3. Underlines */
3337 LIST_FOR_EACH_ENTRY(u, &This->underlines, struct layout_underline, entry) {
3338 IDWriteTextRenderer_DrawUnderline(renderer,
3339 context,
3340 /* horizontal underline always grows from left to right, width is always added to origin regardless of run direction */
3341 (is_run_rtl(u->run) ? u->run->origin_x - u->run->width : u->run->origin_x) + u->run->align_dx + origin_x,
3342 SNAP_COORD(u->run->origin_y + origin_y),
3343 &u->u,
3344 u->run->effect);
3347 /* 4. Strikethrough */
3348 LIST_FOR_EACH_ENTRY(s, &This->strikethrough, struct layout_strikethrough, entry) {
3349 IDWriteTextRenderer_DrawStrikethrough(renderer,
3350 context,
3351 s->run->origin_x + s->run->align_dx + origin_x,
3352 SNAP_COORD(s->run->origin_y + origin_y),
3353 &s->s,
3354 s->run->effect);
3356 #undef SNAP_COORD
3358 return S_OK;
3361 static HRESULT WINAPI dwritetextlayout_GetLineMetrics(IDWriteTextLayout3 *iface,
3362 DWRITE_LINE_METRICS *metrics, UINT32 max_count, UINT32 *count)
3364 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3365 HRESULT hr;
3367 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
3369 hr = layout_compute_effective_runs(This);
3370 if (FAILED(hr))
3371 return hr;
3373 if (metrics) {
3374 UINT32 i, c = min(max_count, This->metrics.lineCount);
3375 for (i = 0; i < c; i++)
3376 memcpy(metrics + i, This->lines + i, sizeof(*metrics));
3379 *count = This->metrics.lineCount;
3380 return max_count >= This->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3383 static HRESULT WINAPI dwritetextlayout_GetMetrics(IDWriteTextLayout3 *iface, DWRITE_TEXT_METRICS *metrics)
3385 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3386 DWRITE_TEXT_METRICS1 metrics1;
3387 HRESULT hr;
3389 TRACE("(%p)->(%p)\n", This, metrics);
3391 hr = IDWriteTextLayout3_GetMetrics(iface, &metrics1);
3392 if (hr == S_OK)
3393 memcpy(metrics, &metrics1, sizeof(*metrics));
3395 return hr;
3398 static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout3 *iface, DWRITE_OVERHANG_METRICS *overhangs)
3400 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3401 FIXME("(%p)->(%p): stub\n", This, overhangs);
3402 return E_NOTIMPL;
3405 static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout3 *iface,
3406 DWRITE_CLUSTER_METRICS *metrics, UINT32 max_count, UINT32 *count)
3408 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3409 HRESULT hr;
3411 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
3413 hr = layout_compute(This);
3414 if (FAILED(hr))
3415 return hr;
3417 if (metrics)
3418 memcpy(metrics, This->clustermetrics, sizeof(DWRITE_CLUSTER_METRICS)*min(max_count, This->cluster_count));
3420 *count = This->cluster_count;
3421 return max_count >= This->cluster_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3424 static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout3 *iface, FLOAT* min_width)
3426 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3427 UINT32 start;
3428 FLOAT width;
3429 HRESULT hr;
3431 TRACE("(%p)->(%p)\n", This, min_width);
3433 if (!min_width)
3434 return E_INVALIDARG;
3436 if (!(This->recompute & RECOMPUTE_MINIMAL_WIDTH))
3437 goto width_done;
3439 *min_width = 0.0f;
3440 hr = layout_compute(This);
3441 if (FAILED(hr))
3442 return hr;
3444 /* Find widest word without emergency breaking between clusters, trailing whitespaces
3445 preceding breaking point do not contribute to word width. */
3446 for (start = 0; start < This->cluster_count;) {
3447 UINT32 end = start, j, next;
3449 /* Last cluster always could be wrapped after. */
3450 while (!This->clustermetrics[end].canWrapLineAfter)
3451 end++;
3452 /* make is so current cluster range that we can wrap after is [start,end) */
3453 end++;
3455 next = end;
3457 /* Ignore trailing whitespace clusters, in case of single space range will
3458 be reduced to empty range, or [start,start+1). */
3459 while (end > start && This->clustermetrics[end-1].isWhitespace)
3460 end--;
3462 /* check if cluster range exceeds last minimal width */
3463 width = 0.0f;
3464 for (j = start; j < end; j++)
3465 width += This->clustermetrics[j].width;
3467 start = next;
3469 if (width > This->minwidth)
3470 This->minwidth = width;
3472 This->recompute &= ~RECOMPUTE_MINIMAL_WIDTH;
3474 width_done:
3475 *min_width = This->minwidth;
3476 return S_OK;
3479 static HRESULT WINAPI dwritetextlayout_HitTestPoint(IDWriteTextLayout3 *iface,
3480 FLOAT pointX, FLOAT pointY, BOOL* is_trailinghit, BOOL* is_inside, DWRITE_HIT_TEST_METRICS *metrics)
3482 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3483 FIXME("(%p)->(%f %f %p %p %p): stub\n", This, pointX, pointY, is_trailinghit, is_inside, metrics);
3484 return E_NOTIMPL;
3487 static HRESULT WINAPI dwritetextlayout_HitTestTextPosition(IDWriteTextLayout3 *iface,
3488 UINT32 textPosition, BOOL is_trailinghit, FLOAT* pointX, FLOAT* pointY, DWRITE_HIT_TEST_METRICS *metrics)
3490 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3491 FIXME("(%p)->(%u %d %p %p %p): stub\n", This, textPosition, is_trailinghit, pointX, pointY, metrics);
3492 return E_NOTIMPL;
3495 static HRESULT WINAPI dwritetextlayout_HitTestTextRange(IDWriteTextLayout3 *iface,
3496 UINT32 textPosition, UINT32 textLength, FLOAT originX, FLOAT originY,
3497 DWRITE_HIT_TEST_METRICS *metrics, UINT32 max_metricscount, UINT32* actual_metricscount)
3499 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3500 FIXME("(%p)->(%u %u %f %f %p %u %p): stub\n", This, textPosition, textLength, originX, originY, metrics,
3501 max_metricscount, actual_metricscount);
3502 return E_NOTIMPL;
3505 static HRESULT WINAPI dwritetextlayout1_SetPairKerning(IDWriteTextLayout3 *iface, BOOL is_pairkerning_enabled,
3506 DWRITE_TEXT_RANGE range)
3508 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3509 struct layout_range_attr_value value;
3511 TRACE("(%p)->(%d %s)\n", This, is_pairkerning_enabled, debugstr_range(&range));
3513 value.range = range;
3514 value.u.pair_kerning = !!is_pairkerning_enabled;
3515 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_PAIR_KERNING, &value);
3518 static HRESULT WINAPI dwritetextlayout1_GetPairKerning(IDWriteTextLayout3 *iface, UINT32 position, BOOL *is_pairkerning_enabled,
3519 DWRITE_TEXT_RANGE *r)
3521 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3522 struct layout_range *range;
3524 TRACE("(%p)->(%u %p %p)\n", This, position, is_pairkerning_enabled, r);
3526 if (position >= This->len)
3527 return S_OK;
3529 range = get_layout_range_by_pos(This, position);
3530 *is_pairkerning_enabled = range->pair_kerning;
3532 return return_range(&range->h, r);
3535 static HRESULT WINAPI dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout3 *iface, FLOAT leading, FLOAT trailing,
3536 FLOAT min_advance, DWRITE_TEXT_RANGE range)
3538 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3539 struct layout_range_attr_value value;
3541 TRACE("(%p)->(%.2f %.2f %.2f %s)\n", This, leading, trailing, min_advance, debugstr_range(&range));
3543 if (min_advance < 0.0f)
3544 return E_INVALIDARG;
3546 value.range = range;
3547 value.u.spacing[0] = leading;
3548 value.u.spacing[1] = trailing;
3549 value.u.spacing[2] = min_advance;
3550 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_SPACING, &value);
3553 static HRESULT WINAPI dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout3 *iface, UINT32 position, FLOAT *leading,
3554 FLOAT *trailing, FLOAT *min_advance, DWRITE_TEXT_RANGE *r)
3556 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3557 struct layout_range_spacing *range;
3559 TRACE("(%p)->(%u %p %p %p %p)\n", This, position, leading, trailing, min_advance, r);
3561 range = (struct layout_range_spacing*)get_layout_range_header_by_pos(&This->spacing, position);
3562 *leading = range->leading;
3563 *trailing = range->trailing;
3564 *min_advance = range->min_advance;
3566 return return_range(&range->h, r);
3569 static HRESULT WINAPI dwritetextlayout2_GetMetrics(IDWriteTextLayout3 *iface, DWRITE_TEXT_METRICS1 *metrics)
3571 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3572 HRESULT hr;
3574 TRACE("(%p)->(%p)\n", This, metrics);
3576 hr = layout_compute_effective_runs(This);
3577 if (FAILED(hr))
3578 return hr;
3580 *metrics = This->metrics;
3581 return S_OK;
3584 static HRESULT WINAPI dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout3 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
3586 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3588 TRACE("(%p)->(%d)\n", This, orientation);
3590 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
3591 return E_INVALIDARG;
3593 This->format.vertical_orientation = orientation;
3594 return S_OK;
3597 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout3 *iface)
3599 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3600 TRACE("(%p)\n", This);
3601 return This->format.vertical_orientation;
3604 static HRESULT WINAPI dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout3 *iface, BOOL lastline_wrapping_enabled)
3606 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3607 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
3608 return IDWriteTextFormat1_SetLastLineWrapping(&This->IDWriteTextFormat1_iface, lastline_wrapping_enabled);
3611 static BOOL WINAPI dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout3 *iface)
3613 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3614 TRACE("(%p)\n", This);
3615 return IDWriteTextFormat1_GetLastLineWrapping(&This->IDWriteTextFormat1_iface);
3618 static HRESULT WINAPI dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout3 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
3620 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3621 TRACE("(%p)->(%d)\n", This, alignment);
3622 return IDWriteTextFormat1_SetOpticalAlignment(&This->IDWriteTextFormat1_iface, alignment);
3625 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout3 *iface)
3627 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3628 TRACE("(%p)\n", This);
3629 return IDWriteTextFormat1_GetOpticalAlignment(&This->IDWriteTextFormat1_iface);
3632 static HRESULT WINAPI dwritetextlayout2_SetFontFallback(IDWriteTextLayout3 *iface, IDWriteFontFallback *fallback)
3634 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3635 TRACE("(%p)->(%p)\n", This, fallback);
3636 return set_fontfallback_for_format(&This->format, fallback);
3639 static HRESULT WINAPI dwritetextlayout2_GetFontFallback(IDWriteTextLayout3 *iface, IDWriteFontFallback **fallback)
3641 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3642 TRACE("(%p)->(%p)\n", This, fallback);
3643 return get_fontfallback_from_format(&This->format, fallback);
3646 static HRESULT WINAPI dwritetextlayout3_InvalidateLayout(IDWriteTextLayout3 *iface)
3648 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3650 TRACE("(%p)\n", This);
3652 This->recompute = RECOMPUTE_EVERYTHING;
3653 return S_OK;
3656 static HRESULT WINAPI dwritetextlayout3_SetLineSpacing(IDWriteTextLayout3 *iface, DWRITE_LINE_SPACING const *spacing)
3658 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3659 BOOL changed;
3660 HRESULT hr;
3662 TRACE("(%p)->(%p)\n", This, spacing);
3664 hr = format_set_linespacing(&This->format, spacing, &changed);
3665 if (FAILED(hr))
3666 return hr;
3668 if (changed)
3669 This->recompute = RECOMPUTE_LINES;
3671 return S_OK;
3674 static HRESULT WINAPI dwritetextlayout3_GetLineSpacing(IDWriteTextLayout3 *iface, DWRITE_LINE_SPACING *spacing)
3676 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3678 TRACE("(%p)->(%p)\n", This, spacing);
3680 *spacing = This->format.spacing;
3681 return S_OK;
3684 static HRESULT WINAPI dwritetextlayout3_GetLineMetrics(IDWriteTextLayout3 *iface, DWRITE_LINE_METRICS1 *metrics,
3685 UINT32 max_count, UINT32 *count)
3687 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
3688 HRESULT hr;
3690 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
3692 hr = layout_compute_effective_runs(This);
3693 if (FAILED(hr))
3694 return hr;
3696 if (metrics)
3697 memcpy(metrics, This->lines, sizeof(*metrics)*min(max_count, This->metrics.lineCount));
3699 *count = This->metrics.lineCount;
3700 return max_count >= This->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3703 static const IDWriteTextLayout3Vtbl dwritetextlayoutvtbl = {
3704 dwritetextlayout_QueryInterface,
3705 dwritetextlayout_AddRef,
3706 dwritetextlayout_Release,
3707 dwritetextlayout_SetTextAlignment,
3708 dwritetextlayout_SetParagraphAlignment,
3709 dwritetextlayout_SetWordWrapping,
3710 dwritetextlayout_SetReadingDirection,
3711 dwritetextlayout_SetFlowDirection,
3712 dwritetextlayout_SetIncrementalTabStop,
3713 dwritetextlayout_SetTrimming,
3714 dwritetextlayout_SetLineSpacing,
3715 dwritetextlayout_GetTextAlignment,
3716 dwritetextlayout_GetParagraphAlignment,
3717 dwritetextlayout_GetWordWrapping,
3718 dwritetextlayout_GetReadingDirection,
3719 dwritetextlayout_GetFlowDirection,
3720 dwritetextlayout_GetIncrementalTabStop,
3721 dwritetextlayout_GetTrimming,
3722 dwritetextlayout_GetLineSpacing,
3723 dwritetextlayout_GetFontCollection,
3724 dwritetextlayout_GetFontFamilyNameLength,
3725 dwritetextlayout_GetFontFamilyName,
3726 dwritetextlayout_GetFontWeight,
3727 dwritetextlayout_GetFontStyle,
3728 dwritetextlayout_GetFontStretch,
3729 dwritetextlayout_GetFontSize,
3730 dwritetextlayout_GetLocaleNameLength,
3731 dwritetextlayout_GetLocaleName,
3732 dwritetextlayout_SetMaxWidth,
3733 dwritetextlayout_SetMaxHeight,
3734 dwritetextlayout_SetFontCollection,
3735 dwritetextlayout_SetFontFamilyName,
3736 dwritetextlayout_SetFontWeight,
3737 dwritetextlayout_SetFontStyle,
3738 dwritetextlayout_SetFontStretch,
3739 dwritetextlayout_SetFontSize,
3740 dwritetextlayout_SetUnderline,
3741 dwritetextlayout_SetStrikethrough,
3742 dwritetextlayout_SetDrawingEffect,
3743 dwritetextlayout_SetInlineObject,
3744 dwritetextlayout_SetTypography,
3745 dwritetextlayout_SetLocaleName,
3746 dwritetextlayout_GetMaxWidth,
3747 dwritetextlayout_GetMaxHeight,
3748 dwritetextlayout_layout_GetFontCollection,
3749 dwritetextlayout_layout_GetFontFamilyNameLength,
3750 dwritetextlayout_layout_GetFontFamilyName,
3751 dwritetextlayout_layout_GetFontWeight,
3752 dwritetextlayout_layout_GetFontStyle,
3753 dwritetextlayout_layout_GetFontStretch,
3754 dwritetextlayout_layout_GetFontSize,
3755 dwritetextlayout_GetUnderline,
3756 dwritetextlayout_GetStrikethrough,
3757 dwritetextlayout_GetDrawingEffect,
3758 dwritetextlayout_GetInlineObject,
3759 dwritetextlayout_GetTypography,
3760 dwritetextlayout_layout_GetLocaleNameLength,
3761 dwritetextlayout_layout_GetLocaleName,
3762 dwritetextlayout_Draw,
3763 dwritetextlayout_GetLineMetrics,
3764 dwritetextlayout_GetMetrics,
3765 dwritetextlayout_GetOverhangMetrics,
3766 dwritetextlayout_GetClusterMetrics,
3767 dwritetextlayout_DetermineMinWidth,
3768 dwritetextlayout_HitTestPoint,
3769 dwritetextlayout_HitTestTextPosition,
3770 dwritetextlayout_HitTestTextRange,
3771 dwritetextlayout1_SetPairKerning,
3772 dwritetextlayout1_GetPairKerning,
3773 dwritetextlayout1_SetCharacterSpacing,
3774 dwritetextlayout1_GetCharacterSpacing,
3775 dwritetextlayout2_GetMetrics,
3776 dwritetextlayout2_SetVerticalGlyphOrientation,
3777 dwritetextlayout2_GetVerticalGlyphOrientation,
3778 dwritetextlayout2_SetLastLineWrapping,
3779 dwritetextlayout2_GetLastLineWrapping,
3780 dwritetextlayout2_SetOpticalAlignment,
3781 dwritetextlayout2_GetOpticalAlignment,
3782 dwritetextlayout2_SetFontFallback,
3783 dwritetextlayout2_GetFontFallback,
3784 dwritetextlayout3_InvalidateLayout,
3785 dwritetextlayout3_SetLineSpacing,
3786 dwritetextlayout3_GetLineSpacing,
3787 dwritetextlayout3_GetLineMetrics
3790 static HRESULT WINAPI dwritetextformat_layout_QueryInterface(IDWriteTextFormat1 *iface, REFIID riid, void **obj)
3792 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3793 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3794 return IDWriteTextLayout3_QueryInterface(&This->IDWriteTextLayout3_iface, riid, obj);
3797 static ULONG WINAPI dwritetextformat_layout_AddRef(IDWriteTextFormat1 *iface)
3799 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3800 return IDWriteTextLayout3_AddRef(&This->IDWriteTextLayout3_iface);
3803 static ULONG WINAPI dwritetextformat_layout_Release(IDWriteTextFormat1 *iface)
3805 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3806 return IDWriteTextLayout3_Release(&This->IDWriteTextLayout3_iface);
3809 static HRESULT WINAPI dwritetextformat_layout_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
3811 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3812 BOOL changed;
3813 HRESULT hr;
3815 TRACE("(%p)->(%d)\n", This, alignment);
3817 hr = format_set_textalignment(&This->format, alignment, &changed);
3818 if (FAILED(hr))
3819 return hr;
3821 /* if layout is not ready there's nothing to align */
3822 if (changed && !(This->recompute & RECOMPUTE_LINES))
3823 layout_apply_text_alignment(This);
3825 return S_OK;
3828 static HRESULT WINAPI dwritetextformat_layout_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
3830 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3831 BOOL changed;
3832 HRESULT hr;
3834 TRACE("(%p)->(%d)\n", This, alignment);
3836 hr = format_set_paralignment(&This->format, alignment, &changed);
3837 if (FAILED(hr))
3838 return hr;
3840 /* if layout is not ready there's nothing to align */
3841 if (changed && !(This->recompute & RECOMPUTE_LINES))
3842 layout_apply_par_alignment(This);
3844 return S_OK;
3847 static HRESULT WINAPI dwritetextformat_layout_SetWordWrapping(IDWriteTextFormat1 *iface, DWRITE_WORD_WRAPPING wrapping)
3849 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3850 BOOL changed;
3851 HRESULT hr;
3853 TRACE("(%p)->(%d)\n", This, wrapping);
3855 hr = format_set_wordwrapping(&This->format, wrapping, &changed);
3856 if (FAILED(hr))
3857 return hr;
3859 if (changed)
3860 This->recompute |= RECOMPUTE_LINES;
3862 return S_OK;
3865 static HRESULT WINAPI dwritetextformat_layout_SetReadingDirection(IDWriteTextFormat1 *iface, DWRITE_READING_DIRECTION direction)
3867 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3868 BOOL changed;
3869 HRESULT hr;
3871 TRACE("(%p)->(%d)\n", This, direction);
3873 hr = format_set_readingdirection(&This->format, direction, &changed);
3874 if (FAILED(hr))
3875 return hr;
3877 if (changed)
3878 This->recompute = RECOMPUTE_EVERYTHING;
3880 return S_OK;
3883 static HRESULT WINAPI dwritetextformat_layout_SetFlowDirection(IDWriteTextFormat1 *iface, DWRITE_FLOW_DIRECTION direction)
3885 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3886 BOOL changed;
3887 HRESULT hr;
3889 TRACE("(%p)->(%d)\n", This, direction);
3891 hr = format_set_flowdirection(&This->format, direction, &changed);
3892 if (FAILED(hr))
3893 return hr;
3895 if (changed)
3896 This->recompute = RECOMPUTE_EVERYTHING;
3898 return S_OK;
3901 static HRESULT WINAPI dwritetextformat_layout_SetIncrementalTabStop(IDWriteTextFormat1 *iface, FLOAT tabstop)
3903 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3904 FIXME("(%p)->(%f): stub\n", This, tabstop);
3905 return E_NOTIMPL;
3908 static HRESULT WINAPI dwritetextformat_layout_SetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING const *trimming,
3909 IDWriteInlineObject *trimming_sign)
3911 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3912 BOOL changed;
3913 HRESULT hr;
3915 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
3917 hr = format_set_trimming(&This->format, trimming, trimming_sign, &changed);
3919 if (changed)
3920 This->recompute |= RECOMPUTE_LINES;
3922 return hr;
3925 static HRESULT WINAPI dwritetextformat_layout_SetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD method,
3926 FLOAT height, FLOAT baseline)
3928 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3929 DWRITE_LINE_SPACING spacing;
3931 TRACE("(%p)->(%d %f %f)\n", This, method, height, baseline);
3933 spacing = This->format.spacing;
3934 spacing.method = method;
3935 spacing.height = height;
3936 spacing.baseline = baseline;
3937 return IDWriteTextLayout3_SetLineSpacing(&This->IDWriteTextLayout3_iface, &spacing);
3940 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_layout_GetTextAlignment(IDWriteTextFormat1 *iface)
3942 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3943 TRACE("(%p)\n", This);
3944 return This->format.textalignment;
3947 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_layout_GetParagraphAlignment(IDWriteTextFormat1 *iface)
3949 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3950 TRACE("(%p)\n", This);
3951 return This->format.paralign;
3954 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_layout_GetWordWrapping(IDWriteTextFormat1 *iface)
3956 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3957 TRACE("(%p)\n", This);
3958 return This->format.wrapping;
3961 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_layout_GetReadingDirection(IDWriteTextFormat1 *iface)
3963 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3964 TRACE("(%p)\n", This);
3965 return This->format.readingdir;
3968 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_layout_GetFlowDirection(IDWriteTextFormat1 *iface)
3970 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3971 TRACE("(%p)\n", This);
3972 return This->format.flow;
3975 static FLOAT WINAPI dwritetextformat_layout_GetIncrementalTabStop(IDWriteTextFormat1 *iface)
3977 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3978 FIXME("(%p): stub\n", This);
3979 return 0.0f;
3982 static HRESULT WINAPI dwritetextformat_layout_GetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING *options,
3983 IDWriteInlineObject **trimming_sign)
3985 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
3987 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
3989 *options = This->format.trimming;
3990 *trimming_sign = This->format.trimmingsign;
3991 if (*trimming_sign)
3992 IDWriteInlineObject_AddRef(*trimming_sign);
3993 return S_OK;
3996 static HRESULT WINAPI dwritetextformat_layout_GetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD *method,
3997 FLOAT *spacing, FLOAT *baseline)
3999 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4001 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
4003 *method = This->format.spacing.method;
4004 *spacing = This->format.spacing.height;
4005 *baseline = This->format.spacing.baseline;
4006 return S_OK;
4009 static HRESULT WINAPI dwritetextformat_layout_GetFontCollection(IDWriteTextFormat1 *iface, IDWriteFontCollection **collection)
4011 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4013 TRACE("(%p)->(%p)\n", This, collection);
4015 *collection = This->format.collection;
4016 if (*collection)
4017 IDWriteFontCollection_AddRef(*collection);
4018 return S_OK;
4021 static UINT32 WINAPI dwritetextformat_layout_GetFontFamilyNameLength(IDWriteTextFormat1 *iface)
4023 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4024 TRACE("(%p)\n", This);
4025 return This->format.family_len;
4028 static HRESULT WINAPI dwritetextformat_layout_GetFontFamilyName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
4030 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4032 TRACE("(%p)->(%p %u)\n", This, name, size);
4034 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
4035 strcpyW(name, This->format.family_name);
4036 return S_OK;
4039 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_layout_GetFontWeight(IDWriteTextFormat1 *iface)
4041 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4042 TRACE("(%p)\n", This);
4043 return This->format.weight;
4046 static DWRITE_FONT_STYLE WINAPI dwritetextformat_layout_GetFontStyle(IDWriteTextFormat1 *iface)
4048 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4049 TRACE("(%p)\n", This);
4050 return This->format.style;
4053 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_layout_GetFontStretch(IDWriteTextFormat1 *iface)
4055 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4056 TRACE("(%p)\n", This);
4057 return This->format.stretch;
4060 static FLOAT WINAPI dwritetextformat_layout_GetFontSize(IDWriteTextFormat1 *iface)
4062 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4063 TRACE("(%p)\n", This);
4064 return This->format.fontsize;
4067 static UINT32 WINAPI dwritetextformat_layout_GetLocaleNameLength(IDWriteTextFormat1 *iface)
4069 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4070 TRACE("(%p)\n", This);
4071 return This->format.locale_len;
4074 static HRESULT WINAPI dwritetextformat_layout_GetLocaleName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
4076 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4078 TRACE("(%p)->(%p %u)\n", This, name, size);
4080 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
4081 strcpyW(name, This->format.locale);
4082 return S_OK;
4085 static HRESULT WINAPI dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat1 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4087 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4088 FIXME("(%p)->(%d): stub\n", This, orientation);
4089 return E_NOTIMPL;
4092 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat1 *iface)
4094 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4095 FIXME("(%p): stub\n", This);
4096 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
4099 static HRESULT WINAPI dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat1 *iface, BOOL lastline_wrapping_enabled)
4101 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4103 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
4105 This->format.last_line_wrapping = !!lastline_wrapping_enabled;
4106 return S_OK;
4109 static BOOL WINAPI dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat1 *iface)
4111 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4112 TRACE("(%p)\n", This);
4113 return This->format.last_line_wrapping;
4116 static HRESULT WINAPI dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat1 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
4118 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4119 TRACE("(%p)->(%d)\n", This, alignment);
4120 return format_set_optical_alignment(&This->format, alignment);
4123 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat1 *iface)
4125 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4126 TRACE("(%p)\n", This);
4127 return This->format.optical_alignment;
4130 static HRESULT WINAPI dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback *fallback)
4132 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4133 TRACE("(%p)->(%p)\n", This, fallback);
4134 return IDWriteTextLayout3_SetFontFallback(&This->IDWriteTextLayout3_iface, fallback);
4137 static HRESULT WINAPI dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback **fallback)
4139 struct dwrite_textlayout *This = impl_layout_from_IDWriteTextFormat1(iface);
4140 TRACE("(%p)->(%p)\n", This, fallback);
4141 return IDWriteTextLayout3_GetFontFallback(&This->IDWriteTextLayout3_iface, fallback);
4144 static const IDWriteTextFormat1Vtbl dwritetextformat1_layout_vtbl = {
4145 dwritetextformat_layout_QueryInterface,
4146 dwritetextformat_layout_AddRef,
4147 dwritetextformat_layout_Release,
4148 dwritetextformat_layout_SetTextAlignment,
4149 dwritetextformat_layout_SetParagraphAlignment,
4150 dwritetextformat_layout_SetWordWrapping,
4151 dwritetextformat_layout_SetReadingDirection,
4152 dwritetextformat_layout_SetFlowDirection,
4153 dwritetextformat_layout_SetIncrementalTabStop,
4154 dwritetextformat_layout_SetTrimming,
4155 dwritetextformat_layout_SetLineSpacing,
4156 dwritetextformat_layout_GetTextAlignment,
4157 dwritetextformat_layout_GetParagraphAlignment,
4158 dwritetextformat_layout_GetWordWrapping,
4159 dwritetextformat_layout_GetReadingDirection,
4160 dwritetextformat_layout_GetFlowDirection,
4161 dwritetextformat_layout_GetIncrementalTabStop,
4162 dwritetextformat_layout_GetTrimming,
4163 dwritetextformat_layout_GetLineSpacing,
4164 dwritetextformat_layout_GetFontCollection,
4165 dwritetextformat_layout_GetFontFamilyNameLength,
4166 dwritetextformat_layout_GetFontFamilyName,
4167 dwritetextformat_layout_GetFontWeight,
4168 dwritetextformat_layout_GetFontStyle,
4169 dwritetextformat_layout_GetFontStretch,
4170 dwritetextformat_layout_GetFontSize,
4171 dwritetextformat_layout_GetLocaleNameLength,
4172 dwritetextformat_layout_GetLocaleName,
4173 dwritetextformat1_layout_SetVerticalGlyphOrientation,
4174 dwritetextformat1_layout_GetVerticalGlyphOrientation,
4175 dwritetextformat1_layout_SetLastLineWrapping,
4176 dwritetextformat1_layout_GetLastLineWrapping,
4177 dwritetextformat1_layout_SetOpticalAlignment,
4178 dwritetextformat1_layout_GetOpticalAlignment,
4179 dwritetextformat1_layout_SetFontFallback,
4180 dwritetextformat1_layout_GetFontFallback,
4183 static HRESULT WINAPI dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink1 *iface,
4184 REFIID riid, void **obj)
4186 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink1) ||
4187 IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) ||
4188 IsEqualIID(riid, &IID_IUnknown))
4190 *obj = iface;
4191 IDWriteTextAnalysisSink1_AddRef(iface);
4192 return S_OK;
4195 *obj = NULL;
4196 return E_NOINTERFACE;
4199 static ULONG WINAPI dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink1 *iface)
4201 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4202 return IDWriteTextLayout3_AddRef(&layout->IDWriteTextLayout3_iface);
4205 static ULONG WINAPI dwritetextlayout_sink_Release(IDWriteTextAnalysisSink1 *iface)
4207 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4208 return IDWriteTextLayout3_Release(&layout->IDWriteTextLayout3_iface);
4211 static HRESULT WINAPI dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink1 *iface,
4212 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
4214 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4215 struct layout_run *run;
4217 TRACE("[%u,%u) script=%u:%s\n", position, position + length, sa->script, debugstr_sa_script(sa->script));
4219 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
4220 if (!run)
4221 return E_OUTOFMEMORY;
4223 run->u.regular.descr.string = &layout->str[position];
4224 run->u.regular.descr.stringLength = length;
4225 run->u.regular.descr.textPosition = position;
4226 run->u.regular.sa = *sa;
4227 list_add_tail(&layout->runs, &run->entry);
4228 return S_OK;
4231 static HRESULT WINAPI dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink1 *iface,
4232 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
4234 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4236 if (position + length > layout->len)
4237 return E_FAIL;
4239 memcpy(&layout->nominal_breakpoints[position], breakpoints, length*sizeof(DWRITE_LINE_BREAKPOINT));
4240 return S_OK;
4243 static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink1 *iface, UINT32 position,
4244 UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
4246 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink1(iface);
4247 struct layout_run *cur_run;
4249 TRACE("[%u,%u) %u %u\n", position, position + length, explicitLevel, resolvedLevel);
4251 LIST_FOR_EACH_ENTRY(cur_run, &layout->runs, struct layout_run, entry) {
4252 struct regular_layout_run *cur = &cur_run->u.regular;
4253 struct layout_run *run;
4255 if (cur_run->kind == LAYOUT_RUN_INLINE)
4256 continue;
4258 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
4259 if (position < cur->descr.textPosition || position >= cur->descr.textPosition + cur->descr.stringLength)
4260 continue;
4262 /* full hit - just set run level */
4263 if (cur->descr.textPosition == position && cur->descr.stringLength == length) {
4264 cur->run.bidiLevel = resolvedLevel;
4265 break;
4268 /* current run is fully covered, move to next one */
4269 if (cur->descr.textPosition == position && cur->descr.stringLength < length) {
4270 cur->run.bidiLevel = resolvedLevel;
4271 position += cur->descr.stringLength;
4272 length -= cur->descr.stringLength;
4273 continue;
4276 /* all fully covered runs are processed at this point, reuse existing run for remaining
4277 reported bidi range and add another run for the rest of original one */
4279 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
4280 if (!run)
4281 return E_OUTOFMEMORY;
4283 *run = *cur_run;
4284 run->u.regular.descr.textPosition = position + length;
4285 run->u.regular.descr.stringLength = cur->descr.stringLength - length;
4286 run->u.regular.descr.string = &layout->str[position + length];
4288 /* reduce existing run */
4289 cur->run.bidiLevel = resolvedLevel;
4290 cur->descr.stringLength = length;
4292 list_add_after(&cur_run->entry, &run->entry);
4293 break;
4296 return S_OK;
4299 static HRESULT WINAPI dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink1 *iface,
4300 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
4302 return E_NOTIMPL;
4305 static HRESULT WINAPI dwritetextlayout_sink_SetGlyphOrientation(IDWriteTextAnalysisSink1 *iface,
4306 UINT32 position, UINT32 length, DWRITE_GLYPH_ORIENTATION_ANGLE angle, UINT8 adjusted_bidi_level,
4307 BOOL is_sideways, BOOL is_rtl)
4309 return E_NOTIMPL;
4312 static const IDWriteTextAnalysisSink1Vtbl dwritetextlayoutsinkvtbl = {
4313 dwritetextlayout_sink_QueryInterface,
4314 dwritetextlayout_sink_AddRef,
4315 dwritetextlayout_sink_Release,
4316 dwritetextlayout_sink_SetScriptAnalysis,
4317 dwritetextlayout_sink_SetLineBreakpoints,
4318 dwritetextlayout_sink_SetBidiLevel,
4319 dwritetextlayout_sink_SetNumberSubstitution,
4320 dwritetextlayout_sink_SetGlyphOrientation
4323 static HRESULT WINAPI dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource1 *iface,
4324 REFIID riid, void **obj)
4326 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource1) ||
4327 IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) ||
4328 IsEqualIID(riid, &IID_IUnknown))
4330 *obj = iface;
4331 IDWriteTextAnalysisSource1_AddRef(iface);
4332 return S_OK;
4335 *obj = NULL;
4336 return E_NOINTERFACE;
4339 static ULONG WINAPI dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource1 *iface)
4341 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4342 return IDWriteTextLayout3_AddRef(&layout->IDWriteTextLayout3_iface);
4345 static ULONG WINAPI dwritetextlayout_source_Release(IDWriteTextAnalysisSource1 *iface)
4347 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4348 return IDWriteTextLayout3_Release(&layout->IDWriteTextLayout3_iface);
4351 static HRESULT WINAPI dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource1 *iface,
4352 UINT32 position, WCHAR const** text, UINT32* text_len)
4354 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4356 TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
4358 if (position < layout->len) {
4359 *text = &layout->str[position];
4360 *text_len = layout->len - position;
4362 else {
4363 *text = NULL;
4364 *text_len = 0;
4367 return S_OK;
4370 static HRESULT WINAPI dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource1 *iface,
4371 UINT32 position, WCHAR const** text, UINT32* text_len)
4373 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4375 TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
4377 if (position > 0 && position < layout->len) {
4378 *text = layout->str;
4379 *text_len = position;
4381 else {
4382 *text = NULL;
4383 *text_len = 0;
4386 return S_OK;
4389 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource1 *iface)
4391 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4392 return IDWriteTextLayout3_GetReadingDirection(&layout->IDWriteTextLayout3_iface);
4395 static HRESULT WINAPI dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource1 *iface,
4396 UINT32 position, UINT32* text_len, WCHAR const** locale)
4398 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource1(iface);
4399 struct layout_range *range = get_layout_range_by_pos(layout, position);
4401 if (position < layout->len) {
4402 struct layout_range *next;
4404 *locale = range->locale;
4405 *text_len = range->h.range.length - position;
4407 next = LIST_ENTRY(list_next(&layout->ranges, &range->h.entry), struct layout_range, h.entry);
4408 while (next && next->h.range.startPosition < layout->len && !strcmpW(range->locale, next->locale)) {
4409 *text_len += next->h.range.length;
4410 next = LIST_ENTRY(list_next(&layout->ranges, &next->h.entry), struct layout_range, h.entry);
4413 *text_len = min(*text_len, layout->len - position);
4415 else {
4416 *locale = NULL;
4417 *text_len = 0;
4420 return S_OK;
4423 static HRESULT WINAPI dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource1 *iface,
4424 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
4426 FIXME("%u %p %p: stub\n", position, text_len, substitution);
4427 return E_NOTIMPL;
4430 static HRESULT WINAPI dwritetextlayout_source_GetVerticalGlyphOrientation(IDWriteTextAnalysisSource1 *iface,
4431 UINT32 position, UINT32 *length, DWRITE_VERTICAL_GLYPH_ORIENTATION *orientation, UINT8 *bidi_level)
4433 FIXME("%u %p %p %p: stub\n", position, length, orientation, bidi_level);
4434 return E_NOTIMPL;
4437 static const IDWriteTextAnalysisSource1Vtbl dwritetextlayoutsourcevtbl = {
4438 dwritetextlayout_source_QueryInterface,
4439 dwritetextlayout_source_AddRef,
4440 dwritetextlayout_source_Release,
4441 dwritetextlayout_source_GetTextAtPosition,
4442 dwritetextlayout_source_GetTextBeforePosition,
4443 dwritetextlayout_source_GetParagraphReadingDirection,
4444 dwritetextlayout_source_GetLocaleName,
4445 dwritetextlayout_source_GetNumberSubstitution,
4446 dwritetextlayout_source_GetVerticalGlyphOrientation
4449 static HRESULT layout_format_from_textformat(struct dwrite_textlayout *layout, IDWriteTextFormat *format)
4451 struct dwrite_textformat *textformat;
4452 IDWriteTextFormat1 *format1;
4453 UINT32 len;
4454 HRESULT hr;
4456 if ((textformat = unsafe_impl_from_IDWriteTextFormat(format))) {
4457 layout->format = textformat->format;
4459 layout->format.locale = heap_strdupW(textformat->format.locale);
4460 layout->format.family_name = heap_strdupW(textformat->format.family_name);
4461 if (!layout->format.locale || !layout->format.family_name)
4463 heap_free(layout->format.locale);
4464 heap_free(layout->format.family_name);
4465 return E_OUTOFMEMORY;
4468 if (layout->format.trimmingsign)
4469 IDWriteInlineObject_AddRef(layout->format.trimmingsign);
4470 if (layout->format.collection)
4471 IDWriteFontCollection_AddRef(layout->format.collection);
4472 if (layout->format.fallback)
4473 IDWriteFontFallback_AddRef(layout->format.fallback);
4475 return S_OK;
4478 layout->format.weight = IDWriteTextFormat_GetFontWeight(format);
4479 layout->format.style = IDWriteTextFormat_GetFontStyle(format);
4480 layout->format.stretch = IDWriteTextFormat_GetFontStretch(format);
4481 layout->format.fontsize= IDWriteTextFormat_GetFontSize(format);
4482 layout->format.textalignment = IDWriteTextFormat_GetTextAlignment(format);
4483 layout->format.paralign = IDWriteTextFormat_GetParagraphAlignment(format);
4484 layout->format.wrapping = IDWriteTextFormat_GetWordWrapping(format);
4485 layout->format.readingdir = IDWriteTextFormat_GetReadingDirection(format);
4486 layout->format.flow = IDWriteTextFormat_GetFlowDirection(format);
4487 layout->format.fallback = NULL;
4488 layout->format.spacing.leadingBefore = 0.0f;
4489 layout->format.spacing.fontLineGapUsage = DWRITE_FONT_LINE_GAP_USAGE_DEFAULT;
4490 hr = IDWriteTextFormat_GetLineSpacing(format, &layout->format.spacing.method,
4491 &layout->format.spacing.height, &layout->format.spacing.baseline);
4492 if (FAILED(hr))
4493 return hr;
4495 hr = IDWriteTextFormat_GetTrimming(format, &layout->format.trimming, &layout->format.trimmingsign);
4496 if (FAILED(hr))
4497 return hr;
4499 /* locale name and length */
4500 len = IDWriteTextFormat_GetLocaleNameLength(format);
4501 layout->format.locale = heap_alloc((len+1)*sizeof(WCHAR));
4502 if (!layout->format.locale)
4503 return E_OUTOFMEMORY;
4505 hr = IDWriteTextFormat_GetLocaleName(format, layout->format.locale, len+1);
4506 if (FAILED(hr))
4507 return hr;
4508 layout->format.locale_len = len;
4510 /* font family name and length */
4511 len = IDWriteTextFormat_GetFontFamilyNameLength(format);
4512 layout->format.family_name = heap_alloc((len+1)*sizeof(WCHAR));
4513 if (!layout->format.family_name)
4514 return E_OUTOFMEMORY;
4516 hr = IDWriteTextFormat_GetFontFamilyName(format, layout->format.family_name, len+1);
4517 if (FAILED(hr))
4518 return hr;
4519 layout->format.family_len = len;
4521 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
4522 if (hr == S_OK) {
4523 IDWriteTextFormat2 *format2;
4525 layout->format.vertical_orientation = IDWriteTextFormat1_GetVerticalGlyphOrientation(format1);
4526 layout->format.optical_alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
4527 IDWriteTextFormat1_GetFontFallback(format1, &layout->format.fallback);
4529 if (IDWriteTextFormat1_QueryInterface(format1, &IID_IDWriteTextFormat2, (void**)&format2) == S_OK) {
4530 IDWriteTextFormat2_GetLineSpacing(format2, &layout->format.spacing);
4531 IDWriteTextFormat2_Release(format2);
4534 IDWriteTextFormat1_Release(format1);
4536 else {
4537 layout->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
4538 layout->format.optical_alignment = DWRITE_OPTICAL_ALIGNMENT_NONE;
4541 return IDWriteTextFormat_GetFontCollection(format, &layout->format.collection);
4544 static HRESULT init_textlayout(const struct textlayout_desc *desc, struct dwrite_textlayout *layout)
4546 struct layout_range_header *range, *strike, *underline, *effect, *spacing, *typography;
4547 static const DWRITE_TEXT_RANGE r = { 0, ~0u };
4548 HRESULT hr;
4550 layout->IDWriteTextLayout3_iface.lpVtbl = &dwritetextlayoutvtbl;
4551 layout->IDWriteTextFormat1_iface.lpVtbl = &dwritetextformat1_layout_vtbl;
4552 layout->IDWriteTextAnalysisSink1_iface.lpVtbl = &dwritetextlayoutsinkvtbl;
4553 layout->IDWriteTextAnalysisSource1_iface.lpVtbl = &dwritetextlayoutsourcevtbl;
4554 layout->ref = 1;
4555 layout->len = desc->length;
4556 layout->recompute = RECOMPUTE_EVERYTHING;
4557 layout->nominal_breakpoints = NULL;
4558 layout->actual_breakpoints = NULL;
4559 layout->cluster_count = 0;
4560 layout->clustermetrics = NULL;
4561 layout->clusters = NULL;
4562 layout->lines = NULL;
4563 layout->line_alloc = 0;
4564 layout->minwidth = 0.0f;
4565 list_init(&layout->eruns);
4566 list_init(&layout->inlineobjects);
4567 list_init(&layout->underlines);
4568 list_init(&layout->strikethrough);
4569 list_init(&layout->runs);
4570 list_init(&layout->ranges);
4571 list_init(&layout->strike_ranges);
4572 list_init(&layout->underline_ranges);
4573 list_init(&layout->effects);
4574 list_init(&layout->spacing);
4575 list_init(&layout->typographies);
4576 memset(&layout->format, 0, sizeof(layout->format));
4577 memset(&layout->metrics, 0, sizeof(layout->metrics));
4578 layout->metrics.layoutWidth = desc->max_width;
4579 layout->metrics.layoutHeight = desc->max_height;
4580 layout->measuringmode = DWRITE_MEASURING_MODE_NATURAL;
4582 layout->ppdip = 0.0f;
4583 memset(&layout->transform, 0, sizeof(layout->transform));
4585 layout->str = heap_strdupnW(desc->string, desc->length);
4586 if (desc->length && !layout->str) {
4587 hr = E_OUTOFMEMORY;
4588 goto fail;
4591 hr = layout_format_from_textformat(layout, desc->format);
4592 if (FAILED(hr))
4593 goto fail;
4595 range = alloc_layout_range(layout, &r, LAYOUT_RANGE_REGULAR);
4596 strike = alloc_layout_range(layout, &r, LAYOUT_RANGE_STRIKETHROUGH);
4597 underline = alloc_layout_range(layout, &r, LAYOUT_RANGE_UNDERLINE);
4598 effect = alloc_layout_range(layout, &r, LAYOUT_RANGE_EFFECT);
4599 spacing = alloc_layout_range(layout, &r, LAYOUT_RANGE_SPACING);
4600 typography = alloc_layout_range(layout, &r, LAYOUT_RANGE_TYPOGRAPHY);
4601 if (!range || !strike || !effect || !spacing || !typography || !underline) {
4602 free_layout_range(range);
4603 free_layout_range(strike);
4604 free_layout_range(underline);
4605 free_layout_range(effect);
4606 free_layout_range(spacing);
4607 free_layout_range(typography);
4608 hr = E_OUTOFMEMORY;
4609 goto fail;
4612 if (desc->is_gdi_compatible)
4613 layout->measuringmode = desc->use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
4614 else
4615 layout->measuringmode = DWRITE_MEASURING_MODE_NATURAL;
4616 layout->ppdip = desc->ppdip;
4617 layout->transform = desc->transform ? *desc->transform : identity;
4619 layout->factory = desc->factory;
4620 IDWriteFactory3_AddRef(layout->factory);
4621 list_add_head(&layout->ranges, &range->entry);
4622 list_add_head(&layout->strike_ranges, &strike->entry);
4623 list_add_head(&layout->underline_ranges, &underline->entry);
4624 list_add_head(&layout->effects, &effect->entry);
4625 list_add_head(&layout->spacing, &spacing->entry);
4626 list_add_head(&layout->typographies, &typography->entry);
4627 return S_OK;
4629 fail:
4630 IDWriteTextLayout3_Release(&layout->IDWriteTextLayout3_iface);
4631 return hr;
4634 HRESULT create_textlayout(const struct textlayout_desc *desc, IDWriteTextLayout **ret)
4636 struct dwrite_textlayout *layout;
4637 HRESULT hr;
4639 *ret = NULL;
4641 if (!desc->format || !desc->string)
4642 return E_INVALIDARG;
4644 layout = heap_alloc(sizeof(struct dwrite_textlayout));
4645 if (!layout) return E_OUTOFMEMORY;
4647 hr = init_textlayout(desc, layout);
4648 if (hr == S_OK)
4649 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout3_iface;
4651 return hr;
4654 static HRESULT WINAPI dwritetrimmingsign_QueryInterface(IDWriteInlineObject *iface, REFIID riid, void **obj)
4656 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4658 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4660 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteInlineObject)) {
4661 *obj = iface;
4662 IDWriteInlineObject_AddRef(iface);
4663 return S_OK;
4666 *obj = NULL;
4667 return E_NOINTERFACE;
4670 static ULONG WINAPI dwritetrimmingsign_AddRef(IDWriteInlineObject *iface)
4672 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4673 ULONG ref = InterlockedIncrement(&This->ref);
4674 TRACE("(%p)->(%d)\n", This, ref);
4675 return ref;
4678 static ULONG WINAPI dwritetrimmingsign_Release(IDWriteInlineObject *iface)
4680 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4681 ULONG ref = InterlockedDecrement(&This->ref);
4683 TRACE("(%p)->(%d)\n", This, ref);
4685 if (!ref) {
4686 IDWriteTextLayout_Release(This->layout);
4687 heap_free(This);
4690 return ref;
4693 static HRESULT WINAPI dwritetrimmingsign_Draw(IDWriteInlineObject *iface, void *context, IDWriteTextRenderer *renderer,
4694 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *effect)
4696 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4697 DWRITE_TEXT_RANGE range = { 0, ~0u };
4698 HRESULT hr;
4700 TRACE("(%p)->(%p %p %.2f %.2f %d %d %p)\n", This, context, renderer, originX, originY, is_sideways, is_rtl, effect);
4702 IDWriteTextLayout_SetDrawingEffect(This->layout, effect, range);
4703 hr = IDWriteTextLayout_Draw(This->layout, context, renderer, originX, originY);
4704 IDWriteTextLayout_SetDrawingEffect(This->layout, NULL, range);
4705 return hr;
4708 static HRESULT WINAPI dwritetrimmingsign_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *ret)
4710 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4711 DWRITE_TEXT_METRICS metrics;
4712 HRESULT hr;
4714 TRACE("(%p)->(%p)\n", This, ret);
4716 hr = IDWriteTextLayout_GetMetrics(This->layout, &metrics);
4717 if (FAILED(hr)) {
4718 memset(ret, 0, sizeof(*ret));
4719 return hr;
4722 ret->width = metrics.width;
4723 ret->height = 0.0f;
4724 ret->baseline = 0.0f;
4725 ret->supportsSideways = FALSE;
4726 return S_OK;
4729 static HRESULT WINAPI dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
4731 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4732 TRACE("(%p)->(%p)\n", This, overhangs);
4733 return IDWriteTextLayout_GetOverhangMetrics(This->layout, overhangs);
4736 static HRESULT WINAPI dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
4737 DWRITE_BREAK_CONDITION *after)
4739 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4741 TRACE("(%p)->(%p %p)\n", This, before, after);
4743 *before = *after = DWRITE_BREAK_CONDITION_NEUTRAL;
4744 return S_OK;
4747 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl = {
4748 dwritetrimmingsign_QueryInterface,
4749 dwritetrimmingsign_AddRef,
4750 dwritetrimmingsign_Release,
4751 dwritetrimmingsign_Draw,
4752 dwritetrimmingsign_GetMetrics,
4753 dwritetrimmingsign_GetOverhangMetrics,
4754 dwritetrimmingsign_GetBreakConditions
4757 static inline BOOL is_reading_direction_horz(DWRITE_READING_DIRECTION direction)
4759 return (direction == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT) ||
4760 (direction == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
4763 static inline BOOL is_reading_direction_vert(DWRITE_READING_DIRECTION direction)
4765 return (direction == DWRITE_READING_DIRECTION_TOP_TO_BOTTOM) ||
4766 (direction == DWRITE_READING_DIRECTION_BOTTOM_TO_TOP);
4769 static inline BOOL is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction)
4771 return (direction == DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT) ||
4772 (direction == DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT);
4775 static inline BOOL is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction)
4777 return (direction == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM) ||
4778 (direction == DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP);
4781 HRESULT create_trimmingsign(IDWriteFactory3 *factory, IDWriteTextFormat *format, IDWriteInlineObject **sign)
4783 static const WCHAR ellipsisW = 0x2026;
4784 struct dwrite_trimmingsign *This;
4785 DWRITE_READING_DIRECTION reading;
4786 DWRITE_FLOW_DIRECTION flow;
4787 HRESULT hr;
4789 *sign = NULL;
4791 /* Validate reading/flow direction here, layout creation won't complain about
4792 invalid combinations. */
4793 reading = IDWriteTextFormat_GetReadingDirection(format);
4794 flow = IDWriteTextFormat_GetFlowDirection(format);
4796 if ((is_reading_direction_horz(reading) && is_flow_direction_horz(flow)) ||
4797 (is_reading_direction_vert(reading) && is_flow_direction_vert(flow)))
4798 return DWRITE_E_FLOWDIRECTIONCONFLICTS;
4800 This = heap_alloc(sizeof(*This));
4801 if (!This)
4802 return E_OUTOFMEMORY;
4804 This->IDWriteInlineObject_iface.lpVtbl = &dwritetrimmingsignvtbl;
4805 This->ref = 1;
4807 hr = IDWriteFactory3_CreateTextLayout(factory, &ellipsisW, 1, format, 0.0f, 0.0f, &This->layout);
4808 if (FAILED(hr)) {
4809 heap_free(This);
4810 return hr;
4813 IDWriteTextLayout_SetWordWrapping(This->layout, DWRITE_WORD_WRAPPING_NO_WRAP);
4814 *sign = &This->IDWriteInlineObject_iface;
4816 return S_OK;
4819 static HRESULT WINAPI dwritetextformat_QueryInterface(IDWriteTextFormat2 *iface, REFIID riid, void **obj)
4821 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4823 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4825 if (IsEqualIID(riid, &IID_IDWriteTextFormat2) ||
4826 IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
4827 IsEqualIID(riid, &IID_IDWriteTextFormat) ||
4828 IsEqualIID(riid, &IID_IUnknown))
4830 *obj = iface;
4831 IDWriteTextFormat2_AddRef(iface);
4832 return S_OK;
4835 *obj = NULL;
4837 return E_NOINTERFACE;
4840 static ULONG WINAPI dwritetextformat_AddRef(IDWriteTextFormat2 *iface)
4842 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4843 ULONG ref = InterlockedIncrement(&This->ref);
4844 TRACE("(%p)->(%d)\n", This, ref);
4845 return ref;
4848 static ULONG WINAPI dwritetextformat_Release(IDWriteTextFormat2 *iface)
4850 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4851 ULONG ref = InterlockedDecrement(&This->ref);
4853 TRACE("(%p)->(%d)\n", This, ref);
4855 if (!ref)
4857 release_format_data(&This->format);
4858 heap_free(This);
4861 return ref;
4864 static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat2 *iface, DWRITE_TEXT_ALIGNMENT alignment)
4866 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4867 TRACE("(%p)->(%d)\n", This, alignment);
4868 return format_set_textalignment(&This->format, alignment, NULL);
4871 static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat2 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
4873 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4874 TRACE("(%p)->(%d)\n", This, alignment);
4875 return format_set_paralignment(&This->format, alignment, NULL);
4878 static HRESULT WINAPI dwritetextformat_SetWordWrapping(IDWriteTextFormat2 *iface, DWRITE_WORD_WRAPPING wrapping)
4880 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4881 TRACE("(%p)->(%d)\n", This, wrapping);
4882 return format_set_wordwrapping(&This->format, wrapping, NULL);
4885 static HRESULT WINAPI dwritetextformat_SetReadingDirection(IDWriteTextFormat2 *iface, DWRITE_READING_DIRECTION direction)
4887 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4888 TRACE("(%p)->(%d)\n", This, direction);
4889 return format_set_readingdirection(&This->format, direction, NULL);
4892 static HRESULT WINAPI dwritetextformat_SetFlowDirection(IDWriteTextFormat2 *iface, DWRITE_FLOW_DIRECTION direction)
4894 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4895 TRACE("(%p)->(%d)\n", This, direction);
4896 return format_set_flowdirection(&This->format, direction, NULL);
4899 static HRESULT WINAPI dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat2 *iface, FLOAT tabstop)
4901 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4902 FIXME("(%p)->(%f): stub\n", This, tabstop);
4903 return E_NOTIMPL;
4906 static HRESULT WINAPI dwritetextformat_SetTrimming(IDWriteTextFormat2 *iface, DWRITE_TRIMMING const *trimming,
4907 IDWriteInlineObject *trimming_sign)
4909 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4910 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
4911 return format_set_trimming(&This->format, trimming, trimming_sign, NULL);
4914 static HRESULT WINAPI dwritetextformat_SetLineSpacing(IDWriteTextFormat2 *iface, DWRITE_LINE_SPACING_METHOD method,
4915 FLOAT height, FLOAT baseline)
4917 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4918 DWRITE_LINE_SPACING spacing;
4920 TRACE("(%p)->(%d %f %f)\n", This, method, height, baseline);
4922 spacing = This->format.spacing;
4923 spacing.method = method;
4924 spacing.height = height;
4925 spacing.baseline = baseline;
4927 return format_set_linespacing(&This->format, &spacing, NULL);
4930 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_GetTextAlignment(IDWriteTextFormat2 *iface)
4932 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4933 TRACE("(%p)\n", This);
4934 return This->format.textalignment;
4937 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_GetParagraphAlignment(IDWriteTextFormat2 *iface)
4939 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4940 TRACE("(%p)\n", This);
4941 return This->format.paralign;
4944 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_GetWordWrapping(IDWriteTextFormat2 *iface)
4946 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4947 TRACE("(%p)\n", This);
4948 return This->format.wrapping;
4951 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_GetReadingDirection(IDWriteTextFormat2 *iface)
4953 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4954 TRACE("(%p)\n", This);
4955 return This->format.readingdir;
4958 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_GetFlowDirection(IDWriteTextFormat2 *iface)
4960 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4961 TRACE("(%p)\n", This);
4962 return This->format.flow;
4965 static FLOAT WINAPI dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat2 *iface)
4967 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4968 FIXME("(%p): stub\n", This);
4969 return 0.0f;
4972 static HRESULT WINAPI dwritetextformat_GetTrimming(IDWriteTextFormat2 *iface, DWRITE_TRIMMING *options,
4973 IDWriteInlineObject **trimming_sign)
4975 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4976 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
4978 *options = This->format.trimming;
4979 if ((*trimming_sign = This->format.trimmingsign))
4980 IDWriteInlineObject_AddRef(*trimming_sign);
4982 return S_OK;
4985 static HRESULT WINAPI dwritetextformat_GetLineSpacing(IDWriteTextFormat2 *iface, DWRITE_LINE_SPACING_METHOD *method,
4986 FLOAT *spacing, FLOAT *baseline)
4988 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
4989 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
4991 *method = This->format.spacing.method;
4992 *spacing = This->format.spacing.height;
4993 *baseline = This->format.spacing.baseline;
4994 return S_OK;
4997 static HRESULT WINAPI dwritetextformat_GetFontCollection(IDWriteTextFormat2 *iface, IDWriteFontCollection **collection)
4999 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5001 TRACE("(%p)->(%p)\n", This, collection);
5003 *collection = This->format.collection;
5004 IDWriteFontCollection_AddRef(*collection);
5006 return S_OK;
5009 static UINT32 WINAPI dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat2 *iface)
5011 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5012 TRACE("(%p)\n", This);
5013 return This->format.family_len;
5016 static HRESULT WINAPI dwritetextformat_GetFontFamilyName(IDWriteTextFormat2 *iface, WCHAR *name, UINT32 size)
5018 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5020 TRACE("(%p)->(%p %u)\n", This, name, size);
5022 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
5023 strcpyW(name, This->format.family_name);
5024 return S_OK;
5027 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_GetFontWeight(IDWriteTextFormat2 *iface)
5029 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5030 TRACE("(%p)\n", This);
5031 return This->format.weight;
5034 static DWRITE_FONT_STYLE WINAPI dwritetextformat_GetFontStyle(IDWriteTextFormat2 *iface)
5036 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5037 TRACE("(%p)\n", This);
5038 return This->format.style;
5041 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_GetFontStretch(IDWriteTextFormat2 *iface)
5043 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5044 TRACE("(%p)\n", This);
5045 return This->format.stretch;
5048 static FLOAT WINAPI dwritetextformat_GetFontSize(IDWriteTextFormat2 *iface)
5050 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5051 TRACE("(%p)\n", This);
5052 return This->format.fontsize;
5055 static UINT32 WINAPI dwritetextformat_GetLocaleNameLength(IDWriteTextFormat2 *iface)
5057 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5058 TRACE("(%p)\n", This);
5059 return This->format.locale_len;
5062 static HRESULT WINAPI dwritetextformat_GetLocaleName(IDWriteTextFormat2 *iface, WCHAR *name, UINT32 size)
5064 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5066 TRACE("(%p)->(%p %u)\n", This, name, size);
5068 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
5069 strcpyW(name, This->format.locale);
5070 return S_OK;
5073 static HRESULT WINAPI dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat2 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
5075 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5077 TRACE("(%p)->(%d)\n", This, orientation);
5079 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
5080 return E_INVALIDARG;
5082 This->format.vertical_orientation = orientation;
5083 return S_OK;
5086 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat2 *iface)
5088 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5089 TRACE("(%p)\n", This);
5090 return This->format.vertical_orientation;
5093 static HRESULT WINAPI dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat2 *iface, BOOL lastline_wrapping_enabled)
5095 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5097 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
5099 This->format.last_line_wrapping = !!lastline_wrapping_enabled;
5100 return S_OK;
5103 static BOOL WINAPI dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat2 *iface)
5105 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5106 TRACE("(%p)\n", This);
5107 return This->format.last_line_wrapping;
5110 static HRESULT WINAPI dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat2 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
5112 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5113 TRACE("(%p)->(%d)\n", This, alignment);
5114 return format_set_optical_alignment(&This->format, alignment);
5117 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat2 *iface)
5119 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5120 TRACE("(%p)\n", This);
5121 return This->format.optical_alignment;
5124 static HRESULT WINAPI dwritetextformat1_SetFontFallback(IDWriteTextFormat2 *iface, IDWriteFontFallback *fallback)
5126 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5127 TRACE("(%p)->(%p)\n", This, fallback);
5128 return set_fontfallback_for_format(&This->format, fallback);
5131 static HRESULT WINAPI dwritetextformat1_GetFontFallback(IDWriteTextFormat2 *iface, IDWriteFontFallback **fallback)
5133 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5134 TRACE("(%p)->(%p)\n", This, fallback);
5135 return get_fontfallback_from_format(&This->format, fallback);
5138 static HRESULT WINAPI dwritetextformat2_SetLineSpacing(IDWriteTextFormat2 *iface, DWRITE_LINE_SPACING const *spacing)
5140 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5141 TRACE("(%p)->(%p)\n", This, spacing);
5142 return format_set_linespacing(&This->format, spacing, NULL);
5145 static HRESULT WINAPI dwritetextformat2_GetLineSpacing(IDWriteTextFormat2 *iface, DWRITE_LINE_SPACING *spacing)
5147 struct dwrite_textformat *This = impl_from_IDWriteTextFormat2(iface);
5149 TRACE("(%p)->(%p)\n", This, spacing);
5151 *spacing = This->format.spacing;
5152 return S_OK;
5155 static const IDWriteTextFormat2Vtbl dwritetextformatvtbl = {
5156 dwritetextformat_QueryInterface,
5157 dwritetextformat_AddRef,
5158 dwritetextformat_Release,
5159 dwritetextformat_SetTextAlignment,
5160 dwritetextformat_SetParagraphAlignment,
5161 dwritetextformat_SetWordWrapping,
5162 dwritetextformat_SetReadingDirection,
5163 dwritetextformat_SetFlowDirection,
5164 dwritetextformat_SetIncrementalTabStop,
5165 dwritetextformat_SetTrimming,
5166 dwritetextformat_SetLineSpacing,
5167 dwritetextformat_GetTextAlignment,
5168 dwritetextformat_GetParagraphAlignment,
5169 dwritetextformat_GetWordWrapping,
5170 dwritetextformat_GetReadingDirection,
5171 dwritetextformat_GetFlowDirection,
5172 dwritetextformat_GetIncrementalTabStop,
5173 dwritetextformat_GetTrimming,
5174 dwritetextformat_GetLineSpacing,
5175 dwritetextformat_GetFontCollection,
5176 dwritetextformat_GetFontFamilyNameLength,
5177 dwritetextformat_GetFontFamilyName,
5178 dwritetextformat_GetFontWeight,
5179 dwritetextformat_GetFontStyle,
5180 dwritetextformat_GetFontStretch,
5181 dwritetextformat_GetFontSize,
5182 dwritetextformat_GetLocaleNameLength,
5183 dwritetextformat_GetLocaleName,
5184 dwritetextformat1_SetVerticalGlyphOrientation,
5185 dwritetextformat1_GetVerticalGlyphOrientation,
5186 dwritetextformat1_SetLastLineWrapping,
5187 dwritetextformat1_GetLastLineWrapping,
5188 dwritetextformat1_SetOpticalAlignment,
5189 dwritetextformat1_GetOpticalAlignment,
5190 dwritetextformat1_SetFontFallback,
5191 dwritetextformat1_GetFontFallback,
5192 dwritetextformat2_SetLineSpacing,
5193 dwritetextformat2_GetLineSpacing
5196 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat *iface)
5198 return (iface->lpVtbl == (IDWriteTextFormatVtbl*)&dwritetextformatvtbl) ?
5199 CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat2_iface) : NULL;
5202 HRESULT create_textformat(const WCHAR *family_name, IDWriteFontCollection *collection, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style,
5203 DWRITE_FONT_STRETCH stretch, FLOAT size, const WCHAR *locale, IDWriteTextFormat **format)
5205 struct dwrite_textformat *This;
5207 *format = NULL;
5209 if (size <= 0.0f)
5210 return E_INVALIDARG;
5212 if (((UINT32)weight > DWRITE_FONT_WEIGHT_ULTRA_BLACK) ||
5213 ((UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED) ||
5214 ((UINT32)style > DWRITE_FONT_STYLE_ITALIC))
5215 return E_INVALIDARG;
5217 This = heap_alloc(sizeof(struct dwrite_textformat));
5218 if (!This) return E_OUTOFMEMORY;
5220 This->IDWriteTextFormat2_iface.lpVtbl = &dwritetextformatvtbl;
5221 This->ref = 1;
5222 This->format.family_name = heap_strdupW(family_name);
5223 This->format.family_len = strlenW(family_name);
5224 This->format.locale = heap_strdupW(locale);
5225 This->format.locale_len = strlenW(locale);
5226 /* force locale name to lower case, layout will inherit this modified value */
5227 strlwrW(This->format.locale);
5228 This->format.weight = weight;
5229 This->format.style = style;
5230 This->format.fontsize = size;
5231 This->format.stretch = stretch;
5232 This->format.textalignment = DWRITE_TEXT_ALIGNMENT_LEADING;
5233 This->format.optical_alignment = DWRITE_OPTICAL_ALIGNMENT_NONE;
5234 This->format.paralign = DWRITE_PARAGRAPH_ALIGNMENT_NEAR;
5235 This->format.wrapping = DWRITE_WORD_WRAPPING_WRAP;
5236 This->format.last_line_wrapping = TRUE;
5237 This->format.readingdir = DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
5238 This->format.flow = DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM;
5239 This->format.spacing.method = DWRITE_LINE_SPACING_METHOD_DEFAULT;
5240 This->format.spacing.height = 0.0f;
5241 This->format.spacing.baseline = 0.0f;
5242 This->format.spacing.leadingBefore = 0.0f;
5243 This->format.spacing.fontLineGapUsage = DWRITE_FONT_LINE_GAP_USAGE_DEFAULT;
5244 This->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
5245 This->format.trimming.granularity = DWRITE_TRIMMING_GRANULARITY_NONE;
5246 This->format.trimming.delimiter = 0;
5247 This->format.trimming.delimiterCount = 0;
5248 This->format.trimmingsign = NULL;
5249 This->format.collection = collection;
5250 This->format.fallback = NULL;
5251 IDWriteFontCollection_AddRef(collection);
5253 *format = (IDWriteTextFormat*)&This->IDWriteTextFormat2_iface;
5255 return S_OK;
5258 static HRESULT WINAPI dwritetypography_QueryInterface(IDWriteTypography *iface, REFIID riid, void **obj)
5260 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5262 TRACE("(%p)->(%s %p)\n", typography, debugstr_guid(riid), obj);
5264 if (IsEqualIID(riid, &IID_IDWriteTypography) || IsEqualIID(riid, &IID_IUnknown)) {
5265 *obj = iface;
5266 IDWriteTypography_AddRef(iface);
5267 return S_OK;
5270 *obj = NULL;
5272 return E_NOINTERFACE;
5275 static ULONG WINAPI dwritetypography_AddRef(IDWriteTypography *iface)
5277 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5278 ULONG ref = InterlockedIncrement(&typography->ref);
5279 TRACE("(%p)->(%d)\n", typography, ref);
5280 return ref;
5283 static ULONG WINAPI dwritetypography_Release(IDWriteTypography *iface)
5285 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5286 ULONG ref = InterlockedDecrement(&typography->ref);
5288 TRACE("(%p)->(%d)\n", typography, ref);
5290 if (!ref) {
5291 heap_free(typography->features);
5292 heap_free(typography);
5295 return ref;
5298 static HRESULT WINAPI dwritetypography_AddFontFeature(IDWriteTypography *iface, DWRITE_FONT_FEATURE feature)
5300 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5302 TRACE("(%p)->(%x %u)\n", typography, feature.nameTag, feature.parameter);
5304 if (typography->count == typography->allocated) {
5305 DWRITE_FONT_FEATURE *ptr = heap_realloc(typography->features, 2*typography->allocated*sizeof(DWRITE_FONT_FEATURE));
5306 if (!ptr)
5307 return E_OUTOFMEMORY;
5309 typography->features = ptr;
5310 typography->allocated *= 2;
5313 typography->features[typography->count++] = feature;
5314 return S_OK;
5317 static UINT32 WINAPI dwritetypography_GetFontFeatureCount(IDWriteTypography *iface)
5319 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5320 TRACE("(%p)\n", typography);
5321 return typography->count;
5324 static HRESULT WINAPI dwritetypography_GetFontFeature(IDWriteTypography *iface, UINT32 index, DWRITE_FONT_FEATURE *feature)
5326 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
5328 TRACE("(%p)->(%u %p)\n", typography, index, feature);
5330 if (index >= typography->count)
5331 return E_INVALIDARG;
5333 *feature = typography->features[index];
5334 return S_OK;
5337 static const IDWriteTypographyVtbl dwritetypographyvtbl = {
5338 dwritetypography_QueryInterface,
5339 dwritetypography_AddRef,
5340 dwritetypography_Release,
5341 dwritetypography_AddFontFeature,
5342 dwritetypography_GetFontFeatureCount,
5343 dwritetypography_GetFontFeature
5346 HRESULT create_typography(IDWriteTypography **ret)
5348 struct dwrite_typography *typography;
5350 *ret = NULL;
5352 typography = heap_alloc(sizeof(*typography));
5353 if (!typography)
5354 return E_OUTOFMEMORY;
5356 typography->IDWriteTypography_iface.lpVtbl = &dwritetypographyvtbl;
5357 typography->ref = 1;
5358 typography->allocated = 2;
5359 typography->count = 0;
5361 typography->features = heap_alloc(typography->allocated*sizeof(DWRITE_FONT_FEATURE));
5362 if (!typography->features) {
5363 heap_free(typography);
5364 return E_OUTOFMEMORY;
5367 *ret = &typography->IDWriteTypography_iface;
5368 return S_OK;