windowscodecs: Add support for 8bpp grayscale TIFF with 8bpp alpha.
[wine.git] / dlls / dwrite / layout.c
blob1f7beb4dad9953bcbbaa3e4c18bbd3422c7f332f
1 /*
2 * Text format and layout
4 * Copyright 2012, 2014-2015 Nikolay Sivov for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include <stdarg.h>
24 #include <math.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "dwrite_private.h"
30 #include "scripts.h"
31 #include "wine/list.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
35 struct dwrite_textformat_data {
36 WCHAR *family_name;
37 UINT32 family_len;
38 WCHAR *locale;
39 UINT32 locale_len;
41 DWRITE_FONT_WEIGHT weight;
42 DWRITE_FONT_STYLE style;
43 DWRITE_FONT_STRETCH stretch;
45 DWRITE_PARAGRAPH_ALIGNMENT paralign;
46 DWRITE_READING_DIRECTION readingdir;
47 DWRITE_WORD_WRAPPING wrapping;
48 DWRITE_TEXT_ALIGNMENT textalignment;
49 DWRITE_FLOW_DIRECTION flow;
50 DWRITE_LINE_SPACING_METHOD spacingmethod;
51 DWRITE_VERTICAL_GLYPH_ORIENTATION vertical_orientation;
53 FLOAT spacing;
54 FLOAT baseline;
55 FLOAT fontsize;
57 DWRITE_TRIMMING trimming;
58 IDWriteInlineObject *trimmingsign;
60 IDWriteFontCollection *collection;
61 IDWriteFontFallback *fallback;
64 enum layout_range_attr_kind {
65 LAYOUT_RANGE_ATTR_WEIGHT,
66 LAYOUT_RANGE_ATTR_STYLE,
67 LAYOUT_RANGE_ATTR_STRETCH,
68 LAYOUT_RANGE_ATTR_FONTSIZE,
69 LAYOUT_RANGE_ATTR_EFFECT,
70 LAYOUT_RANGE_ATTR_INLINE,
71 LAYOUT_RANGE_ATTR_UNDERLINE,
72 LAYOUT_RANGE_ATTR_STRIKETHROUGH,
73 LAYOUT_RANGE_ATTR_PAIR_KERNING,
74 LAYOUT_RANGE_ATTR_FONTCOLL,
75 LAYOUT_RANGE_ATTR_LOCALE,
76 LAYOUT_RANGE_ATTR_FONTFAMILY,
77 LAYOUT_RANGE_ATTR_SPACING
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 } u;
99 enum layout_range_kind {
100 LAYOUT_RANGE_REGULAR,
101 LAYOUT_RANGE_STRIKETHROUGH,
102 LAYOUT_RANGE_EFFECT,
103 LAYOUT_RANGE_SPACING
106 struct layout_range_header {
107 struct list entry;
108 enum layout_range_kind kind;
109 DWRITE_TEXT_RANGE range;
112 struct layout_range {
113 struct layout_range_header h;
114 DWRITE_FONT_WEIGHT weight;
115 DWRITE_FONT_STYLE style;
116 FLOAT fontsize;
117 DWRITE_FONT_STRETCH stretch;
118 IDWriteInlineObject *object;
119 BOOL underline;
120 BOOL pair_kerning;
121 IDWriteFontCollection *collection;
122 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
123 WCHAR *fontfamily;
126 struct layout_range_bool {
127 struct layout_range_header h;
128 BOOL value;
131 struct layout_range_effect {
132 struct layout_range_header h;
133 IUnknown *effect;
136 struct layout_range_spacing {
137 struct layout_range_header h;
138 FLOAT leading;
139 FLOAT trailing;
140 FLOAT min_advance;
143 enum layout_run_kind {
144 LAYOUT_RUN_REGULAR,
145 LAYOUT_RUN_INLINE
148 struct inline_object_run {
149 IDWriteInlineObject *object;
150 UINT16 length;
153 struct regular_layout_run {
154 DWRITE_GLYPH_RUN_DESCRIPTION descr;
155 DWRITE_GLYPH_RUN run;
156 DWRITE_SCRIPT_ANALYSIS sa;
157 UINT16 *glyphs;
158 UINT16 *clustermap;
159 FLOAT *advances;
160 DWRITE_GLYPH_OFFSET *offsets;
161 /* this is actual glyph count after shaping, it's not necessary the same as reported to Draw() */
162 UINT32 glyphcount;
165 struct layout_run {
166 struct list entry;
167 enum layout_run_kind kind;
168 union {
169 struct inline_object_run object;
170 struct regular_layout_run regular;
171 } u;
172 FLOAT baseline;
173 FLOAT height;
176 struct layout_effective_run {
177 struct list entry;
178 const struct layout_run *run; /* nominal run this one is based on */
179 UINT32 start; /* relative text position, 0 means first text position of a nominal run */
180 UINT32 length; /* length in codepoints that this run covers */
181 UINT32 glyphcount; /* total glyph count in this run */
182 FLOAT origin_x; /* baseline X position */
183 FLOAT origin_y; /* baseline Y position */
184 FLOAT align_dx; /* adjustment from text alignment */
185 FLOAT width; /* run width */
186 UINT16 *clustermap; /* effective clustermap, allocated separately, is not reused from nominal map */
187 UINT32 line;
190 struct layout_effective_inline {
191 struct list entry;
192 IDWriteInlineObject *object;
193 IUnknown *effect;
194 FLOAT origin_x;
195 FLOAT origin_y;
196 FLOAT align_dx;
197 FLOAT width;
198 BOOL is_sideways;
199 BOOL is_rtl;
200 UINT32 line;
203 struct layout_strikethrough {
204 struct list entry;
205 const struct layout_effective_run *run;
206 DWRITE_STRIKETHROUGH s;
209 struct layout_cluster {
210 const struct layout_run *run; /* link to nominal run this cluster belongs to */
211 UINT32 position; /* relative to run, first cluster has 0 position */
214 enum layout_recompute_mask {
215 RECOMPUTE_NOMINAL_RUNS = 1 << 0,
216 RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
217 RECOMPUTE_EFFECTIVE_RUNS = 1 << 2,
218 RECOMPUTE_EVERYTHING = 0xffff
221 struct dwrite_textlayout {
222 IDWriteTextLayout2 IDWriteTextLayout2_iface;
223 IDWriteTextFormat1 IDWriteTextFormat1_iface;
224 IDWriteTextAnalysisSink IDWriteTextAnalysisSink_iface;
225 IDWriteTextAnalysisSource IDWriteTextAnalysisSource_iface;
226 LONG ref;
228 WCHAR *str;
229 UINT32 len;
230 struct dwrite_textformat_data format;
231 struct list strike_ranges;
232 struct list effects;
233 struct list spacing;
234 struct list ranges;
235 struct list runs;
236 /* lists ready to use by Draw() */
237 struct list eruns;
238 struct list inlineobjects;
239 struct list strikethrough;
240 USHORT recompute;
242 DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
243 DWRITE_LINE_BREAKPOINT *actual_breakpoints;
245 struct layout_cluster *clusters;
246 DWRITE_CLUSTER_METRICS *clustermetrics;
247 UINT32 cluster_count;
248 FLOAT minwidth;
250 DWRITE_LINE_METRICS *lines;
251 UINT32 line_alloc;
253 DWRITE_TEXT_METRICS1 metrics;
255 /* gdi-compatible layout specifics */
256 BOOL gdicompatible;
257 FLOAT pixels_per_dip;
258 BOOL use_gdi_natural;
259 DWRITE_MATRIX transform;
262 struct dwrite_textformat {
263 IDWriteTextFormat1 IDWriteTextFormat1_iface;
264 LONG ref;
265 struct dwrite_textformat_data format;
268 struct dwrite_trimmingsign {
269 IDWriteInlineObject IDWriteInlineObject_iface;
270 LONG ref;
272 IDWriteTextLayout *layout;
275 struct dwrite_typography {
276 IDWriteTypography IDWriteTypography_iface;
277 LONG ref;
279 DWRITE_FONT_FEATURE *features;
280 UINT32 allocated;
281 UINT32 count;
284 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl;
286 static void release_format_data(struct dwrite_textformat_data *data)
288 if (data->collection) IDWriteFontCollection_Release(data->collection);
289 if (data->fallback) IDWriteFontFallback_Release(data->fallback);
290 if (data->trimmingsign) IDWriteInlineObject_Release(data->trimmingsign);
291 heap_free(data->family_name);
292 heap_free(data->locale);
295 static inline struct dwrite_textlayout *impl_from_IDWriteTextLayout2(IDWriteTextLayout2 *iface)
297 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextLayout2_iface);
300 static inline struct dwrite_textlayout *impl_layout_form_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
302 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextFormat1_iface);
305 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSink(IDWriteTextAnalysisSink *iface)
307 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSink_iface);
310 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSource(IDWriteTextAnalysisSource *iface)
312 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSource_iface);
315 static inline struct dwrite_textformat *impl_from_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
317 return CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat1_iface);
320 static inline struct dwrite_trimmingsign *impl_from_IDWriteInlineObject(IDWriteInlineObject *iface)
322 return CONTAINING_RECORD(iface, struct dwrite_trimmingsign, IDWriteInlineObject_iface);
325 static inline struct dwrite_typography *impl_from_IDWriteTypography(IDWriteTypography *iface)
327 return CONTAINING_RECORD(iface, struct dwrite_typography, IDWriteTypography_iface);
330 static inline const char *debugstr_run(const struct regular_layout_run *run)
332 return wine_dbg_sprintf("[%u,%u)", run->descr.textPosition, run->descr.textPosition +
333 run->descr.stringLength);
336 static inline HRESULT format_set_textalignment(struct dwrite_textformat_data *format, DWRITE_TEXT_ALIGNMENT alignment,
337 BOOL *changed)
339 if ((UINT32)alignment > DWRITE_TEXT_ALIGNMENT_JUSTIFIED)
340 return E_INVALIDARG;
341 if (changed) *changed = format->textalignment != alignment;
342 format->textalignment = alignment;
343 return S_OK;
346 static inline HRESULT format_set_paralignment(struct dwrite_textformat_data *format,
347 DWRITE_PARAGRAPH_ALIGNMENT alignment, BOOL *changed)
349 if ((UINT32)alignment > DWRITE_PARAGRAPH_ALIGNMENT_CENTER)
350 return E_INVALIDARG;
351 if (changed) *changed = format->paralign != alignment;
352 format->paralign = alignment;
353 return S_OK;
356 static inline HRESULT format_set_readingdirection(struct dwrite_textformat_data *format,
357 DWRITE_READING_DIRECTION direction, BOOL *changed)
359 if ((UINT32)direction > DWRITE_READING_DIRECTION_BOTTOM_TO_TOP)
360 return E_INVALIDARG;
361 if (changed) *changed = format->readingdir != direction;
362 format->readingdir = direction;
363 return S_OK;
366 static inline HRESULT format_set_wordwrapping(struct dwrite_textformat_data *format,
367 DWRITE_WORD_WRAPPING wrapping, BOOL *changed)
369 if ((UINT32)wrapping > DWRITE_WORD_WRAPPING_CHARACTER)
370 return E_INVALIDARG;
371 if (changed) *changed = format->wrapping != wrapping;
372 format->wrapping = wrapping;
373 return S_OK;
376 static HRESULT get_fontfallback_from_format(const struct dwrite_textformat_data *format, IDWriteFontFallback **fallback)
378 *fallback = format->fallback;
379 if (*fallback)
380 IDWriteFontFallback_AddRef(*fallback);
381 return S_OK;
384 static HRESULT set_fontfallback_for_format(struct dwrite_textformat_data *format, IDWriteFontFallback *fallback)
386 if (format->fallback)
387 IDWriteFontFallback_Release(format->fallback);
388 format->fallback = fallback;
389 if (fallback)
390 IDWriteFontFallback_AddRef(fallback);
391 return S_OK;
394 static struct layout_run *alloc_layout_run(enum layout_run_kind kind)
396 struct layout_run *ret;
398 ret = heap_alloc(sizeof(*ret));
399 if (!ret) return NULL;
401 memset(ret, 0, sizeof(*ret));
402 ret->kind = kind;
403 if (kind == LAYOUT_RUN_REGULAR) {
404 ret->u.regular.sa.script = Script_Unknown;
405 ret->u.regular.sa.shapes = DWRITE_SCRIPT_SHAPES_DEFAULT;
408 return ret;
411 static void free_layout_runs(struct dwrite_textlayout *layout)
413 struct layout_run *cur, *cur2;
414 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->runs, struct layout_run, entry) {
415 list_remove(&cur->entry);
416 if (cur->kind == LAYOUT_RUN_REGULAR) {
417 if (cur->u.regular.run.fontFace)
418 IDWriteFontFace_Release(cur->u.regular.run.fontFace);
419 heap_free(cur->u.regular.glyphs);
420 heap_free(cur->u.regular.clustermap);
421 heap_free(cur->u.regular.advances);
422 heap_free(cur->u.regular.offsets);
424 heap_free(cur);
428 static void free_layout_eruns(struct dwrite_textlayout *layout)
430 struct layout_effective_inline *in, *in2;
431 struct layout_effective_run *cur, *cur2;
432 struct layout_strikethrough *s, *s2;
434 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->eruns, struct layout_effective_run, entry) {
435 list_remove(&cur->entry);
436 heap_free(cur->clustermap);
437 heap_free(cur);
440 LIST_FOR_EACH_ENTRY_SAFE(in, in2, &layout->inlineobjects, struct layout_effective_inline, entry) {
441 list_remove(&in->entry);
442 heap_free(in);
445 LIST_FOR_EACH_ENTRY_SAFE(s, s2, &layout->strikethrough, struct layout_strikethrough, entry) {
446 list_remove(&s->entry);
447 heap_free(s);
451 /* Used to resolve break condition by forcing stronger condition over weaker. */
452 static inline DWRITE_BREAK_CONDITION override_break_condition(DWRITE_BREAK_CONDITION existingbreak, DWRITE_BREAK_CONDITION newbreak)
454 switch (existingbreak) {
455 case DWRITE_BREAK_CONDITION_NEUTRAL:
456 return newbreak;
457 case DWRITE_BREAK_CONDITION_CAN_BREAK:
458 return newbreak == DWRITE_BREAK_CONDITION_NEUTRAL ? existingbreak : newbreak;
459 /* let's keep stronger conditions as is */
460 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK:
461 case DWRITE_BREAK_CONDITION_MUST_BREAK:
462 break;
463 default:
464 ERR("unknown break condition %d\n", existingbreak);
467 return existingbreak;
470 /* This helper should be used to get effective range length, in other words it returns number of text
471 positions from range starting point to the end of the range, limited by layout text length */
472 static inline UINT32 get_clipped_range_length(const struct dwrite_textlayout *layout, const struct layout_range *range)
474 if (range->h.range.startPosition + range->h.range.length <= layout->len)
475 return range->h.range.length;
476 return layout->len - range->h.range.startPosition;
479 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
480 static HRESULT layout_update_breakpoints_range(struct dwrite_textlayout *layout, const struct layout_range *cur)
482 DWRITE_BREAK_CONDITION before, after;
483 UINT32 i, length;
484 HRESULT hr;
486 /* ignore returned conditions if failed */
487 hr = IDWriteInlineObject_GetBreakConditions(cur->object, &before, &after);
488 if (FAILED(hr))
489 after = before = DWRITE_BREAK_CONDITION_NEUTRAL;
491 if (!layout->actual_breakpoints) {
492 layout->actual_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
493 if (!layout->actual_breakpoints)
494 return E_OUTOFMEMORY;
495 memcpy(layout->actual_breakpoints, layout->nominal_breakpoints, sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
498 length = get_clipped_range_length(layout, cur);
499 for (i = cur->h.range.startPosition; i < length + cur->h.range.startPosition; i++) {
500 /* for first codepoint check if there's anything before it and update accordingly */
501 if (i == cur->h.range.startPosition) {
502 if (i > 0)
503 layout->actual_breakpoints[i].breakConditionBefore = layout->actual_breakpoints[i-1].breakConditionAfter =
504 override_break_condition(layout->actual_breakpoints[i-1].breakConditionAfter, before);
505 else
506 layout->actual_breakpoints[i].breakConditionBefore = before;
507 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
509 /* similar check for last codepoint */
510 else if (i == cur->h.range.startPosition + length - 1) {
511 if (i == layout->len - 1)
512 layout->actual_breakpoints[i].breakConditionAfter = after;
513 else
514 layout->actual_breakpoints[i].breakConditionAfter = layout->actual_breakpoints[i+1].breakConditionBefore =
515 override_break_condition(layout->actual_breakpoints[i+1].breakConditionBefore, after);
516 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
518 /* for all positions within a range disable breaks */
519 else {
520 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
521 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
524 layout->actual_breakpoints[i].isWhitespace = FALSE;
525 layout->actual_breakpoints[i].isSoftHyphen = FALSE;
528 return S_OK;
531 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos);
533 static inline DWRITE_LINE_BREAKPOINT get_effective_breakpoint(const struct dwrite_textlayout *layout, UINT32 pos)
535 if (layout->actual_breakpoints)
536 return layout->actual_breakpoints[pos];
537 return layout->nominal_breakpoints[pos];
540 static inline void init_cluster_metrics(const struct dwrite_textlayout *layout, const struct regular_layout_run *run,
541 UINT16 start_glyph, UINT16 stop_glyph, UINT32 stop_position, UINT16 length, DWRITE_CLUSTER_METRICS *metrics)
543 UINT8 breakcondition;
544 UINT32 position;
545 UINT16 j;
547 /* For clusters made of control chars we report zero glyphs, and we need zero cluster
548 width as well; advances are already computed at this point and are not necessary zero. */
549 metrics->width = 0.0;
550 if (run->run.glyphCount) {
551 for (j = start_glyph; j < stop_glyph; j++)
552 metrics->width += run->run.glyphAdvances[j];
554 metrics->length = length;
556 position = stop_position;
557 if (stop_glyph == run->glyphcount)
558 breakcondition = get_effective_breakpoint(layout, stop_position).breakConditionAfter;
559 else {
560 breakcondition = get_effective_breakpoint(layout, stop_position).breakConditionBefore;
561 if (stop_position) position = stop_position - 1;
564 metrics->canWrapLineAfter = breakcondition == DWRITE_BREAK_CONDITION_CAN_BREAK ||
565 breakcondition == DWRITE_BREAK_CONDITION_MUST_BREAK;
566 if (metrics->length == 1) {
567 WORD type = 0;
569 GetStringTypeW(CT_CTYPE1, &layout->str[position], 1, &type);
570 metrics->isWhitespace = !!(type & C1_SPACE);
571 metrics->isNewline = FALSE /* FIXME */;
572 metrics->isSoftHyphen = layout->str[position] == 0x00ad /* Unicode Soft Hyphen */;
574 else {
575 metrics->isWhitespace = FALSE;
576 metrics->isNewline = FALSE;
577 metrics->isSoftHyphen = FALSE;
579 metrics->isRightToLeft = run->run.bidiLevel & 1;
580 metrics->padding = 0;
585 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
586 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
587 Note that there's no need to reallocate anything at this point as we allocate one cluster per
588 codepoint initially.
591 static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 *cluster)
593 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[*cluster];
594 struct layout_cluster *c = &layout->clusters[*cluster];
595 const struct regular_layout_run *run = &r->u.regular;
596 UINT32 i, start = 0;
598 for (i = 0; i < run->descr.stringLength; i++) {
599 BOOL end = i == run->descr.stringLength - 1;
601 if (run->descr.clusterMap[start] != run->descr.clusterMap[i]) {
602 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->descr.clusterMap[i], i,
603 i - start, metrics);
604 c->position = start;
605 c->run = r;
607 *cluster += 1;
608 metrics++;
609 c++;
610 start = i;
613 if (end) {
614 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->glyphcount, i,
615 i - start + 1, metrics);
616 c->position = start;
617 c->run = r;
619 *cluster += 1;
620 return;
625 static inline FLOAT get_scaled_font_metric(UINT32 metric, FLOAT emSize, const DWRITE_FONT_METRICS *metrics)
627 return (FLOAT)metric * emSize / (FLOAT)metrics->designUnitsPerEm;
630 static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
632 IDWriteTextAnalyzer *analyzer;
633 struct layout_range *range;
634 struct layout_run *r;
635 UINT32 cluster = 0;
636 HRESULT hr;
638 free_layout_eruns(layout);
639 free_layout_runs(layout);
641 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
642 if (!layout->clustermetrics) {
643 layout->clustermetrics = heap_alloc(layout->len*sizeof(*layout->clustermetrics));
644 layout->clusters = heap_alloc(layout->len*sizeof(*layout->clusters));
645 if (!layout->clustermetrics || !layout->clusters) {
646 heap_free(layout->clustermetrics);
647 heap_free(layout->clusters);
648 return E_OUTOFMEMORY;
651 layout->cluster_count = 0;
653 hr = get_textanalyzer(&analyzer);
654 if (FAILED(hr))
655 return hr;
657 LIST_FOR_EACH_ENTRY(range, &layout->ranges, struct layout_range, h.entry) {
658 /* we don't care about ranges that don't contain any text */
659 if (range->h.range.startPosition >= layout->len)
660 break;
662 /* inline objects override actual text in a range */
663 if (range->object) {
664 hr = layout_update_breakpoints_range(layout, range);
665 if (FAILED(hr))
666 return hr;
668 r = alloc_layout_run(LAYOUT_RUN_INLINE);
669 if (!r)
670 return E_OUTOFMEMORY;
672 r->u.object.object = range->object;
673 r->u.object.length = get_clipped_range_length(layout, range);
674 list_add_tail(&layout->runs, &r->entry);
675 continue;
678 /* initial splitting by script */
679 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, &layout->IDWriteTextAnalysisSource_iface,
680 range->h.range.startPosition, get_clipped_range_length(layout, range), &layout->IDWriteTextAnalysisSink_iface);
681 if (FAILED(hr))
682 break;
684 /* this splits it further */
685 hr = IDWriteTextAnalyzer_AnalyzeBidi(analyzer, &layout->IDWriteTextAnalysisSource_iface,
686 range->h.range.startPosition, get_clipped_range_length(layout, range), &layout->IDWriteTextAnalysisSink_iface);
687 if (FAILED(hr))
688 break;
691 /* fill run info */
692 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
693 DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props = NULL;
694 DWRITE_SHAPING_TEXT_PROPERTIES *text_props = NULL;
695 struct regular_layout_run *run = &r->u.regular;
696 DWRITE_FONT_METRICS fontmetrics = { 0 };
697 IDWriteFontFamily *family;
698 UINT32 index, max_count;
699 IDWriteFont *font;
700 BOOL exists = TRUE;
702 /* we need to do very little in case of inline objects */
703 if (r->kind == LAYOUT_RUN_INLINE) {
704 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[cluster];
705 struct layout_cluster *c = &layout->clusters[cluster];
706 DWRITE_INLINE_OBJECT_METRICS inlinemetrics;
708 metrics->width = 0.0;
709 metrics->length = r->u.object.length;
710 metrics->canWrapLineAfter = FALSE;
711 metrics->isWhitespace = FALSE;
712 metrics->isNewline = FALSE;
713 metrics->isSoftHyphen = FALSE;
714 metrics->isRightToLeft = FALSE;
715 metrics->padding = 0;
716 c->run = r;
717 c->position = 0; /* there's always one cluster per inline object, so 0 is valid value */
718 cluster++;
720 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
721 hr = IDWriteInlineObject_GetMetrics(r->u.object.object, &inlinemetrics);
722 if (FAILED(hr)) {
723 memset(&inlinemetrics, 0, sizeof(inlinemetrics));
724 hr = S_OK;
726 metrics->width = inlinemetrics.width;
727 r->baseline = inlinemetrics.baseline;
728 r->height = inlinemetrics.height;
730 /* FIXME: use resolved breakpoints in this case too */
732 continue;
735 range = get_layout_range_by_pos(layout, run->descr.textPosition);
737 hr = IDWriteFontCollection_FindFamilyName(range->collection, range->fontfamily, &index, &exists);
738 if (FAILED(hr) || !exists) {
739 WARN("%s: family %s not found in collection %p\n", debugstr_run(run), debugstr_w(range->fontfamily), range->collection);
740 continue;
743 hr = IDWriteFontCollection_GetFontFamily(range->collection, index, &family);
744 if (FAILED(hr))
745 continue;
747 hr = IDWriteFontFamily_GetFirstMatchingFont(family, range->weight, range->stretch, range->style, &font);
748 IDWriteFontFamily_Release(family);
749 if (FAILED(hr)) {
750 WARN("%s: failed to get a matching font\n", debugstr_run(run));
751 continue;
754 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
755 IDWriteFont_Release(font);
756 if (FAILED(hr))
757 continue;
759 run->run.fontEmSize = range->fontsize;
760 run->descr.localeName = range->locale;
761 run->clustermap = heap_alloc(run->descr.stringLength*sizeof(UINT16));
763 max_count = 3*run->descr.stringLength/2 + 16;
764 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
765 if (!run->clustermap || !run->glyphs)
766 goto memerr;
768 text_props = heap_alloc(run->descr.stringLength*sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
769 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
770 if (!text_props || !glyph_props)
771 goto memerr;
773 while (1) {
774 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, run->descr.string, run->descr.stringLength,
775 run->run.fontFace, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
776 NULL /* FIXME */, NULL, NULL, 0, max_count, run->clustermap, text_props, run->glyphs, glyph_props,
777 &run->glyphcount);
778 if (hr == E_NOT_SUFFICIENT_BUFFER) {
779 heap_free(run->glyphs);
780 heap_free(glyph_props);
782 max_count = run->glyphcount;
784 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
785 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
786 if (!run->glyphs || !glyph_props)
787 goto memerr;
789 continue;
792 break;
795 if (FAILED(hr)) {
796 heap_free(text_props);
797 heap_free(glyph_props);
798 WARN("%s: shaping failed 0x%08x\n", debugstr_run(run), hr);
799 continue;
802 run->run.glyphIndices = run->glyphs;
803 run->descr.clusterMap = run->clustermap;
805 run->advances = heap_alloc(run->glyphcount*sizeof(FLOAT));
806 run->offsets = heap_alloc(run->glyphcount*sizeof(DWRITE_GLYPH_OFFSET));
807 if (!run->advances || !run->offsets)
808 goto memerr;
810 /* now set advances and offsets */
811 if (layout->gdicompatible)
812 hr = IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap,
813 text_props, run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount,
814 run->run.fontFace, run->run.fontEmSize, layout->pixels_per_dip, &layout->transform, layout->use_gdi_natural,
815 run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL, NULL, 0,
816 run->advances, run->offsets);
817 else
818 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap, text_props,
819 run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount, run->run.fontFace,
820 run->run.fontEmSize, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
821 NULL, NULL, 0, run->advances, run->offsets);
823 heap_free(text_props);
824 heap_free(glyph_props);
825 if (FAILED(hr))
826 WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_run(run), hr);
828 run->run.glyphAdvances = run->advances;
829 run->run.glyphOffsets = run->offsets;
831 /* Special treatment of control script, shaping code adds normal glyphs for it,
832 with non-zero advances, and layout code exposes those as zero width clusters,
833 so we have to do it manually. */
834 if (run->sa.script == Script_Common)
835 run->run.glyphCount = 0;
836 else
837 run->run.glyphCount = run->glyphcount;
839 /* baseline derived from font metrics */
840 if (layout->gdicompatible) {
841 hr = IDWriteFontFace_GetGdiCompatibleMetrics(run->run.fontFace,
842 run->run.fontEmSize,
843 layout->pixels_per_dip,
844 &layout->transform,
845 &fontmetrics);
846 if (FAILED(hr))
847 WARN("failed to get compat metrics, 0x%08x\n", hr);
849 else
850 IDWriteFontFace_GetMetrics(run->run.fontFace, &fontmetrics);
852 r->baseline = get_scaled_font_metric(fontmetrics.ascent, run->run.fontEmSize, &fontmetrics);
853 r->height = get_scaled_font_metric(fontmetrics.ascent + fontmetrics.descent, run->run.fontEmSize, &fontmetrics);
855 layout_set_cluster_metrics(layout, r, &cluster);
857 continue;
859 memerr:
860 heap_free(text_props);
861 heap_free(glyph_props);
862 heap_free(run->clustermap);
863 heap_free(run->glyphs);
864 heap_free(run->advances);
865 heap_free(run->offsets);
866 run->advances = NULL;
867 run->offsets = NULL;
868 run->clustermap = run->glyphs = NULL;
869 hr = E_OUTOFMEMORY;
870 break;
873 if (hr == S_OK) {
874 layout->cluster_count = cluster;
875 if (cluster)
876 layout->clustermetrics[cluster-1].canWrapLineAfter = TRUE;
879 IDWriteTextAnalyzer_Release(analyzer);
880 return hr;
883 static HRESULT layout_compute(struct dwrite_textlayout *layout)
885 HRESULT hr;
887 if (!(layout->recompute & RECOMPUTE_NOMINAL_RUNS))
888 return S_OK;
890 /* nominal breakpoints are evaluated only once, because string never changes */
891 if (!layout->nominal_breakpoints) {
892 IDWriteTextAnalyzer *analyzer;
893 HRESULT hr;
895 layout->nominal_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
896 if (!layout->nominal_breakpoints)
897 return E_OUTOFMEMORY;
899 hr = get_textanalyzer(&analyzer);
900 if (FAILED(hr))
901 return hr;
903 hr = IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer, &layout->IDWriteTextAnalysisSource_iface,
904 0, layout->len, &layout->IDWriteTextAnalysisSink_iface);
905 IDWriteTextAnalyzer_Release(analyzer);
907 if (layout->actual_breakpoints) {
908 heap_free(layout->actual_breakpoints);
909 layout->actual_breakpoints = NULL;
912 hr = layout_compute_runs(layout);
914 if (TRACE_ON(dwrite)) {
915 struct layout_run *cur;
917 LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
918 if (cur->kind == LAYOUT_RUN_INLINE)
919 TRACE("run inline object %p, len %u\n", cur->u.object.object, cur->u.object.length);
920 else
921 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur->u.regular.descr.textPosition, cur->u.regular.descr.textPosition +
922 cur->u.regular.descr.stringLength-1, cur->u.regular.descr.stringLength, cur->u.regular.run.bidiLevel);
926 layout->recompute &= ~RECOMPUTE_NOMINAL_RUNS;
927 return hr;
930 static inline FLOAT get_cluster_range_width(struct dwrite_textlayout *layout, UINT32 start, UINT32 end)
932 FLOAT width = 0.0;
933 for (; start < end; start++)
934 width += layout->clustermetrics[start].width;
935 return width;
938 static struct layout_range_header *get_layout_range_header_by_pos(struct list *ranges, UINT32 pos)
940 struct layout_range_header *cur;
942 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
943 DWRITE_TEXT_RANGE *r = &cur->range;
944 if (r->startPosition <= pos && pos < r->startPosition + r->length)
945 return cur;
948 return NULL;
951 static inline IUnknown *layout_get_effect_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
953 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->effects, pos);
954 return ((struct layout_range_effect*)h)->effect;
957 static inline BOOL layout_is_erun_rtl(const struct layout_effective_run *erun)
959 return erun->run->u.regular.run.bidiLevel & 1;
962 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
963 'cluster_count' indicates how many clusters to add, including first one. */
964 static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 first_cluster,
965 UINT32 cluster_count, UINT32 line, FLOAT origin_x, BOOL strikethrough)
967 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
968 UINT32 i, start, length, last_cluster;
969 struct layout_effective_run *run;
971 if (r->kind == LAYOUT_RUN_INLINE) {
972 struct layout_effective_inline *inlineobject;
974 inlineobject = heap_alloc(sizeof(*inlineobject));
975 if (!inlineobject)
976 return E_OUTOFMEMORY;
978 inlineobject->object = r->u.object.object;
979 inlineobject->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
980 inlineobject->origin_x = is_rtl ? origin_x - inlineobject->width : origin_x;
981 inlineobject->origin_y = 0.0; /* set after line is built */
982 inlineobject->align_dx = 0.0;
984 /* It's not clear how these two are set, possibly directionality
985 is derived from surrounding text (replaced text could have
986 different ranges which differ in reading direction). */
987 inlineobject->is_sideways = FALSE;
988 inlineobject->is_rtl = FALSE;
989 inlineobject->line = line;
991 /* effect assigned from start position and on is used for inline objects */
992 inlineobject->effect = layout_get_effect_from_pos(layout, layout->clusters[first_cluster].position);
994 list_add_tail(&layout->inlineobjects, &inlineobject->entry);
995 return S_OK;
998 run = heap_alloc(sizeof(*run));
999 if (!run)
1000 return E_OUTOFMEMORY;
1002 /* No need to iterate for that, use simple fact that:
1003 <last cluster position> = first cluster position> + <sum of cluster lengths not including last one> */
1004 last_cluster = first_cluster + cluster_count - 1;
1005 length = layout->clusters[last_cluster].position - layout->clusters[first_cluster].position +
1006 layout->clustermetrics[last_cluster].length;
1008 run->clustermap = heap_alloc(sizeof(UINT16)*length);
1009 if (!run->clustermap) {
1010 heap_free(run);
1011 return E_OUTOFMEMORY;
1014 run->run = r;
1015 run->start = start = layout->clusters[first_cluster].position;
1016 run->length = length;
1017 run->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1019 /* Check if run direction matches paragraph direction, if it doesn't adjust by
1020 run width */
1021 if (layout_is_erun_rtl(run) ^ is_rtl)
1022 run->origin_x = is_rtl ? origin_x - run->width : origin_x + run->width;
1023 else
1024 run->origin_x = origin_x;
1026 run->origin_y = 0.0; /* set after line is built */
1027 run->align_dx = 0.0;
1028 run->line = line;
1030 if (r->u.regular.run.glyphCount) {
1031 /* trim from the left */
1032 run->glyphcount = r->u.regular.run.glyphCount - r->u.regular.clustermap[start];
1033 /* trim from the right */
1034 if (start + length < r->u.regular.descr.stringLength - 1)
1035 run->glyphcount -= r->u.regular.run.glyphCount - r->u.regular.clustermap[start + length];
1037 else
1038 run->glyphcount = 0;
1040 /* cluster map needs to be shifted */
1041 for (i = 0; i < length; i++)
1042 run->clustermap[i] = r->u.regular.clustermap[start + i] - r->u.regular.clustermap[start];
1044 list_add_tail(&layout->eruns, &run->entry);
1046 /* Strikethrough style is guaranteed to be consistent within effective run,
1047 it's width equals to run width, thikness and offset are derived from
1048 font metrics, rest of the values are from layout or run itself */
1049 if (strikethrough) {
1050 DWRITE_FONT_METRICS metrics = { 0 };
1051 struct layout_strikethrough *s;
1053 s = heap_alloc(sizeof(*s));
1054 if (!s)
1055 return E_OUTOFMEMORY;
1057 if (layout->gdicompatible) {
1058 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(
1059 r->u.regular.run.fontFace,
1060 r->u.regular.run.fontEmSize,
1061 layout->pixels_per_dip,
1062 &layout->transform,
1063 &metrics);
1064 if (FAILED(hr))
1065 WARN("failed to get font metrics, 0x%08x\n", hr);
1067 else
1068 IDWriteFontFace_GetMetrics(r->u.regular.run.fontFace, &metrics);
1070 s->s.width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1071 s->s.thickness = metrics.strikethroughThickness;
1072 s->s.offset = metrics.strikethroughPosition;
1073 s->s.readingDirection = layout->format.readingdir;
1074 s->s.flowDirection = layout->format.flow;
1075 s->s.localeName = r->u.regular.descr.localeName;
1076 s->s.measuringMode = DWRITE_MEASURING_MODE_NATURAL; /* FIXME */
1077 s->run = run;
1079 list_add_tail(&layout->strikethrough, &s->entry);
1082 return S_OK;
1085 static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_LINE_METRICS *metrics, UINT32 *line)
1087 if (!layout->line_alloc) {
1088 layout->line_alloc = 5;
1089 layout->lines = heap_alloc(layout->line_alloc*sizeof(*layout->lines));
1090 if (!layout->lines)
1091 return E_OUTOFMEMORY;
1094 if (layout->metrics.lineCount == layout->line_alloc) {
1095 DWRITE_LINE_METRICS *l = heap_realloc(layout->lines, layout->line_alloc*2*sizeof(*layout->lines));
1096 if (!l)
1097 return E_OUTOFMEMORY;
1098 layout->lines = l;
1099 layout->line_alloc *= 2;
1102 layout->lines[*line] = *metrics;
1103 layout->metrics.lineCount += 1;
1104 *line += 1;
1105 return S_OK;
1108 static inline BOOL layout_get_strikethrough_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1110 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->strike_ranges, pos);
1111 return ((struct layout_range_bool*)h)->value;
1114 static inline struct layout_effective_run *layout_get_next_erun(struct dwrite_textlayout *layout,
1115 const struct layout_effective_run *cur)
1117 struct list *e;
1119 if (!cur)
1120 e = list_head(&layout->eruns);
1121 else
1122 e = list_next(&layout->eruns, &cur->entry);
1123 if (!e)
1124 return NULL;
1125 return LIST_ENTRY(e, struct layout_effective_run, entry);
1128 static inline struct layout_effective_inline *layout_get_next_inline_run(struct dwrite_textlayout *layout,
1129 const struct layout_effective_inline *cur)
1131 struct list *e;
1133 if (!cur)
1134 e = list_head(&layout->inlineobjects);
1135 else
1136 e = list_next(&layout->inlineobjects, &cur->entry);
1137 if (!e)
1138 return NULL;
1139 return LIST_ENTRY(e, struct layout_effective_inline, entry);
1142 static FLOAT layout_get_line_width(struct dwrite_textlayout *layout,
1143 struct layout_effective_run *erun, struct layout_effective_inline *inrun, UINT32 line)
1145 FLOAT width = 0.0;
1147 while (erun && erun->line == line) {
1148 width += erun->width;
1149 erun = layout_get_next_erun(layout, erun);
1150 if (!erun)
1151 break;
1154 while (inrun && inrun->line == line) {
1155 width += inrun->width;
1156 inrun = layout_get_next_inline_run(layout, inrun);
1157 if (!inrun)
1158 break;
1161 return width;
1164 static void layout_apply_leading_alignment(struct dwrite_textlayout *layout)
1166 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1167 struct layout_effective_inline *inrun;
1168 struct layout_effective_run *erun;
1170 erun = layout_get_next_erun(layout, NULL);
1171 inrun = layout_get_next_inline_run(layout, NULL);
1173 while (erun) {
1174 erun->align_dx = 0.0;
1175 erun = layout_get_next_erun(layout, erun);
1178 while (inrun) {
1179 inrun->align_dx = 0.0;
1180 inrun = layout_get_next_inline_run(layout, inrun);
1183 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0;
1186 static void layout_apply_trailing_alignment(struct dwrite_textlayout *layout)
1188 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1189 struct layout_effective_inline *inrun;
1190 struct layout_effective_run *erun;
1191 UINT32 line;
1193 erun = layout_get_next_erun(layout, NULL);
1194 inrun = layout_get_next_inline_run(layout, NULL);
1196 for (line = 0; line < layout->metrics.lineCount; line++) {
1197 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1198 FLOAT shift = layout->metrics.layoutWidth - width;
1200 if (is_rtl)
1201 shift *= -1.0;
1203 while (erun && erun->line == line) {
1204 erun->align_dx = shift;
1205 erun = layout_get_next_erun(layout, erun);
1208 while (inrun && inrun->line == line) {
1209 inrun->align_dx = shift;
1210 inrun = layout_get_next_inline_run(layout, inrun);
1214 layout->metrics.left = is_rtl ? 0.0 : layout->metrics.layoutWidth - layout->metrics.width;
1217 static void layout_apply_centered_alignment(struct dwrite_textlayout *layout)
1219 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1220 struct layout_effective_inline *inrun;
1221 struct layout_effective_run *erun;
1222 UINT32 line;
1224 erun = layout_get_next_erun(layout, NULL);
1225 inrun = layout_get_next_inline_run(layout, NULL);
1227 for (line = 0; line < layout->metrics.lineCount; line++) {
1228 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1229 FLOAT shift = (layout->metrics.layoutWidth - width) / 2.0;
1231 if (is_rtl)
1232 shift *= -1.0;
1234 while (erun && erun->line == line) {
1235 erun->align_dx = shift;
1236 erun = layout_get_next_erun(layout, erun);
1239 while (inrun && inrun->line == line) {
1240 inrun->align_dx = shift;
1241 inrun = layout_get_next_inline_run(layout, inrun);
1245 layout->metrics.left = (layout->metrics.layoutWidth - layout->metrics.width) / 2.0;
1248 static void layout_apply_text_alignment(struct dwrite_textlayout *layout)
1250 switch (layout->format.textalignment)
1252 case DWRITE_TEXT_ALIGNMENT_LEADING:
1253 layout_apply_leading_alignment(layout);
1254 break;
1255 case DWRITE_TEXT_ALIGNMENT_TRAILING:
1256 layout_apply_trailing_alignment(layout);
1257 break;
1258 case DWRITE_TEXT_ALIGNMENT_CENTER:
1259 layout_apply_centered_alignment(layout);
1260 break;
1261 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED:
1262 FIXME("alignment %d not implemented\n", layout->format.textalignment);
1263 break;
1264 default:
1269 static void layout_apply_par_alignment(struct dwrite_textlayout *layout)
1271 struct layout_effective_inline *inrun;
1272 struct layout_effective_run *erun;
1273 FLOAT origin_y = 0.0;
1274 UINT32 line;
1276 /* alignment mode defines origin, after that all run origins are updated
1277 the same way */
1279 switch (layout->format.paralign)
1281 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR:
1282 origin_y = 0.0;
1283 break;
1284 case DWRITE_PARAGRAPH_ALIGNMENT_FAR:
1285 origin_y = layout->metrics.layoutHeight - layout->metrics.height;
1286 break;
1287 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER:
1288 origin_y = (layout->metrics.layoutHeight - layout->metrics.height) / 2.0;
1289 break;
1290 default:
1294 layout->metrics.top = origin_y;
1296 erun = layout_get_next_erun(layout, NULL);
1297 inrun = layout_get_next_inline_run(layout, NULL);
1298 for (line = 0; line < layout->metrics.lineCount; line++) {
1299 origin_y += layout->lines[line].baseline;
1301 while (erun && erun->line == line) {
1302 erun->origin_y = origin_y;
1303 erun = layout_get_next_erun(layout, erun);
1306 while (inrun && inrun->line == line) {
1307 inrun->origin_y = origin_y;
1308 inrun = layout_get_next_inline_run(layout, inrun);
1313 static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
1315 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1316 struct layout_effective_inline *inrun;
1317 struct layout_effective_run *erun;
1318 const struct layout_run *run;
1319 DWRITE_LINE_METRICS metrics;
1320 FLOAT width, origin_x, origin_y;
1321 UINT32 i, start, line, textpos;
1322 HRESULT hr;
1323 BOOL s[2];
1325 if (!(layout->recompute & RECOMPUTE_EFFECTIVE_RUNS))
1326 return S_OK;
1328 hr = layout_compute(layout);
1329 if (FAILED(hr))
1330 return hr;
1332 layout->metrics.lineCount = 0;
1333 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0;
1334 line = 0;
1335 run = layout->clusters[0].run;
1336 memset(&metrics, 0, sizeof(metrics));
1337 s[0] = s[1] = layout_get_strikethrough_from_pos(layout, 0);
1339 for (i = 0, start = 0, textpos = 0, width = 0.0; i < layout->cluster_count; i++) {
1340 BOOL overflow;
1342 s[1] = layout_get_strikethrough_from_pos(layout, textpos);
1344 /* switched to next nominal run, at this point all previous pending clusters are already
1345 checked for layout line overflow, so new effective run will fit in current line */
1346 if (run != layout->clusters[i].run || s[0] != s[1]) {
1347 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, s[0]);
1348 if (FAILED(hr))
1349 return hr;
1350 origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) :
1351 get_cluster_range_width(layout, start, i);
1352 run = layout->clusters[i].run;
1353 start = i;
1356 overflow = layout->clustermetrics[i].canWrapLineAfter &&
1357 (width + layout->clustermetrics[i].width > layout->metrics.layoutWidth);
1358 /* check if we got new */
1359 if (overflow ||
1360 layout->clustermetrics[i].isNewline || /* always wrap on new line */
1361 i == layout->cluster_count - 1) /* end of the text */ {
1363 UINT32 strlength, last_cluster = i, index;
1364 FLOAT descent, trailingspacewidth;
1366 if (!overflow) {
1367 width += layout->clustermetrics[i].width;
1368 metrics.length += layout->clustermetrics[i].length;
1369 last_cluster = i;
1371 else
1372 last_cluster = i ? i - 1 : i;
1374 if (i >= start) {
1375 hr = layout_add_effective_run(layout, run, start, last_cluster - start + 1, line, origin_x, s[0]);
1376 if (FAILED(hr))
1377 return hr;
1378 /* we don't need to update origin for next run as we're going to wrap */
1381 /* take a look at clusters we got for this line in reverse order to set
1382 trailing properties for current line */
1383 strlength = metrics.length;
1384 index = last_cluster;
1385 trailingspacewidth = 0.0;
1386 while (strlength) {
1387 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1389 if (!cluster->isNewline && !cluster->isWhitespace)
1390 break;
1392 if (cluster->isNewline) {
1393 metrics.trailingWhitespaceLength += cluster->length;
1394 metrics.newlineLength += cluster->length;
1397 if (cluster->isWhitespace) {
1398 metrics.trailingWhitespaceLength += cluster->length;
1399 trailingspacewidth += cluster->width;
1402 strlength -= cluster->length;
1403 index--;
1406 /* look for max baseline and descent for this line */
1407 strlength = metrics.length;
1408 index = last_cluster;
1409 metrics.baseline = 0.0;
1410 descent = 0.0;
1411 while (strlength) {
1412 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1413 const struct layout_run *cur = layout->clusters[index].run;
1414 FLOAT cur_descent = cur->height - cur->baseline;
1416 if (cur->baseline > metrics.baseline)
1417 metrics.baseline = cur->baseline;
1419 if (cur_descent > descent)
1420 descent = cur_descent;
1422 strlength -= cluster->length;
1423 index--;
1425 metrics.height = descent + metrics.baseline;
1427 if (width > layout->metrics.widthIncludingTrailingWhitespace)
1428 layout->metrics.widthIncludingTrailingWhitespace = width;
1429 if (width - trailingspacewidth > layout->metrics.width)
1430 layout->metrics.width = width - trailingspacewidth;
1432 metrics.isTrimmed = width > layout->metrics.layoutWidth;
1433 hr = layout_set_line_metrics(layout, &metrics, &line);
1434 if (FAILED(hr))
1435 return hr;
1437 width = layout->clustermetrics[i].width;
1438 memset(&metrics, 0, sizeof(metrics));
1439 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0;
1440 start = i;
1442 else {
1443 metrics.length += layout->clustermetrics[i].length;
1444 width += layout->clustermetrics[i].width;
1447 s[0] = s[1];
1448 textpos += layout->clustermetrics[i].length;
1451 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0;
1452 layout->metrics.top = 0.0;
1453 layout->metrics.maxBidiReorderingDepth = 1; /* FIXME */
1454 layout->metrics.height = 0.0;
1456 /* Now all line info is here, update effective runs positions in flow direction */
1457 erun = layout_get_next_erun(layout, NULL);
1458 inrun = layout_get_next_inline_run(layout, NULL);
1460 origin_y = 0.0;
1461 for (line = 0; line < layout->metrics.lineCount; line++) {
1463 origin_y += layout->lines[line].baseline;
1465 /* For all runs on this line */
1466 while (erun && erun->line == line) {
1467 erun->origin_y = origin_y;
1468 erun = layout_get_next_erun(layout, erun);
1471 /* Same for inline runs */
1472 while (inrun && inrun->line == line) {
1473 inrun->origin_y = origin_y;
1474 inrun = layout_get_next_inline_run(layout, inrun);
1477 layout->metrics.height += layout->lines[line].height;
1480 /* initial alignment is always leading */
1481 if (layout->format.textalignment != DWRITE_TEXT_ALIGNMENT_LEADING)
1482 layout_apply_text_alignment(layout);
1484 /* initial paragraph alignment is always near */
1485 if (layout->format.paralign != DWRITE_PARAGRAPH_ALIGNMENT_NEAR)
1486 layout_apply_par_alignment(layout);
1488 layout->metrics.heightIncludingTrailingWhitespace = layout->metrics.height; /* FIXME: not true for vertical text */
1490 layout->recompute &= ~RECOMPUTE_EFFECTIVE_RUNS;
1491 return hr;
1494 static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
1496 struct layout_range_spacing const *range_spacing = (struct layout_range_spacing*)h;
1497 struct layout_range_effect const *range_effect = (struct layout_range_effect*)h;
1498 struct layout_range_bool const *range_bool = (struct layout_range_bool*)h;
1499 struct layout_range const *range = (struct layout_range*)h;
1501 switch (attr) {
1502 case LAYOUT_RANGE_ATTR_WEIGHT:
1503 return range->weight == value->u.weight;
1504 case LAYOUT_RANGE_ATTR_STYLE:
1505 return range->style == value->u.style;
1506 case LAYOUT_RANGE_ATTR_STRETCH:
1507 return range->stretch == value->u.stretch;
1508 case LAYOUT_RANGE_ATTR_FONTSIZE:
1509 return range->fontsize == value->u.fontsize;
1510 case LAYOUT_RANGE_ATTR_INLINE:
1511 return range->object == value->u.object;
1512 case LAYOUT_RANGE_ATTR_EFFECT:
1513 return range_effect->effect == value->u.effect;
1514 case LAYOUT_RANGE_ATTR_UNDERLINE:
1515 return range->underline == value->u.underline;
1516 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
1517 return range_bool->value == value->u.strikethrough;
1518 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
1519 return range->pair_kerning == value->u.pair_kerning;
1520 case LAYOUT_RANGE_ATTR_FONTCOLL:
1521 return range->collection == value->u.collection;
1522 case LAYOUT_RANGE_ATTR_LOCALE:
1523 return strcmpW(range->locale, value->u.locale) == 0;
1524 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1525 return strcmpW(range->fontfamily, value->u.fontfamily) == 0;
1526 case LAYOUT_RANGE_ATTR_SPACING:
1527 return range_spacing->leading == value->u.spacing[0] &&
1528 range_spacing->trailing == value->u.spacing[1] &&
1529 range_spacing->min_advance == value->u.spacing[2];
1530 default:
1534 return FALSE;
1537 static inline BOOL is_same_layout_attributes(struct layout_range_header const *hleft, struct layout_range_header const *hright)
1539 switch (hleft->kind)
1541 case LAYOUT_RANGE_REGULAR:
1543 struct layout_range const *left = (struct layout_range const*)hleft;
1544 struct layout_range const *right = (struct layout_range const*)hright;
1545 return left->weight == right->weight &&
1546 left->style == right->style &&
1547 left->stretch == right->stretch &&
1548 left->fontsize == right->fontsize &&
1549 left->object == right->object &&
1550 left->underline == right->underline &&
1551 left->pair_kerning == right->pair_kerning &&
1552 left->collection == right->collection &&
1553 !strcmpW(left->locale, right->locale) &&
1554 !strcmpW(left->fontfamily, right->fontfamily);
1556 case LAYOUT_RANGE_STRIKETHROUGH:
1558 struct layout_range_bool const *left = (struct layout_range_bool const*)hleft;
1559 struct layout_range_bool const *right = (struct layout_range_bool const*)hright;
1560 return left->value == right->value;
1562 case LAYOUT_RANGE_EFFECT:
1564 struct layout_range_effect const *left = (struct layout_range_effect const*)hleft;
1565 struct layout_range_effect const *right = (struct layout_range_effect const*)hright;
1566 return left->effect == right->effect;
1568 case LAYOUT_RANGE_SPACING:
1570 struct layout_range_spacing const *left = (struct layout_range_spacing const*)hleft;
1571 struct layout_range_spacing const *right = (struct layout_range_spacing const*)hright;
1572 return left->leading == right->leading &&
1573 left->trailing == right->trailing &&
1574 left->min_advance == right->min_advance;
1576 default:
1577 FIXME("unknown range kind %d\n", hleft->kind);
1578 return FALSE;
1582 static inline BOOL is_same_text_range(const DWRITE_TEXT_RANGE *left, const DWRITE_TEXT_RANGE *right)
1584 return left->startPosition == right->startPosition && left->length == right->length;
1587 /* Allocates range and inits it with default values from text format. */
1588 static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout *layout, const DWRITE_TEXT_RANGE *r,
1589 enum layout_range_kind kind)
1591 struct layout_range_header *h;
1593 switch (kind)
1595 case LAYOUT_RANGE_REGULAR:
1597 struct layout_range *range;
1599 range = heap_alloc(sizeof(*range));
1600 if (!range) return NULL;
1602 range->weight = layout->format.weight;
1603 range->style = layout->format.style;
1604 range->stretch = layout->format.stretch;
1605 range->fontsize = layout->format.fontsize;
1606 range->object = NULL;
1607 range->underline = FALSE;
1608 range->pair_kerning = FALSE;
1610 range->fontfamily = heap_strdupW(layout->format.family_name);
1611 if (!range->fontfamily) {
1612 heap_free(range);
1613 return NULL;
1616 range->collection = layout->format.collection;
1617 if (range->collection)
1618 IDWriteFontCollection_AddRef(range->collection);
1619 strcpyW(range->locale, layout->format.locale);
1621 h = &range->h;
1622 break;
1624 case LAYOUT_RANGE_STRIKETHROUGH:
1626 struct layout_range_bool *range;
1628 range = heap_alloc(sizeof(*range));
1629 if (!range) return NULL;
1631 range->value = FALSE;
1632 h = &range->h;
1633 break;
1635 case LAYOUT_RANGE_EFFECT:
1637 struct layout_range_effect *range;
1639 range = heap_alloc(sizeof(*range));
1640 if (!range) return NULL;
1642 range->effect = NULL;
1643 h = &range->h;
1644 break;
1646 case LAYOUT_RANGE_SPACING:
1648 struct layout_range_spacing *range;
1650 range = heap_alloc(sizeof(*range));
1651 if (!range) return NULL;
1653 range->leading = 0.0;
1654 range->trailing = 0.0;
1655 range->min_advance = 0.0;
1656 h = &range->h;
1657 break;
1659 default:
1660 FIXME("unknown range kind %d\n", kind);
1661 return NULL;
1664 h->kind = kind;
1665 h->range = *r;
1666 return h;
1669 static struct layout_range_header *alloc_layout_range_from(struct layout_range_header *h, const DWRITE_TEXT_RANGE *r)
1671 struct layout_range_header *ret;
1673 switch (h->kind)
1675 case LAYOUT_RANGE_REGULAR:
1677 struct layout_range *from = (struct layout_range*)h;
1679 struct layout_range *range = heap_alloc(sizeof(*range));
1680 if (!range) return NULL;
1682 *range = *from;
1683 range->fontfamily = heap_strdupW(from->fontfamily);
1684 if (!range->fontfamily) {
1685 heap_free(range);
1686 return NULL;
1689 /* update refcounts */
1690 if (range->object)
1691 IDWriteInlineObject_AddRef(range->object);
1692 if (range->collection)
1693 IDWriteFontCollection_AddRef(range->collection);
1694 ret = &range->h;
1695 break;
1697 case LAYOUT_RANGE_STRIKETHROUGH:
1699 struct layout_range_bool *strike = heap_alloc(sizeof(*strike));
1700 if (!strike) return NULL;
1702 *strike = *(struct layout_range_bool*)h;
1703 ret = &strike->h;
1704 break;
1706 case LAYOUT_RANGE_EFFECT:
1708 struct layout_range_effect *effect = heap_alloc(sizeof(*effect));
1709 if (!effect) return NULL;
1711 *effect = *(struct layout_range_effect*)h;
1712 if (effect->effect)
1713 IUnknown_AddRef(effect->effect);
1714 ret = &effect->h;
1715 break;
1717 case LAYOUT_RANGE_SPACING:
1719 struct layout_range_spacing *spacing = heap_alloc(sizeof(*spacing));
1720 if (!spacing) return NULL;
1722 *spacing = *(struct layout_range_spacing*)h;
1723 ret = &spacing->h;
1724 break;
1726 default:
1727 FIXME("unknown range kind %d\n", h->kind);
1728 return NULL;
1731 ret->range = *r;
1732 return ret;
1735 static void free_layout_range(struct layout_range_header *h)
1737 if (!h)
1738 return;
1740 switch (h->kind)
1742 case LAYOUT_RANGE_REGULAR:
1744 struct layout_range *range = (struct layout_range*)h;
1746 if (range->object)
1747 IDWriteInlineObject_Release(range->object);
1748 if (range->collection)
1749 IDWriteFontCollection_Release(range->collection);
1750 heap_free(range->fontfamily);
1751 break;
1753 case LAYOUT_RANGE_EFFECT:
1755 struct layout_range_effect *effect = (struct layout_range_effect*)h;
1756 if (effect->effect)
1757 IUnknown_Release(effect->effect);
1758 break;
1760 default:
1764 heap_free(h);
1767 static void free_layout_ranges_list(struct dwrite_textlayout *layout)
1769 struct layout_range_header *cur, *cur2;
1771 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->ranges, struct layout_range_header, entry) {
1772 list_remove(&cur->entry);
1773 free_layout_range(cur);
1776 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->strike_ranges, struct layout_range_header, entry) {
1777 list_remove(&cur->entry);
1778 free_layout_range(cur);
1781 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->effects, struct layout_range_header, entry) {
1782 list_remove(&cur->entry);
1783 free_layout_range(cur);
1786 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->spacing, struct layout_range_header, entry) {
1787 list_remove(&cur->entry);
1788 free_layout_range(cur);
1792 static struct layout_range_header *find_outer_range(struct list *ranges, const DWRITE_TEXT_RANGE *range)
1794 struct layout_range_header *cur;
1796 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
1798 if (cur->range.startPosition > range->startPosition)
1799 return NULL;
1801 if ((cur->range.startPosition + cur->range.length < range->startPosition + range->length) &&
1802 (range->startPosition < cur->range.startPosition + cur->range.length))
1803 return NULL;
1804 if (cur->range.startPosition + cur->range.length >= range->startPosition + range->length)
1805 return cur;
1808 return NULL;
1811 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos)
1813 struct layout_range *cur;
1815 LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, h.entry) {
1816 DWRITE_TEXT_RANGE *r = &cur->h.range;
1817 if (r->startPosition <= pos && pos < r->startPosition + r->length)
1818 return cur;
1821 return NULL;
1824 static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
1826 if (*dest == value) return FALSE;
1828 if (*dest)
1829 IUnknown_Release(*dest);
1830 *dest = value;
1831 if (*dest)
1832 IUnknown_AddRef(*dest);
1834 return TRUE;
1837 static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
1839 struct layout_range_spacing *dest_spacing = (struct layout_range_spacing*)h;
1840 struct layout_range_effect *dest_effect = (struct layout_range_effect*)h;
1841 struct layout_range_bool *dest_bool = (struct layout_range_bool*)h;
1842 struct layout_range *dest = (struct layout_range*)h;
1844 BOOL changed = FALSE;
1846 switch (attr) {
1847 case LAYOUT_RANGE_ATTR_WEIGHT:
1848 changed = dest->weight != value->u.weight;
1849 dest->weight = value->u.weight;
1850 break;
1851 case LAYOUT_RANGE_ATTR_STYLE:
1852 changed = dest->style != value->u.style;
1853 dest->style = value->u.style;
1854 break;
1855 case LAYOUT_RANGE_ATTR_STRETCH:
1856 changed = dest->stretch != value->u.stretch;
1857 dest->stretch = value->u.stretch;
1858 break;
1859 case LAYOUT_RANGE_ATTR_FONTSIZE:
1860 changed = dest->fontsize != value->u.fontsize;
1861 dest->fontsize = value->u.fontsize;
1862 break;
1863 case LAYOUT_RANGE_ATTR_INLINE:
1864 changed = set_layout_range_iface_attr((IUnknown**)&dest->object, (IUnknown*)value->u.object);
1865 break;
1866 case LAYOUT_RANGE_ATTR_EFFECT:
1867 changed = set_layout_range_iface_attr((IUnknown**)&dest_effect->effect, (IUnknown*)value->u.effect);
1868 break;
1869 case LAYOUT_RANGE_ATTR_UNDERLINE:
1870 changed = dest->underline != value->u.underline;
1871 dest->underline = value->u.underline;
1872 break;
1873 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
1874 changed = dest_bool->value != value->u.strikethrough;
1875 dest_bool->value = value->u.strikethrough;
1876 break;
1877 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
1878 changed = dest->pair_kerning != value->u.pair_kerning;
1879 dest->pair_kerning = value->u.pair_kerning;
1880 break;
1881 case LAYOUT_RANGE_ATTR_FONTCOLL:
1882 changed = set_layout_range_iface_attr((IUnknown**)&dest->collection, (IUnknown*)value->u.collection);
1883 break;
1884 case LAYOUT_RANGE_ATTR_LOCALE:
1885 changed = strcmpW(dest->locale, value->u.locale) != 0;
1886 if (changed)
1887 strcpyW(dest->locale, value->u.locale);
1888 break;
1889 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1890 changed = strcmpW(dest->fontfamily, value->u.fontfamily) != 0;
1891 if (changed) {
1892 heap_free(dest->fontfamily);
1893 dest->fontfamily = heap_strdupW(value->u.fontfamily);
1895 break;
1896 case LAYOUT_RANGE_ATTR_SPACING:
1897 changed = dest_spacing->leading != value->u.spacing[0] ||
1898 dest_spacing->trailing != value->u.spacing[1] ||
1899 dest_spacing->min_advance != value->u.spacing[2];
1900 dest_spacing->leading = value->u.spacing[0];
1901 dest_spacing->trailing = value->u.spacing[1];
1902 dest_spacing->min_advance = value->u.spacing[2];
1903 break;
1904 default:
1908 return changed;
1911 static inline BOOL is_in_layout_range(const DWRITE_TEXT_RANGE *outer, const DWRITE_TEXT_RANGE *inner)
1913 return (inner->startPosition >= outer->startPosition) &&
1914 (inner->startPosition + inner->length <= outer->startPosition + outer->length);
1917 static inline HRESULT return_range(const struct layout_range_header *h, DWRITE_TEXT_RANGE *r)
1919 if (r) *r = h->range;
1920 return S_OK;
1923 /* Set attribute value for given range, does all needed splitting/merging of existing ranges. */
1924 static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
1926 struct layout_range_header *cur, *right, *left, *outer;
1927 BOOL changed = FALSE;
1928 struct list *ranges;
1929 DWRITE_TEXT_RANGE r;
1931 /* ignore zero length ranges */
1932 if (value->range.length == 0)
1933 return S_OK;
1935 /* select from ranges lists */
1936 switch (attr)
1938 case LAYOUT_RANGE_ATTR_WEIGHT:
1939 case LAYOUT_RANGE_ATTR_STYLE:
1940 case LAYOUT_RANGE_ATTR_STRETCH:
1941 case LAYOUT_RANGE_ATTR_FONTSIZE:
1942 case LAYOUT_RANGE_ATTR_INLINE:
1943 case LAYOUT_RANGE_ATTR_UNDERLINE:
1944 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
1945 case LAYOUT_RANGE_ATTR_FONTCOLL:
1946 case LAYOUT_RANGE_ATTR_LOCALE:
1947 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1948 ranges = &layout->ranges;
1949 break;
1950 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
1951 ranges = &layout->strike_ranges;
1952 break;
1953 case LAYOUT_RANGE_ATTR_EFFECT:
1954 ranges = &layout->effects;
1955 break;
1956 case LAYOUT_RANGE_ATTR_SPACING:
1957 ranges = &layout->spacing;
1958 break;
1959 default:
1960 FIXME("unknown attr kind %d\n", attr);
1961 return E_FAIL;
1964 /* If new range is completely within existing range, split existing range in two */
1965 if ((outer = find_outer_range(ranges, &value->range))) {
1967 /* no need to add same range */
1968 if (is_same_layout_attrvalue(outer, attr, value))
1969 return S_OK;
1971 /* for matching range bounds just replace data */
1972 if (is_same_text_range(&outer->range, &value->range)) {
1973 changed = set_layout_range_attrval(outer, attr, value);
1974 goto done;
1977 /* add new range to the left */
1978 if (value->range.startPosition == outer->range.startPosition) {
1979 left = alloc_layout_range_from(outer, &value->range);
1980 if (!left) return E_OUTOFMEMORY;
1982 changed = set_layout_range_attrval(left, attr, value);
1983 list_add_before(&outer->entry, &left->entry);
1984 outer->range.startPosition += value->range.length;
1985 outer->range.length -= value->range.length;
1986 goto done;
1989 /* add new range to the right */
1990 if (value->range.startPosition + value->range.length == outer->range.startPosition + outer->range.length) {
1991 right = alloc_layout_range_from(outer, &value->range);
1992 if (!right) return E_OUTOFMEMORY;
1994 changed = set_layout_range_attrval(right, attr, value);
1995 list_add_after(&outer->entry, &right->entry);
1996 outer->range.length -= value->range.length;
1997 goto done;
2000 r.startPosition = value->range.startPosition + value->range.length;
2001 r.length = outer->range.length + outer->range.startPosition - r.startPosition;
2003 /* right part */
2004 right = alloc_layout_range_from(outer, &r);
2005 /* new range in the middle */
2006 cur = alloc_layout_range_from(outer, &value->range);
2007 if (!right || !cur) {
2008 free_layout_range(right);
2009 free_layout_range(cur);
2010 return E_OUTOFMEMORY;
2013 /* reuse container range as a left part */
2014 outer->range.length = value->range.startPosition - outer->range.startPosition;
2016 /* new part */
2017 set_layout_range_attrval(cur, attr, value);
2019 list_add_after(&outer->entry, &cur->entry);
2020 list_add_after(&cur->entry, &right->entry);
2022 return S_OK;
2025 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2026 Update all of them. */
2027 left = get_layout_range_header_by_pos(ranges, value->range.startPosition);
2028 if (left->range.startPosition == value->range.startPosition)
2029 changed = set_layout_range_attrval(left, attr, value);
2030 else /* need to split */ {
2031 r.startPosition = value->range.startPosition;
2032 r.length = left->range.length - value->range.startPosition + left->range.startPosition;
2033 left->range.length -= r.length;
2034 cur = alloc_layout_range_from(left, &r);
2035 changed = set_layout_range_attrval(cur, attr, value);
2036 list_add_after(&left->entry, &cur->entry);
2038 cur = LIST_ENTRY(list_next(ranges, &left->entry), struct layout_range_header, entry);
2040 /* for all existing ranges covered by new one update value */
2041 while (cur && is_in_layout_range(&value->range, &cur->range)) {
2042 changed = set_layout_range_attrval(cur, attr, value);
2043 cur = LIST_ENTRY(list_next(ranges, &cur->entry), struct layout_range_header, entry);
2046 /* it's possible rightmost range intersects */
2047 if (cur && (cur->range.startPosition < value->range.startPosition + value->range.length)) {
2048 r.startPosition = cur->range.startPosition;
2049 r.length = value->range.startPosition + value->range.length - cur->range.startPosition;
2050 left = alloc_layout_range_from(cur, &r);
2051 changed = set_layout_range_attrval(left, attr, value);
2052 cur->range.startPosition += left->range.length;
2053 cur->range.length -= left->range.length;
2054 list_add_before(&cur->entry, &left->entry);
2057 done:
2058 if (changed) {
2059 struct list *next, *i;
2061 layout->recompute = RECOMPUTE_EVERYTHING;
2062 i = list_head(ranges);
2063 while ((next = list_next(ranges, i))) {
2064 struct layout_range_header *next_range = LIST_ENTRY(next, struct layout_range_header, entry);
2066 cur = LIST_ENTRY(i, struct layout_range_header, entry);
2067 if (is_same_layout_attributes(cur, next_range)) {
2068 /* remove similar range */
2069 cur->range.length += next_range->range.length;
2070 list_remove(next);
2071 free_layout_range(next_range);
2073 else
2074 i = list_next(ranges, i);
2078 return S_OK;
2081 static inline const WCHAR *get_string_attribute_ptr(struct layout_range *range, enum layout_range_attr_kind kind)
2083 const WCHAR *str;
2085 switch (kind) {
2086 case LAYOUT_RANGE_ATTR_LOCALE:
2087 str = range->locale;
2088 break;
2089 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2090 str = range->fontfamily;
2091 break;
2092 default:
2093 str = NULL;
2096 return str;
2099 static HRESULT get_string_attribute_length(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2100 UINT32 *length, DWRITE_TEXT_RANGE *r)
2102 struct layout_range *range;
2103 const WCHAR *str;
2105 range = get_layout_range_by_pos(layout, position);
2106 if (!range) {
2107 *length = 0;
2108 return S_OK;
2111 str = get_string_attribute_ptr(range, kind);
2112 *length = strlenW(str);
2113 return return_range(&range->h, r);
2116 static HRESULT get_string_attribute_value(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2117 WCHAR *ret, UINT32 length, DWRITE_TEXT_RANGE *r)
2119 struct layout_range *range;
2120 const WCHAR *str;
2122 if (length == 0)
2123 return E_INVALIDARG;
2125 ret[0] = 0;
2126 range = get_layout_range_by_pos(layout, position);
2127 if (!range)
2128 return E_INVALIDARG;
2130 str = get_string_attribute_ptr(range, kind);
2131 if (length < strlenW(str) + 1)
2132 return E_NOT_SUFFICIENT_BUFFER;
2134 strcpyW(ret, str);
2135 return return_range(&range->h, r);
2138 static HRESULT WINAPI dwritetextlayout_QueryInterface(IDWriteTextLayout2 *iface, REFIID riid, void **obj)
2140 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2142 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2144 *obj = NULL;
2146 if (IsEqualIID(riid, &IID_IDWriteTextLayout2) ||
2147 IsEqualIID(riid, &IID_IDWriteTextLayout1) ||
2148 IsEqualIID(riid, &IID_IDWriteTextLayout) ||
2149 IsEqualIID(riid, &IID_IUnknown))
2151 *obj = iface;
2153 else if (IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
2154 IsEqualIID(riid, &IID_IDWriteTextFormat))
2155 *obj = &This->IDWriteTextFormat1_iface;
2157 if (*obj) {
2158 IDWriteTextLayout2_AddRef(iface);
2159 return S_OK;
2162 return E_NOINTERFACE;
2165 static ULONG WINAPI dwritetextlayout_AddRef(IDWriteTextLayout2 *iface)
2167 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2168 ULONG ref = InterlockedIncrement(&This->ref);
2169 TRACE("(%p)->(%d)\n", This, ref);
2170 return ref;
2173 static ULONG WINAPI dwritetextlayout_Release(IDWriteTextLayout2 *iface)
2175 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2176 ULONG ref = InterlockedDecrement(&This->ref);
2178 TRACE("(%p)->(%d)\n", This, ref);
2180 if (!ref) {
2181 free_layout_ranges_list(This);
2182 free_layout_eruns(This);
2183 free_layout_runs(This);
2184 release_format_data(&This->format);
2185 heap_free(This->nominal_breakpoints);
2186 heap_free(This->actual_breakpoints);
2187 heap_free(This->clustermetrics);
2188 heap_free(This->clusters);
2189 heap_free(This->lines);
2190 heap_free(This->str);
2191 heap_free(This);
2194 return ref;
2197 static HRESULT WINAPI dwritetextlayout_SetTextAlignment(IDWriteTextLayout2 *iface, DWRITE_TEXT_ALIGNMENT alignment)
2199 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2200 return IDWriteTextFormat1_SetTextAlignment(&This->IDWriteTextFormat1_iface, alignment);
2203 static HRESULT WINAPI dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout2 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
2205 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2206 return IDWriteTextFormat1_SetParagraphAlignment(&This->IDWriteTextFormat1_iface, alignment);
2209 static HRESULT WINAPI dwritetextlayout_SetWordWrapping(IDWriteTextLayout2 *iface, DWRITE_WORD_WRAPPING wrapping)
2211 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2212 return IDWriteTextFormat1_SetWordWrapping(&This->IDWriteTextFormat1_iface, wrapping);
2215 static HRESULT WINAPI dwritetextlayout_SetReadingDirection(IDWriteTextLayout2 *iface, DWRITE_READING_DIRECTION direction)
2217 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2218 return IDWriteTextFormat1_SetReadingDirection(&This->IDWriteTextFormat1_iface, direction);
2221 static HRESULT WINAPI dwritetextlayout_SetFlowDirection(IDWriteTextLayout2 *iface, DWRITE_FLOW_DIRECTION direction)
2223 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2224 TRACE("(%p)->(%d)\n", This, direction);
2225 return IDWriteTextFormat1_SetFlowDirection(&This->IDWriteTextFormat1_iface, direction);
2228 static HRESULT WINAPI dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout2 *iface, FLOAT tabstop)
2230 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2231 TRACE("(%p)->(%.2f)\n", This, tabstop);
2232 return IDWriteTextFormat1_SetIncrementalTabStop(&This->IDWriteTextFormat1_iface, tabstop);
2235 static HRESULT WINAPI dwritetextlayout_SetTrimming(IDWriteTextLayout2 *iface, DWRITE_TRIMMING const *trimming,
2236 IDWriteInlineObject *trimming_sign)
2238 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2239 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
2240 return IDWriteTextFormat1_SetTrimming(&This->IDWriteTextFormat1_iface, trimming, trimming_sign);
2243 static HRESULT WINAPI dwritetextlayout_SetLineSpacing(IDWriteTextLayout2 *iface, DWRITE_LINE_SPACING_METHOD spacing,
2244 FLOAT line_spacing, FLOAT baseline)
2246 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2247 TRACE("(%p)->(%d %.2f %.2f)\n", This, spacing, line_spacing, baseline);
2248 return IDWriteTextFormat1_SetLineSpacing(&This->IDWriteTextFormat1_iface, spacing, line_spacing, baseline);
2251 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextlayout_GetTextAlignment(IDWriteTextLayout2 *iface)
2253 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2254 return IDWriteTextFormat1_GetTextAlignment(&This->IDWriteTextFormat1_iface);
2257 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout2 *iface)
2259 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2260 return IDWriteTextFormat1_GetParagraphAlignment(&This->IDWriteTextFormat1_iface);
2263 static DWRITE_WORD_WRAPPING WINAPI dwritetextlayout_GetWordWrapping(IDWriteTextLayout2 *iface)
2265 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2266 return IDWriteTextFormat1_GetWordWrapping(&This->IDWriteTextFormat1_iface);
2269 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_GetReadingDirection(IDWriteTextLayout2 *iface)
2271 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2272 return IDWriteTextFormat1_GetReadingDirection(&This->IDWriteTextFormat1_iface);
2275 static DWRITE_FLOW_DIRECTION WINAPI dwritetextlayout_GetFlowDirection(IDWriteTextLayout2 *iface)
2277 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2278 return IDWriteTextFormat1_GetFlowDirection(&This->IDWriteTextFormat1_iface);
2281 static FLOAT WINAPI dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout2 *iface)
2283 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2284 return IDWriteTextFormat1_GetIncrementalTabStop(&This->IDWriteTextFormat1_iface);
2287 static HRESULT WINAPI dwritetextlayout_GetTrimming(IDWriteTextLayout2 *iface, DWRITE_TRIMMING *options,
2288 IDWriteInlineObject **trimming_sign)
2290 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2291 return IDWriteTextFormat1_GetTrimming(&This->IDWriteTextFormat1_iface, options, trimming_sign);
2294 static HRESULT WINAPI dwritetextlayout_GetLineSpacing(IDWriteTextLayout2 *iface, DWRITE_LINE_SPACING_METHOD *method,
2295 FLOAT *spacing, FLOAT *baseline)
2297 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2298 return IDWriteTextFormat1_GetLineSpacing(&This->IDWriteTextFormat1_iface, method, spacing, baseline);
2301 static HRESULT WINAPI dwritetextlayout_GetFontCollection(IDWriteTextLayout2 *iface, IDWriteFontCollection **collection)
2303 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2304 return IDWriteTextFormat1_GetFontCollection(&This->IDWriteTextFormat1_iface, collection);
2307 static UINT32 WINAPI dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout2 *iface)
2309 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2310 return IDWriteTextFormat1_GetFontFamilyNameLength(&This->IDWriteTextFormat1_iface);
2313 static HRESULT WINAPI dwritetextlayout_GetFontFamilyName(IDWriteTextLayout2 *iface, WCHAR *name, UINT32 size)
2315 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2316 return IDWriteTextFormat1_GetFontFamilyName(&This->IDWriteTextFormat1_iface, name, size);
2319 static DWRITE_FONT_WEIGHT WINAPI dwritetextlayout_GetFontWeight(IDWriteTextLayout2 *iface)
2321 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2322 return IDWriteTextFormat1_GetFontWeight(&This->IDWriteTextFormat1_iface);
2325 static DWRITE_FONT_STYLE WINAPI dwritetextlayout_GetFontStyle(IDWriteTextLayout2 *iface)
2327 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2328 return IDWriteTextFormat1_GetFontStyle(&This->IDWriteTextFormat1_iface);
2331 static DWRITE_FONT_STRETCH WINAPI dwritetextlayout_GetFontStretch(IDWriteTextLayout2 *iface)
2333 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2334 return IDWriteTextFormat1_GetFontStretch(&This->IDWriteTextFormat1_iface);
2337 static FLOAT WINAPI dwritetextlayout_GetFontSize(IDWriteTextLayout2 *iface)
2339 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2340 return IDWriteTextFormat1_GetFontSize(&This->IDWriteTextFormat1_iface);
2343 static UINT32 WINAPI dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout2 *iface)
2345 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2346 return IDWriteTextFormat1_GetLocaleNameLength(&This->IDWriteTextFormat1_iface);
2349 static HRESULT WINAPI dwritetextlayout_GetLocaleName(IDWriteTextLayout2 *iface, WCHAR *name, UINT32 size)
2351 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2352 return IDWriteTextFormat1_GetLocaleName(&This->IDWriteTextFormat1_iface, name, size);
2355 static HRESULT WINAPI dwritetextlayout_SetMaxWidth(IDWriteTextLayout2 *iface, FLOAT maxWidth)
2357 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2359 TRACE("(%p)->(%.2f)\n", This, maxWidth);
2361 if (maxWidth < 0.0)
2362 return E_INVALIDARG;
2364 This->metrics.layoutWidth = maxWidth;
2365 return S_OK;
2368 static HRESULT WINAPI dwritetextlayout_SetMaxHeight(IDWriteTextLayout2 *iface, FLOAT maxHeight)
2370 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2372 TRACE("(%p)->(%.2f)\n", This, maxHeight);
2374 if (maxHeight < 0.0)
2375 return E_INVALIDARG;
2377 This->metrics.layoutHeight = maxHeight;
2378 return S_OK;
2381 static HRESULT WINAPI dwritetextlayout_SetFontCollection(IDWriteTextLayout2 *iface, IDWriteFontCollection* collection, DWRITE_TEXT_RANGE range)
2383 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2384 struct layout_range_attr_value value;
2386 TRACE("(%p)->(%p %s)\n", This, collection, debugstr_range(&range));
2388 value.range = range;
2389 value.u.collection = collection;
2390 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTCOLL, &value);
2393 static HRESULT WINAPI dwritetextlayout_SetFontFamilyName(IDWriteTextLayout2 *iface, WCHAR const *name, DWRITE_TEXT_RANGE range)
2395 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2396 struct layout_range_attr_value value;
2398 TRACE("(%p)->(%s %s)\n", This, debugstr_w(name), debugstr_range(&range));
2400 if (!name)
2401 return E_INVALIDARG;
2403 value.range = range;
2404 value.u.fontfamily = name;
2405 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTFAMILY, &value);
2408 static HRESULT WINAPI dwritetextlayout_SetFontWeight(IDWriteTextLayout2 *iface, DWRITE_FONT_WEIGHT weight, DWRITE_TEXT_RANGE range)
2410 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2411 struct layout_range_attr_value value;
2413 TRACE("(%p)->(%d %s)\n", This, weight, debugstr_range(&range));
2415 value.range = range;
2416 value.u.weight = weight;
2417 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_WEIGHT, &value);
2420 static HRESULT WINAPI dwritetextlayout_SetFontStyle(IDWriteTextLayout2 *iface, DWRITE_FONT_STYLE style, DWRITE_TEXT_RANGE range)
2422 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2423 struct layout_range_attr_value value;
2425 TRACE("(%p)->(%d %s)\n", This, style, debugstr_range(&range));
2427 if ((UINT32)style > DWRITE_FONT_STYLE_ITALIC)
2428 return E_INVALIDARG;
2430 value.range = range;
2431 value.u.style = style;
2432 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STYLE, &value);
2435 static HRESULT WINAPI dwritetextlayout_SetFontStretch(IDWriteTextLayout2 *iface, DWRITE_FONT_STRETCH stretch, DWRITE_TEXT_RANGE range)
2437 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2438 struct layout_range_attr_value value;
2440 TRACE("(%p)->(%d %s)\n", This, stretch, debugstr_range(&range));
2442 if (stretch == DWRITE_FONT_STRETCH_UNDEFINED || (UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
2443 return E_INVALIDARG;
2445 value.range = range;
2446 value.u.stretch = stretch;
2447 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRETCH, &value);
2450 static HRESULT WINAPI dwritetextlayout_SetFontSize(IDWriteTextLayout2 *iface, FLOAT size, DWRITE_TEXT_RANGE range)
2452 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2453 struct layout_range_attr_value value;
2455 TRACE("(%p)->(%.2f %s)\n", This, size, debugstr_range(&range));
2457 if (size <= 0.0)
2458 return E_INVALIDARG;
2460 value.range = range;
2461 value.u.fontsize = size;
2462 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTSIZE, &value);
2465 static HRESULT WINAPI dwritetextlayout_SetUnderline(IDWriteTextLayout2 *iface, BOOL underline, DWRITE_TEXT_RANGE range)
2467 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2468 struct layout_range_attr_value value;
2470 TRACE("(%p)->(%d %s)\n", This, underline, debugstr_range(&range));
2472 value.range = range;
2473 value.u.underline = underline;
2474 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_UNDERLINE, &value);
2477 static HRESULT WINAPI dwritetextlayout_SetStrikethrough(IDWriteTextLayout2 *iface, BOOL strikethrough, DWRITE_TEXT_RANGE range)
2479 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2480 struct layout_range_attr_value value;
2482 TRACE("(%p)->(%d %s)\n", This, strikethrough, debugstr_range(&range));
2484 value.range = range;
2485 value.u.strikethrough = strikethrough;
2486 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRIKETHROUGH, &value);
2489 static HRESULT WINAPI dwritetextlayout_SetDrawingEffect(IDWriteTextLayout2 *iface, IUnknown* effect, DWRITE_TEXT_RANGE range)
2491 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2492 struct layout_range_attr_value value;
2494 TRACE("(%p)->(%p %s)\n", This, effect, debugstr_range(&range));
2496 value.range = range;
2497 value.u.effect = effect;
2498 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_EFFECT, &value);
2501 static HRESULT WINAPI dwritetextlayout_SetInlineObject(IDWriteTextLayout2 *iface, IDWriteInlineObject *object, DWRITE_TEXT_RANGE range)
2503 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2504 struct layout_range_attr_value value;
2506 TRACE("(%p)->(%p %s)\n", This, object, debugstr_range(&range));
2508 value.range = range;
2509 value.u.object = object;
2510 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_INLINE, &value);
2513 static HRESULT WINAPI dwritetextlayout_SetTypography(IDWriteTextLayout2 *iface, IDWriteTypography* typography, DWRITE_TEXT_RANGE range)
2515 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2516 FIXME("(%p)->(%p %s): stub\n", This, typography, debugstr_range(&range));
2517 return E_NOTIMPL;
2520 static HRESULT WINAPI dwritetextlayout_SetLocaleName(IDWriteTextLayout2 *iface, WCHAR const* locale, DWRITE_TEXT_RANGE range)
2522 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2523 struct layout_range_attr_value value;
2525 TRACE("(%p)->(%s %s)\n", This, debugstr_w(locale), debugstr_range(&range));
2527 if (!locale || strlenW(locale) > LOCALE_NAME_MAX_LENGTH-1)
2528 return E_INVALIDARG;
2530 value.range = range;
2531 value.u.locale = locale;
2532 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_LOCALE, &value);
2535 static FLOAT WINAPI dwritetextlayout_GetMaxWidth(IDWriteTextLayout2 *iface)
2537 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2538 TRACE("(%p)\n", This);
2539 return This->metrics.layoutWidth;
2542 static FLOAT WINAPI dwritetextlayout_GetMaxHeight(IDWriteTextLayout2 *iface)
2544 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2545 TRACE("(%p)\n", This);
2546 return This->metrics.layoutHeight;
2549 static HRESULT WINAPI dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout2 *iface, UINT32 position,
2550 IDWriteFontCollection** collection, DWRITE_TEXT_RANGE *r)
2552 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2553 struct layout_range *range;
2555 TRACE("(%p)->(%u %p %p)\n", This, position, collection, r);
2557 if (position >= This->len)
2558 return S_OK;
2560 range = get_layout_range_by_pos(This, position);
2561 *collection = range->collection;
2562 if (*collection)
2563 IDWriteFontCollection_AddRef(*collection);
2565 return return_range(&range->h, r);
2568 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout2 *iface,
2569 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
2571 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2572 TRACE("(%p)->(%d %p %p)\n", This, position, length, r);
2573 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, length, r);
2576 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout2 *iface,
2577 UINT32 position, WCHAR *name, UINT32 length, DWRITE_TEXT_RANGE *r)
2579 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2580 TRACE("(%p)->(%u %p %u %p)\n", This, position, name, length, r);
2581 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, name, length, r);
2584 static HRESULT WINAPI dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout2 *iface,
2585 UINT32 position, DWRITE_FONT_WEIGHT *weight, DWRITE_TEXT_RANGE *r)
2587 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2588 struct layout_range *range;
2590 TRACE("(%p)->(%u %p %p)\n", This, position, weight, r);
2592 if (position >= This->len)
2593 return S_OK;
2595 range = get_layout_range_by_pos(This, position);
2596 *weight = range->weight;
2598 return return_range(&range->h, r);
2601 static HRESULT WINAPI dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout2 *iface,
2602 UINT32 position, DWRITE_FONT_STYLE *style, DWRITE_TEXT_RANGE *r)
2604 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2605 struct layout_range *range;
2607 TRACE("(%p)->(%u %p %p)\n", This, position, style, r);
2609 range = get_layout_range_by_pos(This, position);
2610 *style = range->style;
2611 return return_range(&range->h, r);
2614 static HRESULT WINAPI dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout2 *iface,
2615 UINT32 position, DWRITE_FONT_STRETCH *stretch, DWRITE_TEXT_RANGE *r)
2617 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2618 struct layout_range *range;
2620 TRACE("(%p)->(%u %p %p)\n", This, position, stretch, r);
2622 range = get_layout_range_by_pos(This, position);
2623 *stretch = range->stretch;
2624 return return_range(&range->h, r);
2627 static HRESULT WINAPI dwritetextlayout_layout_GetFontSize(IDWriteTextLayout2 *iface,
2628 UINT32 position, FLOAT *size, DWRITE_TEXT_RANGE *r)
2630 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2631 struct layout_range *range;
2633 TRACE("(%p)->(%u %p %p)\n", This, position, size, r);
2635 range = get_layout_range_by_pos(This, position);
2636 *size = range->fontsize;
2637 return return_range(&range->h, r);
2640 static HRESULT WINAPI dwritetextlayout_GetUnderline(IDWriteTextLayout2 *iface,
2641 UINT32 position, BOOL *underline, DWRITE_TEXT_RANGE *r)
2643 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2644 struct layout_range *range;
2646 TRACE("(%p)->(%u %p %p)\n", This, position, underline, r);
2648 if (position >= This->len)
2649 return S_OK;
2651 range = get_layout_range_by_pos(This, position);
2652 *underline = range->underline;
2654 return return_range(&range->h, r);
2657 static HRESULT WINAPI dwritetextlayout_GetStrikethrough(IDWriteTextLayout2 *iface,
2658 UINT32 position, BOOL *strikethrough, DWRITE_TEXT_RANGE *r)
2660 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2661 struct layout_range_bool *range;
2663 TRACE("(%p)->(%u %p %p)\n", This, position, strikethrough, r);
2665 range = (struct layout_range_bool*)get_layout_range_header_by_pos(&This->strike_ranges, position);
2666 *strikethrough = range->value;
2668 return return_range(&range->h, r);
2671 static HRESULT WINAPI dwritetextlayout_GetDrawingEffect(IDWriteTextLayout2 *iface,
2672 UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r)
2674 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2675 struct layout_range_effect *range;
2677 TRACE("(%p)->(%u %p %p)\n", This, position, effect, r);
2679 range = (struct layout_range_effect*)get_layout_range_header_by_pos(&This->effects, position);
2680 *effect = range->effect;
2681 if (*effect)
2682 IUnknown_AddRef(*effect);
2684 return return_range(&range->h, r);
2687 static HRESULT WINAPI dwritetextlayout_GetInlineObject(IDWriteTextLayout2 *iface,
2688 UINT32 position, IDWriteInlineObject **object, DWRITE_TEXT_RANGE *r)
2690 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2691 struct layout_range *range;
2693 TRACE("(%p)->(%u %p %p)\n", This, position, object, r);
2695 if (position >= This->len)
2696 return S_OK;
2698 range = get_layout_range_by_pos(This, position);
2699 *object = range->object;
2700 if (*object)
2701 IDWriteInlineObject_AddRef(*object);
2703 return return_range(&range->h, r);
2706 static HRESULT WINAPI dwritetextlayout_GetTypography(IDWriteTextLayout2 *iface,
2707 UINT32 position, IDWriteTypography** typography, DWRITE_TEXT_RANGE *range)
2709 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2710 FIXME("(%p)->(%u %p %p): stub\n", This, position, typography, range);
2711 return E_NOTIMPL;
2714 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout2 *iface,
2715 UINT32 position, UINT32* length, DWRITE_TEXT_RANGE *r)
2717 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2718 TRACE("(%p)->(%u %p %p)\n", This, position, length, r);
2719 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_LOCALE, position, length, r);
2722 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout2 *iface,
2723 UINT32 position, WCHAR* locale, UINT32 length, DWRITE_TEXT_RANGE *r)
2725 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2726 TRACE("(%p)->(%u %p %u %p)\n", This, position, locale, length, r);
2727 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_LOCALE, position, locale, length, r);
2730 static inline FLOAT renderer_apply_snapping(FLOAT coord, BOOL skiptransform, FLOAT ppdip, FLOAT det,
2731 const DWRITE_MATRIX *m)
2733 FLOAT vec[2], vec2[2];
2735 if (!skiptransform) {
2736 /* apply transform */
2737 vec[0] = 0.0;
2738 vec[1] = coord;
2740 vec2[0] = m->m11 * vec[0] + m->m12 * vec[1] + m->dx;
2741 vec2[1] = m->m21 * vec[0] + m->m22 * vec[1] + m->dy;
2743 /* snap */
2744 vec2[0] = floorf(vec2[0] * ppdip + 0.5f) / ppdip;
2745 vec2[1] = floorf(vec2[1] * ppdip + 0.5f) / ppdip;
2747 /* apply inverted transform, we don't care about X component at this point */
2748 vec[1] = (-m->m21 * vec2[0] + m->m11 * vec2[1] - (m->m11 * m->dy - m->m12 * m->dx)) / det;
2750 else
2751 vec[1] = floorf(coord * ppdip + 0.5f) / ppdip;
2753 return vec[1];
2756 static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface,
2757 void *context, IDWriteTextRenderer* renderer, FLOAT origin_x, FLOAT origin_y)
2759 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2760 BOOL disabled = FALSE, skiptransform = FALSE;
2761 struct layout_effective_inline *inlineobject;
2762 struct layout_effective_run *run;
2763 struct layout_strikethrough *s;
2764 FLOAT det = 0.0, ppdip = 0.0;
2765 DWRITE_MATRIX m = { 0 };
2766 HRESULT hr;
2768 TRACE("(%p)->(%p %p %.2f %.2f)\n", This, context, renderer, origin_x, origin_y);
2770 hr = layout_compute_effective_runs(This);
2771 if (FAILED(hr))
2772 return hr;
2774 hr = IDWriteTextRenderer_IsPixelSnappingDisabled(renderer, context, &disabled);
2775 if (FAILED(hr))
2776 return hr;
2778 if (!disabled) {
2779 hr = IDWriteTextRenderer_GetPixelsPerDip(renderer, context, &ppdip);
2780 if (FAILED(hr))
2781 return hr;
2783 hr = IDWriteTextRenderer_GetCurrentTransform(renderer, context, &m);
2784 if (FAILED(hr))
2785 return hr;
2787 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
2788 if (ppdip <= 0.0 ||
2789 (m.m11 * m.m22 != 0.0 && (m.m12 != 0.0 || m.m21 != 0.0)) ||
2790 (m.m12 * m.m21 != 0.0 && (m.m11 != 0.0 || m.m22 != 0.0)))
2791 disabled = TRUE;
2792 else {
2793 det = m.m11 * m.m22 - m.m12 * m.m21;
2795 /* on certain conditions we can skip transform */
2796 if (!memcmp(&m, &identity, sizeof(m)) || fabsf(det) <= 1e-10f)
2797 skiptransform = TRUE;
2801 #define SNAP_COORD(x) renderer_apply_snapping((x), skiptransform, ppdip, det, &m)
2802 /* 1. Regular runs */
2803 LIST_FOR_EACH_ENTRY(run, &This->eruns, struct layout_effective_run, entry) {
2804 const struct regular_layout_run *regular = &run->run->u.regular;
2805 UINT32 start_glyph = regular->clustermap[run->start];
2806 DWRITE_GLYPH_RUN_DESCRIPTION descr;
2807 DWRITE_GLYPH_RUN glyph_run;
2809 /* Everything but cluster map will be reused from nominal run, as we only need
2810 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
2811 it can't be reused because it has to start with 0 index for each reported run. */
2812 glyph_run = regular->run;
2813 glyph_run.glyphCount = run->glyphcount;
2815 /* fixup glyph data arrays */
2816 glyph_run.glyphIndices += start_glyph;
2817 glyph_run.glyphAdvances += start_glyph;
2818 glyph_run.glyphOffsets += start_glyph;
2820 /* description */
2821 descr = regular->descr;
2822 descr.stringLength = run->length;
2823 descr.string += run->start;
2824 descr.clusterMap = run->clustermap;
2825 descr.textPosition += run->start;
2827 /* return value is ignored */
2828 IDWriteTextRenderer_DrawGlyphRun(renderer,
2829 context,
2830 run->origin_x + run->align_dx + origin_x,
2831 disabled ? run->origin_y + origin_y : SNAP_COORD(run->origin_y + origin_y),
2832 DWRITE_MEASURING_MODE_NATURAL,
2833 &glyph_run,
2834 &descr,
2835 NULL);
2838 /* 2. Inline objects */
2839 LIST_FOR_EACH_ENTRY(inlineobject, &This->inlineobjects, struct layout_effective_inline, entry) {
2840 IDWriteTextRenderer_DrawInlineObject(renderer,
2841 context,
2842 inlineobject->origin_x + inlineobject->align_dx + origin_x,
2843 disabled ? inlineobject->origin_y + origin_y : SNAP_COORD(inlineobject->origin_y + origin_y),
2844 inlineobject->object,
2845 inlineobject->is_sideways,
2846 inlineobject->is_rtl,
2847 inlineobject->effect);
2850 /* TODO: 3. Underlines */
2852 /* 4. Strikethrough */
2853 LIST_FOR_EACH_ENTRY(s, &This->strikethrough, struct layout_strikethrough, entry) {
2854 IDWriteTextRenderer_DrawStrikethrough(renderer,
2855 context,
2856 s->run->origin_x,
2857 disabled ? s->run->origin_y : SNAP_COORD(s->run->origin_y),
2858 &s->s,
2859 NULL);
2861 #undef SNAP_COORD
2863 return S_OK;
2866 static HRESULT WINAPI dwritetextlayout_GetLineMetrics(IDWriteTextLayout2 *iface,
2867 DWRITE_LINE_METRICS *metrics, UINT32 max_count, UINT32 *count)
2869 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2870 HRESULT hr;
2872 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
2874 hr = layout_compute_effective_runs(This);
2875 if (FAILED(hr))
2876 return hr;
2878 if (metrics)
2879 memcpy(metrics, This->lines, sizeof(*metrics)*min(max_count, This->metrics.lineCount));
2881 *count = This->metrics.lineCount;
2882 return max_count >= This->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
2885 static HRESULT WINAPI dwritetextlayout_GetMetrics(IDWriteTextLayout2 *iface, DWRITE_TEXT_METRICS *metrics)
2887 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2888 DWRITE_TEXT_METRICS1 metrics1;
2889 HRESULT hr;
2891 TRACE("(%p)->(%p)\n", This, metrics);
2893 hr = IDWriteTextLayout2_GetMetrics(iface, &metrics1);
2894 if (hr == S_OK)
2895 memcpy(metrics, &metrics1, sizeof(*metrics));
2897 return hr;
2900 static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout2 *iface, DWRITE_OVERHANG_METRICS *overhangs)
2902 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2903 FIXME("(%p)->(%p): stub\n", This, overhangs);
2904 return E_NOTIMPL;
2907 static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout2 *iface,
2908 DWRITE_CLUSTER_METRICS *metrics, UINT32 max_count, UINT32 *count)
2910 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2911 HRESULT hr;
2913 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
2915 hr = layout_compute(This);
2916 if (FAILED(hr))
2917 return hr;
2919 if (metrics)
2920 memcpy(metrics, This->clustermetrics, sizeof(DWRITE_CLUSTER_METRICS)*min(max_count, This->cluster_count));
2922 *count = This->cluster_count;
2923 return max_count >= This->cluster_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
2926 /* Only to be used with DetermineMinWidth() to find the longest cluster sequence that we don't want to try
2927 too hard to break. */
2928 static inline BOOL is_terminal_cluster(struct dwrite_textlayout *layout, UINT32 index)
2930 if (layout->clustermetrics[index].isWhitespace || layout->clustermetrics[index].isNewline ||
2931 (index == layout->cluster_count - 1))
2932 return TRUE;
2933 /* check next one */
2934 return (index < layout->cluster_count - 1) && layout->clustermetrics[index+1].isWhitespace;
2937 static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout2 *iface, FLOAT* min_width)
2939 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2940 FLOAT width;
2941 HRESULT hr;
2942 UINT32 i;
2944 TRACE("(%p)->(%p)\n", This, min_width);
2946 if (!min_width)
2947 return E_INVALIDARG;
2949 if (!(This->recompute & RECOMPUTE_MINIMAL_WIDTH))
2950 goto width_done;
2952 *min_width = 0.0;
2953 hr = layout_compute(This);
2954 if (FAILED(hr))
2955 return hr;
2957 for (i = 0; i < This->cluster_count;) {
2958 if (is_terminal_cluster(This, i)) {
2959 width = This->clustermetrics[i].width;
2960 i++;
2962 else {
2963 width = 0.0;
2964 while (!is_terminal_cluster(This, i)) {
2965 width += This->clustermetrics[i].width;
2966 i++;
2968 /* count last one too */
2969 width += This->clustermetrics[i].width;
2972 if (width > This->minwidth)
2973 This->minwidth = width;
2975 This->recompute &= ~RECOMPUTE_MINIMAL_WIDTH;
2977 width_done:
2978 *min_width = This->minwidth;
2979 return S_OK;
2982 static HRESULT WINAPI dwritetextlayout_HitTestPoint(IDWriteTextLayout2 *iface,
2983 FLOAT pointX, FLOAT pointY, BOOL* is_trailinghit, BOOL* is_inside, DWRITE_HIT_TEST_METRICS *metrics)
2985 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2986 FIXME("(%p)->(%f %f %p %p %p): stub\n", This, pointX, pointY, is_trailinghit, is_inside, metrics);
2987 return E_NOTIMPL;
2990 static HRESULT WINAPI dwritetextlayout_HitTestTextPosition(IDWriteTextLayout2 *iface,
2991 UINT32 textPosition, BOOL is_trailinghit, FLOAT* pointX, FLOAT* pointY, DWRITE_HIT_TEST_METRICS *metrics)
2993 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2994 FIXME("(%p)->(%u %d %p %p %p): stub\n", This, textPosition, is_trailinghit, pointX, pointY, metrics);
2995 return E_NOTIMPL;
2998 static HRESULT WINAPI dwritetextlayout_HitTestTextRange(IDWriteTextLayout2 *iface,
2999 UINT32 textPosition, UINT32 textLength, FLOAT originX, FLOAT originY,
3000 DWRITE_HIT_TEST_METRICS *metrics, UINT32 max_metricscount, UINT32* actual_metricscount)
3002 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3003 FIXME("(%p)->(%u %u %f %f %p %u %p): stub\n", This, textPosition, textLength, originX, originY, metrics,
3004 max_metricscount, actual_metricscount);
3005 return E_NOTIMPL;
3008 static HRESULT WINAPI dwritetextlayout1_SetPairKerning(IDWriteTextLayout2 *iface, BOOL is_pairkerning_enabled,
3009 DWRITE_TEXT_RANGE range)
3011 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3012 struct layout_range_attr_value value;
3014 TRACE("(%p)->(%d %s)\n", This, is_pairkerning_enabled, debugstr_range(&range));
3016 value.range = range;
3017 value.u.pair_kerning = !!is_pairkerning_enabled;
3018 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_PAIR_KERNING, &value);
3021 static HRESULT WINAPI dwritetextlayout1_GetPairKerning(IDWriteTextLayout2 *iface, UINT32 position, BOOL *is_pairkerning_enabled,
3022 DWRITE_TEXT_RANGE *r)
3024 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3025 struct layout_range *range;
3027 TRACE("(%p)->(%u %p %p)\n", This, position, is_pairkerning_enabled, r);
3029 if (position >= This->len)
3030 return S_OK;
3032 range = get_layout_range_by_pos(This, position);
3033 *is_pairkerning_enabled = range->pair_kerning;
3035 return return_range(&range->h, r);
3038 static HRESULT WINAPI dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout2 *iface, FLOAT leading, FLOAT trailing,
3039 FLOAT min_advance, DWRITE_TEXT_RANGE range)
3041 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3042 struct layout_range_attr_value value;
3044 TRACE("(%p)->(%.2f %.2f %.2f %s)\n", This, leading, trailing, min_advance, debugstr_range(&range));
3046 if (min_advance < 0.0)
3047 return E_INVALIDARG;
3049 value.range = range;
3050 value.u.spacing[0] = leading;
3051 value.u.spacing[1] = trailing;
3052 value.u.spacing[2] = min_advance;
3053 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_SPACING, &value);
3056 static HRESULT WINAPI dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout2 *iface, UINT32 position, FLOAT *leading,
3057 FLOAT *trailing, FLOAT *min_advance, DWRITE_TEXT_RANGE *r)
3059 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3060 struct layout_range_spacing *range;
3062 TRACE("(%p)->(%u %p %p %p %p)\n", This, position, leading, trailing, min_advance, r);
3064 range = (struct layout_range_spacing*)get_layout_range_header_by_pos(&This->spacing, position);
3065 *leading = range->leading;
3066 *trailing = range->trailing;
3067 *min_advance = range->min_advance;
3069 return return_range(&range->h, r);
3072 static HRESULT WINAPI dwritetextlayout2_GetMetrics(IDWriteTextLayout2 *iface, DWRITE_TEXT_METRICS1 *metrics)
3074 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3075 HRESULT hr;
3077 TRACE("(%p)->(%p)\n", This, metrics);
3079 hr = layout_compute_effective_runs(This);
3080 if (FAILED(hr))
3081 return hr;
3083 *metrics = This->metrics;
3084 return S_OK;
3087 static HRESULT WINAPI dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout2 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
3089 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3091 TRACE("(%p)->(%d)\n", This, orientation);
3093 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
3094 return E_INVALIDARG;
3096 This->format.vertical_orientation = orientation;
3097 return S_OK;
3100 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout2 *iface)
3102 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3103 TRACE("(%p)\n", This);
3104 return This->format.vertical_orientation;
3107 static HRESULT WINAPI dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout2 *iface, BOOL lastline_wrapping_enabled)
3109 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3110 FIXME("(%p)->(%d): stub\n", This, lastline_wrapping_enabled);
3111 return E_NOTIMPL;
3114 static BOOL WINAPI dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout2 *iface)
3116 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3117 FIXME("(%p): stub\n", This);
3118 return FALSE;
3121 static HRESULT WINAPI dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout2 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
3123 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3124 FIXME("(%p)->(%d): stub\n", This, alignment);
3125 return E_NOTIMPL;
3128 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout2 *iface)
3130 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3131 FIXME("(%p): stub\n", This);
3132 return DWRITE_OPTICAL_ALIGNMENT_NONE;
3135 static HRESULT WINAPI dwritetextlayout2_SetFontFallback(IDWriteTextLayout2 *iface, IDWriteFontFallback *fallback)
3137 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3138 TRACE("(%p)->(%p)\n", This, fallback);
3139 return set_fontfallback_for_format(&This->format, fallback);
3142 static HRESULT WINAPI dwritetextlayout2_GetFontFallback(IDWriteTextLayout2 *iface, IDWriteFontFallback **fallback)
3144 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3145 TRACE("(%p)->(%p)\n", This, fallback);
3146 return get_fontfallback_from_format(&This->format, fallback);
3149 static const IDWriteTextLayout2Vtbl dwritetextlayoutvtbl = {
3150 dwritetextlayout_QueryInterface,
3151 dwritetextlayout_AddRef,
3152 dwritetextlayout_Release,
3153 dwritetextlayout_SetTextAlignment,
3154 dwritetextlayout_SetParagraphAlignment,
3155 dwritetextlayout_SetWordWrapping,
3156 dwritetextlayout_SetReadingDirection,
3157 dwritetextlayout_SetFlowDirection,
3158 dwritetextlayout_SetIncrementalTabStop,
3159 dwritetextlayout_SetTrimming,
3160 dwritetextlayout_SetLineSpacing,
3161 dwritetextlayout_GetTextAlignment,
3162 dwritetextlayout_GetParagraphAlignment,
3163 dwritetextlayout_GetWordWrapping,
3164 dwritetextlayout_GetReadingDirection,
3165 dwritetextlayout_GetFlowDirection,
3166 dwritetextlayout_GetIncrementalTabStop,
3167 dwritetextlayout_GetTrimming,
3168 dwritetextlayout_GetLineSpacing,
3169 dwritetextlayout_GetFontCollection,
3170 dwritetextlayout_GetFontFamilyNameLength,
3171 dwritetextlayout_GetFontFamilyName,
3172 dwritetextlayout_GetFontWeight,
3173 dwritetextlayout_GetFontStyle,
3174 dwritetextlayout_GetFontStretch,
3175 dwritetextlayout_GetFontSize,
3176 dwritetextlayout_GetLocaleNameLength,
3177 dwritetextlayout_GetLocaleName,
3178 dwritetextlayout_SetMaxWidth,
3179 dwritetextlayout_SetMaxHeight,
3180 dwritetextlayout_SetFontCollection,
3181 dwritetextlayout_SetFontFamilyName,
3182 dwritetextlayout_SetFontWeight,
3183 dwritetextlayout_SetFontStyle,
3184 dwritetextlayout_SetFontStretch,
3185 dwritetextlayout_SetFontSize,
3186 dwritetextlayout_SetUnderline,
3187 dwritetextlayout_SetStrikethrough,
3188 dwritetextlayout_SetDrawingEffect,
3189 dwritetextlayout_SetInlineObject,
3190 dwritetextlayout_SetTypography,
3191 dwritetextlayout_SetLocaleName,
3192 dwritetextlayout_GetMaxWidth,
3193 dwritetextlayout_GetMaxHeight,
3194 dwritetextlayout_layout_GetFontCollection,
3195 dwritetextlayout_layout_GetFontFamilyNameLength,
3196 dwritetextlayout_layout_GetFontFamilyName,
3197 dwritetextlayout_layout_GetFontWeight,
3198 dwritetextlayout_layout_GetFontStyle,
3199 dwritetextlayout_layout_GetFontStretch,
3200 dwritetextlayout_layout_GetFontSize,
3201 dwritetextlayout_GetUnderline,
3202 dwritetextlayout_GetStrikethrough,
3203 dwritetextlayout_GetDrawingEffect,
3204 dwritetextlayout_GetInlineObject,
3205 dwritetextlayout_GetTypography,
3206 dwritetextlayout_layout_GetLocaleNameLength,
3207 dwritetextlayout_layout_GetLocaleName,
3208 dwritetextlayout_Draw,
3209 dwritetextlayout_GetLineMetrics,
3210 dwritetextlayout_GetMetrics,
3211 dwritetextlayout_GetOverhangMetrics,
3212 dwritetextlayout_GetClusterMetrics,
3213 dwritetextlayout_DetermineMinWidth,
3214 dwritetextlayout_HitTestPoint,
3215 dwritetextlayout_HitTestTextPosition,
3216 dwritetextlayout_HitTestTextRange,
3217 dwritetextlayout1_SetPairKerning,
3218 dwritetextlayout1_GetPairKerning,
3219 dwritetextlayout1_SetCharacterSpacing,
3220 dwritetextlayout1_GetCharacterSpacing,
3221 dwritetextlayout2_GetMetrics,
3222 dwritetextlayout2_SetVerticalGlyphOrientation,
3223 dwritetextlayout2_GetVerticalGlyphOrientation,
3224 dwritetextlayout2_SetLastLineWrapping,
3225 dwritetextlayout2_GetLastLineWrapping,
3226 dwritetextlayout2_SetOpticalAlignment,
3227 dwritetextlayout2_GetOpticalAlignment,
3228 dwritetextlayout2_SetFontFallback,
3229 dwritetextlayout2_GetFontFallback
3232 static HRESULT WINAPI dwritetextformat1_layout_QueryInterface(IDWriteTextFormat1 *iface, REFIID riid, void **obj)
3234 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3235 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3236 return IDWriteTextLayout2_QueryInterface(&This->IDWriteTextLayout2_iface, riid, obj);
3239 static ULONG WINAPI dwritetextformat1_layout_AddRef(IDWriteTextFormat1 *iface)
3241 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3242 return IDWriteTextLayout2_AddRef(&This->IDWriteTextLayout2_iface);
3245 static ULONG WINAPI dwritetextformat1_layout_Release(IDWriteTextFormat1 *iface)
3247 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3248 return IDWriteTextLayout2_Release(&This->IDWriteTextLayout2_iface);
3251 static HRESULT WINAPI dwritetextformat1_layout_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
3253 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3254 BOOL changed;
3255 HRESULT hr;
3257 TRACE("(%p)->(%d)\n", This, alignment);
3259 hr = format_set_textalignment(&This->format, alignment, &changed);
3260 if (FAILED(hr))
3261 return hr;
3263 /* if layout is not ready there's nothing to align */
3264 if (changed && !(This->recompute & RECOMPUTE_EFFECTIVE_RUNS))
3265 layout_apply_text_alignment(This);
3267 return S_OK;
3270 static HRESULT WINAPI dwritetextformat1_layout_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
3272 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3273 BOOL changed;
3274 HRESULT hr;
3276 TRACE("(%p)->(%d)\n", This, alignment);
3278 hr = format_set_paralignment(&This->format, alignment, &changed);
3279 if (FAILED(hr))
3280 return hr;
3282 /* if layout is not ready there's nothing to align */
3283 if (changed && !(This->recompute & RECOMPUTE_EFFECTIVE_RUNS))
3284 layout_apply_par_alignment(This);
3286 return S_OK;
3289 static HRESULT WINAPI dwritetextformat1_layout_SetWordWrapping(IDWriteTextFormat1 *iface, DWRITE_WORD_WRAPPING wrapping)
3291 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3292 BOOL changed;
3293 HRESULT hr;
3295 TRACE("(%p)->(%d)\n", This, wrapping);
3297 hr = format_set_wordwrapping(&This->format, wrapping, &changed);
3298 if (FAILED(hr))
3299 return hr;
3301 if (changed)
3302 This->recompute |= RECOMPUTE_EFFECTIVE_RUNS;
3304 return S_OK;
3307 static HRESULT WINAPI dwritetextformat1_layout_SetReadingDirection(IDWriteTextFormat1 *iface, DWRITE_READING_DIRECTION direction)
3309 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3310 BOOL changed;
3311 HRESULT hr;
3313 TRACE("(%p)->(%d)\n", This, direction);
3315 hr = format_set_readingdirection(&This->format, direction, &changed);
3316 if (FAILED(hr))
3317 return hr;
3319 if (changed)
3320 This->recompute = RECOMPUTE_EVERYTHING;
3322 return S_OK;
3325 static HRESULT WINAPI dwritetextformat1_layout_SetFlowDirection(IDWriteTextFormat1 *iface, DWRITE_FLOW_DIRECTION direction)
3327 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3328 FIXME("(%p)->(%d): stub\n", This, direction);
3329 return E_NOTIMPL;
3332 static HRESULT WINAPI dwritetextformat1_layout_SetIncrementalTabStop(IDWriteTextFormat1 *iface, FLOAT tabstop)
3334 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3335 FIXME("(%p)->(%f): stub\n", This, tabstop);
3336 return E_NOTIMPL;
3339 static HRESULT WINAPI dwritetextformat1_layout_SetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING const *trimming,
3340 IDWriteInlineObject *trimming_sign)
3342 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3343 FIXME("(%p)->(%p %p): stub\n", This, trimming, trimming_sign);
3344 return E_NOTIMPL;
3347 static HRESULT WINAPI dwritetextformat1_layout_SetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD spacing,
3348 FLOAT line_spacing, FLOAT baseline)
3350 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3351 FIXME("(%p)->(%d %f %f): stub\n", This, spacing, line_spacing, baseline);
3352 return E_NOTIMPL;
3355 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat1_layout_GetTextAlignment(IDWriteTextFormat1 *iface)
3357 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3358 TRACE("(%p)\n", This);
3359 return This->format.textalignment;
3362 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat1_layout_GetParagraphAlignment(IDWriteTextFormat1 *iface)
3364 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3365 TRACE("(%p)\n", This);
3366 return This->format.paralign;
3369 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat1_layout_GetWordWrapping(IDWriteTextFormat1 *iface)
3371 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3372 TRACE("(%p)\n", This);
3373 return This->format.wrapping;
3376 static DWRITE_READING_DIRECTION WINAPI dwritetextformat1_layout_GetReadingDirection(IDWriteTextFormat1 *iface)
3378 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3379 TRACE("(%p)\n", This);
3380 return This->format.readingdir;
3383 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat1_layout_GetFlowDirection(IDWriteTextFormat1 *iface)
3385 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3386 TRACE("(%p)\n", This);
3387 return This->format.flow;
3390 static FLOAT WINAPI dwritetextformat1_layout_GetIncrementalTabStop(IDWriteTextFormat1 *iface)
3392 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3393 FIXME("(%p): stub\n", This);
3394 return 0.0;
3397 static HRESULT WINAPI dwritetextformat1_layout_GetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING *options,
3398 IDWriteInlineObject **trimming_sign)
3400 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3402 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
3404 *options = This->format.trimming;
3405 *trimming_sign = This->format.trimmingsign;
3406 if (*trimming_sign)
3407 IDWriteInlineObject_AddRef(*trimming_sign);
3408 return S_OK;
3411 static HRESULT WINAPI dwritetextformat1_layout_GetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD *method,
3412 FLOAT *spacing, FLOAT *baseline)
3414 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3416 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
3418 *method = This->format.spacingmethod;
3419 *spacing = This->format.spacing;
3420 *baseline = This->format.baseline;
3421 return S_OK;
3424 static HRESULT WINAPI dwritetextformat1_layout_GetFontCollection(IDWriteTextFormat1 *iface, IDWriteFontCollection **collection)
3426 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3428 TRACE("(%p)->(%p)\n", This, collection);
3430 *collection = This->format.collection;
3431 if (*collection)
3432 IDWriteFontCollection_AddRef(*collection);
3433 return S_OK;
3436 static UINT32 WINAPI dwritetextformat1_layout_GetFontFamilyNameLength(IDWriteTextFormat1 *iface)
3438 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3439 TRACE("(%p)\n", This);
3440 return This->format.family_len;
3443 static HRESULT WINAPI dwritetextformat1_layout_GetFontFamilyName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
3445 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3447 TRACE("(%p)->(%p %u)\n", This, name, size);
3449 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
3450 strcpyW(name, This->format.family_name);
3451 return S_OK;
3454 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat1_layout_GetFontWeight(IDWriteTextFormat1 *iface)
3456 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3457 TRACE("(%p)\n", This);
3458 return This->format.weight;
3461 static DWRITE_FONT_STYLE WINAPI dwritetextformat1_layout_GetFontStyle(IDWriteTextFormat1 *iface)
3463 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3464 TRACE("(%p)\n", This);
3465 return This->format.style;
3468 static DWRITE_FONT_STRETCH WINAPI dwritetextformat1_layout_GetFontStretch(IDWriteTextFormat1 *iface)
3470 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3471 TRACE("(%p)\n", This);
3472 return This->format.stretch;
3475 static FLOAT WINAPI dwritetextformat1_layout_GetFontSize(IDWriteTextFormat1 *iface)
3477 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3478 TRACE("(%p)\n", This);
3479 return This->format.fontsize;
3482 static UINT32 WINAPI dwritetextformat1_layout_GetLocaleNameLength(IDWriteTextFormat1 *iface)
3484 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3485 TRACE("(%p)\n", This);
3486 return This->format.locale_len;
3489 static HRESULT WINAPI dwritetextformat1_layout_GetLocaleName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
3491 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3493 TRACE("(%p)->(%p %u)\n", This, name, size);
3495 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
3496 strcpyW(name, This->format.locale);
3497 return S_OK;
3500 static HRESULT WINAPI dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat1 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
3502 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3503 FIXME("(%p)->(%d): stub\n", This, orientation);
3504 return E_NOTIMPL;
3507 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat1 *iface)
3509 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3510 FIXME("(%p): stub\n", This);
3511 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
3514 static HRESULT WINAPI dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat1 *iface, BOOL lastline_wrapping_enabled)
3516 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3517 FIXME("(%p)->(%d): stub\n", This, lastline_wrapping_enabled);
3518 return E_NOTIMPL;
3521 static BOOL WINAPI dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat1 *iface)
3523 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3524 FIXME("(%p): stub\n", This);
3525 return FALSE;
3528 static HRESULT WINAPI dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat1 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
3530 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3531 FIXME("(%p)->(%d): stub\n", This, alignment);
3532 return E_NOTIMPL;
3535 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat1 *iface)
3537 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3538 FIXME("(%p): stub\n", This);
3539 return DWRITE_OPTICAL_ALIGNMENT_NONE;
3542 static HRESULT WINAPI dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback *fallback)
3544 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3545 TRACE("(%p)->(%p)\n", This, fallback);
3546 return IDWriteTextLayout2_SetFontFallback(&This->IDWriteTextLayout2_iface, fallback);
3549 static HRESULT WINAPI dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback **fallback)
3551 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3552 TRACE("(%p)->(%p)\n", This, fallback);
3553 return IDWriteTextLayout2_GetFontFallback(&This->IDWriteTextLayout2_iface, fallback);
3556 static const IDWriteTextFormat1Vtbl dwritetextformat1_layout_vtbl = {
3557 dwritetextformat1_layout_QueryInterface,
3558 dwritetextformat1_layout_AddRef,
3559 dwritetextformat1_layout_Release,
3560 dwritetextformat1_layout_SetTextAlignment,
3561 dwritetextformat1_layout_SetParagraphAlignment,
3562 dwritetextformat1_layout_SetWordWrapping,
3563 dwritetextformat1_layout_SetReadingDirection,
3564 dwritetextformat1_layout_SetFlowDirection,
3565 dwritetextformat1_layout_SetIncrementalTabStop,
3566 dwritetextformat1_layout_SetTrimming,
3567 dwritetextformat1_layout_SetLineSpacing,
3568 dwritetextformat1_layout_GetTextAlignment,
3569 dwritetextformat1_layout_GetParagraphAlignment,
3570 dwritetextformat1_layout_GetWordWrapping,
3571 dwritetextformat1_layout_GetReadingDirection,
3572 dwritetextformat1_layout_GetFlowDirection,
3573 dwritetextformat1_layout_GetIncrementalTabStop,
3574 dwritetextformat1_layout_GetTrimming,
3575 dwritetextformat1_layout_GetLineSpacing,
3576 dwritetextformat1_layout_GetFontCollection,
3577 dwritetextformat1_layout_GetFontFamilyNameLength,
3578 dwritetextformat1_layout_GetFontFamilyName,
3579 dwritetextformat1_layout_GetFontWeight,
3580 dwritetextformat1_layout_GetFontStyle,
3581 dwritetextformat1_layout_GetFontStretch,
3582 dwritetextformat1_layout_GetFontSize,
3583 dwritetextformat1_layout_GetLocaleNameLength,
3584 dwritetextformat1_layout_GetLocaleName,
3585 dwritetextformat1_layout_SetVerticalGlyphOrientation,
3586 dwritetextformat1_layout_GetVerticalGlyphOrientation,
3587 dwritetextformat1_layout_SetLastLineWrapping,
3588 dwritetextformat1_layout_GetLastLineWrapping,
3589 dwritetextformat1_layout_SetOpticalAlignment,
3590 dwritetextformat1_layout_GetOpticalAlignment,
3591 dwritetextformat1_layout_SetFontFallback,
3592 dwritetextformat1_layout_GetFontFallback
3595 static HRESULT WINAPI dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink *iface,
3596 REFIID riid, void **obj)
3598 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) || IsEqualIID(riid, &IID_IUnknown)) {
3599 *obj = iface;
3600 IDWriteTextAnalysisSink_AddRef(iface);
3601 return S_OK;
3604 *obj = NULL;
3605 return E_NOINTERFACE;
3608 static ULONG WINAPI dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink *iface)
3610 return 2;
3613 static ULONG WINAPI dwritetextlayout_sink_Release(IDWriteTextAnalysisSink *iface)
3615 return 1;
3618 static HRESULT WINAPI dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink *iface,
3619 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
3621 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
3622 struct layout_run *run;
3624 TRACE("%u %u script=%d\n", position, length, sa->script);
3626 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
3627 if (!run)
3628 return E_OUTOFMEMORY;
3630 run->u.regular.descr.string = &layout->str[position];
3631 run->u.regular.descr.stringLength = length;
3632 run->u.regular.descr.textPosition = position;
3633 run->u.regular.sa = *sa;
3634 list_add_tail(&layout->runs, &run->entry);
3635 return S_OK;
3638 static HRESULT WINAPI dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink *iface,
3639 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
3641 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
3643 if (position + length > layout->len)
3644 return E_FAIL;
3646 memcpy(&layout->nominal_breakpoints[position], breakpoints, length*sizeof(DWRITE_LINE_BREAKPOINT));
3647 return S_OK;
3650 static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink *iface, UINT32 position,
3651 UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
3653 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
3654 struct layout_run *cur_run;
3656 TRACE("%u %u %u %u\n", position, length, explicitLevel, resolvedLevel);
3658 LIST_FOR_EACH_ENTRY(cur_run, &layout->runs, struct layout_run, entry) {
3659 struct regular_layout_run *cur = &cur_run->u.regular;
3660 struct layout_run *run;
3662 if (cur_run->kind == LAYOUT_RUN_INLINE)
3663 continue;
3665 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
3666 if (position < cur->descr.textPosition || position >= cur->descr.textPosition + cur->descr.stringLength)
3667 continue;
3669 /* full hit - just set run level */
3670 if (cur->descr.textPosition == position && cur->descr.stringLength == length) {
3671 cur->run.bidiLevel = resolvedLevel;
3672 break;
3675 /* current run is fully covered, move to next one */
3676 if (cur->descr.textPosition == position && cur->descr.stringLength < length) {
3677 cur->run.bidiLevel = resolvedLevel;
3678 position += cur->descr.stringLength;
3679 length -= cur->descr.stringLength;
3680 continue;
3683 /* all fully covered runs are processed at this point, reuse existing run for remaining
3684 reported bidi range and add another run for the rest of original one */
3686 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
3687 if (!run)
3688 return E_OUTOFMEMORY;
3690 *run = *cur_run;
3691 run->u.regular.descr.textPosition = position + length;
3692 run->u.regular.descr.stringLength = cur->descr.stringLength - length;
3693 run->u.regular.descr.string = &layout->str[position + length];
3695 /* reduce existing run */
3696 cur->run.bidiLevel = resolvedLevel;
3697 cur->descr.stringLength = length;
3699 list_add_after(&cur_run->entry, &run->entry);
3700 break;
3703 return S_OK;
3706 static HRESULT WINAPI dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink *iface,
3707 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
3709 return E_NOTIMPL;
3712 static const IDWriteTextAnalysisSinkVtbl dwritetextlayoutsinkvtbl = {
3713 dwritetextlayout_sink_QueryInterface,
3714 dwritetextlayout_sink_AddRef,
3715 dwritetextlayout_sink_Release,
3716 dwritetextlayout_sink_SetScriptAnalysis,
3717 dwritetextlayout_sink_SetLineBreakpoints,
3718 dwritetextlayout_sink_SetBidiLevel,
3719 dwritetextlayout_sink_SetNumberSubstitution
3722 static HRESULT WINAPI dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource *iface,
3723 REFIID riid, void **obj)
3725 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) ||
3726 IsEqualIID(riid, &IID_IUnknown))
3728 *obj = iface;
3729 IDWriteTextAnalysisSource_AddRef(iface);
3730 return S_OK;
3733 *obj = NULL;
3734 return E_NOINTERFACE;
3737 static ULONG WINAPI dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource *iface)
3739 return 2;
3742 static ULONG WINAPI dwritetextlayout_source_Release(IDWriteTextAnalysisSource *iface)
3744 return 1;
3747 static HRESULT WINAPI dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource *iface,
3748 UINT32 position, WCHAR const** text, UINT32* text_len)
3750 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource(iface);
3752 TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
3754 if (position < layout->len) {
3755 *text = &layout->str[position];
3756 *text_len = layout->len - position;
3758 else {
3759 *text = NULL;
3760 *text_len = 0;
3763 return S_OK;
3766 static HRESULT WINAPI dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource *iface,
3767 UINT32 position, WCHAR const** text, UINT32* text_len)
3769 FIXME("%u %p %p: stub\n", position, text, text_len);
3770 return E_NOTIMPL;
3773 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource *iface)
3775 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource(iface);
3776 return IDWriteTextLayout2_GetReadingDirection(&layout->IDWriteTextLayout2_iface);
3779 static HRESULT WINAPI dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource *iface,
3780 UINT32 position, UINT32* text_len, WCHAR const** locale)
3782 FIXME("%u %p %p: stub\n", position, text_len, locale);
3783 return E_NOTIMPL;
3786 static HRESULT WINAPI dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource *iface,
3787 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
3789 FIXME("%u %p %p: stub\n", position, text_len, substitution);
3790 return E_NOTIMPL;
3793 static const IDWriteTextAnalysisSourceVtbl dwritetextlayoutsourcevtbl = {
3794 dwritetextlayout_source_QueryInterface,
3795 dwritetextlayout_source_AddRef,
3796 dwritetextlayout_source_Release,
3797 dwritetextlayout_source_GetTextAtPosition,
3798 dwritetextlayout_source_GetTextBeforePosition,
3799 dwritetextlayout_source_GetParagraphReadingDirection,
3800 dwritetextlayout_source_GetLocaleName,
3801 dwritetextlayout_source_GetNumberSubstitution
3804 static HRESULT layout_format_from_textformat(struct dwrite_textlayout *layout, IDWriteTextFormat *format)
3806 IDWriteTextFormat1 *format1;
3807 UINT32 len;
3808 HRESULT hr;
3810 layout->format.weight = IDWriteTextFormat_GetFontWeight(format);
3811 layout->format.style = IDWriteTextFormat_GetFontStyle(format);
3812 layout->format.stretch = IDWriteTextFormat_GetFontStretch(format);
3813 layout->format.fontsize= IDWriteTextFormat_GetFontSize(format);
3814 layout->format.textalignment = IDWriteTextFormat_GetTextAlignment(format);
3815 layout->format.paralign = IDWriteTextFormat_GetParagraphAlignment(format);
3816 layout->format.wrapping = IDWriteTextFormat_GetWordWrapping(format);
3817 layout->format.readingdir = IDWriteTextFormat_GetReadingDirection(format);
3818 layout->format.flow = IDWriteTextFormat_GetFlowDirection(format);
3819 layout->format.fallback = NULL;
3820 hr = IDWriteTextFormat_GetLineSpacing(format, &layout->format.spacingmethod,
3821 &layout->format.spacing, &layout->format.baseline);
3822 if (FAILED(hr))
3823 return hr;
3825 hr = IDWriteTextFormat_GetTrimming(format, &layout->format.trimming, &layout->format.trimmingsign);
3826 if (FAILED(hr))
3827 return hr;
3829 /* locale name and length */
3830 len = IDWriteTextFormat_GetLocaleNameLength(format);
3831 layout->format.locale = heap_alloc((len+1)*sizeof(WCHAR));
3832 if (!layout->format.locale)
3833 return E_OUTOFMEMORY;
3835 hr = IDWriteTextFormat_GetLocaleName(format, layout->format.locale, len+1);
3836 if (FAILED(hr))
3837 return hr;
3838 layout->format.locale_len = len;
3840 /* font family name and length */
3841 len = IDWriteTextFormat_GetFontFamilyNameLength(format);
3842 layout->format.family_name = heap_alloc((len+1)*sizeof(WCHAR));
3843 if (!layout->format.family_name)
3844 return E_OUTOFMEMORY;
3846 hr = IDWriteTextFormat_GetFontFamilyName(format, layout->format.family_name, len+1);
3847 if (FAILED(hr))
3848 return hr;
3849 layout->format.family_len = len;
3851 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
3852 if (hr == S_OK) {
3853 layout->format.vertical_orientation = IDWriteTextFormat1_GetVerticalGlyphOrientation(format1);
3854 IDWriteTextFormat1_GetFontFallback(format1, &layout->format.fallback);
3855 IDWriteTextFormat1_Release(format1);
3857 else
3858 layout->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
3860 return IDWriteTextFormat_GetFontCollection(format, &layout->format.collection);
3863 static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, struct dwrite_textlayout *layout)
3865 struct layout_range_header *range, *strike, *effect, *spacing;
3866 DWRITE_TEXT_RANGE r = { 0, ~0u };
3867 HRESULT hr;
3869 layout->IDWriteTextLayout2_iface.lpVtbl = &dwritetextlayoutvtbl;
3870 layout->IDWriteTextFormat1_iface.lpVtbl = &dwritetextformat1_layout_vtbl;
3871 layout->IDWriteTextAnalysisSink_iface.lpVtbl = &dwritetextlayoutsinkvtbl;
3872 layout->IDWriteTextAnalysisSource_iface.lpVtbl = &dwritetextlayoutsourcevtbl;
3873 layout->ref = 1;
3874 layout->len = len;
3875 layout->recompute = RECOMPUTE_EVERYTHING;
3876 layout->nominal_breakpoints = NULL;
3877 layout->actual_breakpoints = NULL;
3878 layout->cluster_count = 0;
3879 layout->clustermetrics = NULL;
3880 layout->clusters = NULL;
3881 layout->lines = NULL;
3882 layout->line_alloc = 0;
3883 layout->minwidth = 0.0;
3884 list_init(&layout->eruns);
3885 list_init(&layout->inlineobjects);
3886 list_init(&layout->strikethrough);
3887 list_init(&layout->runs);
3888 list_init(&layout->ranges);
3889 list_init(&layout->strike_ranges);
3890 list_init(&layout->effects);
3891 list_init(&layout->spacing);
3892 memset(&layout->format, 0, sizeof(layout->format));
3893 memset(&layout->metrics, 0, sizeof(layout->metrics));
3894 layout->metrics.layoutWidth = maxwidth;
3895 layout->metrics.layoutHeight = maxheight;
3897 layout->gdicompatible = FALSE;
3898 layout->pixels_per_dip = 0.0;
3899 layout->use_gdi_natural = FALSE;
3900 memset(&layout->transform, 0, sizeof(layout->transform));
3902 layout->str = heap_strdupnW(str, len);
3903 if (len && !layout->str) {
3904 hr = E_OUTOFMEMORY;
3905 goto fail;
3908 hr = layout_format_from_textformat(layout, format);
3909 if (FAILED(hr))
3910 goto fail;
3912 range = alloc_layout_range(layout, &r, LAYOUT_RANGE_REGULAR);
3913 strike = alloc_layout_range(layout, &r, LAYOUT_RANGE_STRIKETHROUGH);
3914 effect = alloc_layout_range(layout, &r, LAYOUT_RANGE_EFFECT);
3915 spacing = alloc_layout_range(layout, &r, LAYOUT_RANGE_SPACING);
3916 if (!range || !strike || !effect || !spacing) {
3917 free_layout_range(range);
3918 free_layout_range(strike);
3919 free_layout_range(effect);
3920 free_layout_range(spacing);
3921 hr = E_OUTOFMEMORY;
3922 goto fail;
3925 list_add_head(&layout->ranges, &range->entry);
3926 list_add_head(&layout->strike_ranges, &strike->entry);
3927 list_add_head(&layout->effects, &effect->entry);
3928 list_add_head(&layout->spacing, &spacing->entry);
3929 return S_OK;
3931 fail:
3932 IDWriteTextLayout2_Release(&layout->IDWriteTextLayout2_iface);
3933 return hr;
3936 HRESULT create_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, IDWriteTextLayout **ret)
3938 struct dwrite_textlayout *layout;
3939 HRESULT hr;
3941 *ret = NULL;
3943 layout = heap_alloc(sizeof(struct dwrite_textlayout));
3944 if (!layout) return E_OUTOFMEMORY;
3946 hr = init_textlayout(str, len, format, maxwidth, maxheight, layout);
3947 if (hr == S_OK)
3948 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout2_iface;
3950 return hr;
3953 HRESULT create_gdicompat_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight,
3954 FLOAT pixels_per_dip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural, IDWriteTextLayout **ret)
3956 struct dwrite_textlayout *layout;
3957 HRESULT hr;
3959 *ret = NULL;
3961 layout = heap_alloc(sizeof(struct dwrite_textlayout));
3962 if (!layout) return E_OUTOFMEMORY;
3964 hr = init_textlayout(str, len, format, maxwidth, maxheight, layout);
3965 if (hr == S_OK) {
3966 /* set gdi-specific properties */
3967 layout->gdicompatible = TRUE;
3968 layout->pixels_per_dip = pixels_per_dip;
3969 layout->use_gdi_natural = use_gdi_natural;
3970 layout->transform = transform ? *transform : identity;
3972 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout2_iface;
3975 return hr;
3978 static HRESULT WINAPI dwritetrimmingsign_QueryInterface(IDWriteInlineObject *iface, REFIID riid, void **obj)
3980 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3982 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3984 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteInlineObject)) {
3985 *obj = iface;
3986 IDWriteInlineObject_AddRef(iface);
3987 return S_OK;
3990 *obj = NULL;
3991 return E_NOINTERFACE;
3994 static ULONG WINAPI dwritetrimmingsign_AddRef(IDWriteInlineObject *iface)
3996 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3997 ULONG ref = InterlockedIncrement(&This->ref);
3998 TRACE("(%p)->(%d)\n", This, ref);
3999 return ref;
4002 static ULONG WINAPI dwritetrimmingsign_Release(IDWriteInlineObject *iface)
4004 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4005 ULONG ref = InterlockedDecrement(&This->ref);
4007 TRACE("(%p)->(%d)\n", This, ref);
4009 if (!ref) {
4010 IDWriteTextLayout_Release(This->layout);
4011 heap_free(This);
4014 return ref;
4017 static HRESULT WINAPI dwritetrimmingsign_Draw(IDWriteInlineObject *iface, void *context, IDWriteTextRenderer *renderer,
4018 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *effect)
4020 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4021 DWRITE_TEXT_RANGE range = { 0, ~0u };
4023 TRACE("(%p)->(%p %p %.2f %.2f %d %d %p)\n", This, context, renderer, originX, originY, is_sideways, is_rtl, effect);
4025 IDWriteTextLayout_SetDrawingEffect(This->layout, effect, range);
4026 return IDWriteTextLayout_Draw(This->layout, context, renderer, originX, originY);
4029 static HRESULT WINAPI dwritetrimmingsign_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *ret)
4031 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4032 DWRITE_TEXT_METRICS metrics;
4033 HRESULT hr;
4035 TRACE("(%p)->(%p)\n", This, ret);
4037 hr = IDWriteTextLayout_GetMetrics(This->layout, &metrics);
4038 if (FAILED(hr)) {
4039 memset(ret, 0, sizeof(*ret));
4040 return hr;
4043 ret->width = metrics.width;
4044 ret->height = 0.0;
4045 ret->baseline = 0.0;
4046 ret->supportsSideways = FALSE;
4047 return S_OK;
4050 static HRESULT WINAPI dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
4052 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4053 FIXME("(%p)->(%p): stub\n", This, overhangs);
4054 return E_NOTIMPL;
4057 static HRESULT WINAPI dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
4058 DWRITE_BREAK_CONDITION *after)
4060 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4062 TRACE("(%p)->(%p %p)\n", This, before, after);
4064 *before = *after = DWRITE_BREAK_CONDITION_NEUTRAL;
4065 return S_OK;
4068 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl = {
4069 dwritetrimmingsign_QueryInterface,
4070 dwritetrimmingsign_AddRef,
4071 dwritetrimmingsign_Release,
4072 dwritetrimmingsign_Draw,
4073 dwritetrimmingsign_GetMetrics,
4074 dwritetrimmingsign_GetOverhangMetrics,
4075 dwritetrimmingsign_GetBreakConditions
4078 static inline BOOL is_reading_direction_horz(DWRITE_READING_DIRECTION direction)
4080 return (direction == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT) ||
4081 (direction == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
4084 static inline BOOL is_reading_direction_vert(DWRITE_READING_DIRECTION direction)
4086 return (direction == DWRITE_READING_DIRECTION_TOP_TO_BOTTOM) ||
4087 (direction == DWRITE_READING_DIRECTION_BOTTOM_TO_TOP);
4090 static inline BOOL is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction)
4092 return (direction == DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT) ||
4093 (direction == DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT);
4096 static inline BOOL is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction)
4098 return (direction == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM) ||
4099 (direction == DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP);
4102 HRESULT create_trimmingsign(IDWriteFactory2 *factory, IDWriteTextFormat *format, IDWriteInlineObject **sign)
4104 static const WCHAR ellipsisW = 0x2026;
4105 struct dwrite_trimmingsign *This;
4106 DWRITE_READING_DIRECTION reading;
4107 DWRITE_FLOW_DIRECTION flow;
4108 HRESULT hr;
4110 *sign = NULL;
4112 /* Validate reading/flow direction here, layout creation won't complain about
4113 invalid combinations. */
4114 reading = IDWriteTextFormat_GetReadingDirection(format);
4115 flow = IDWriteTextFormat_GetFlowDirection(format);
4117 if ((is_reading_direction_horz(reading) && is_flow_direction_horz(flow)) ||
4118 (is_reading_direction_vert(reading) && is_flow_direction_vert(flow)))
4119 return DWRITE_E_FLOWDIRECTIONCONFLICTS;
4121 This = heap_alloc(sizeof(*This));
4122 if (!This)
4123 return E_OUTOFMEMORY;
4125 This->IDWriteInlineObject_iface.lpVtbl = &dwritetrimmingsignvtbl;
4126 This->ref = 1;
4128 hr = IDWriteFactory2_CreateTextLayout(factory, &ellipsisW, 1, format, 0.0, 0.0, &This->layout);
4129 if (FAILED(hr)) {
4130 heap_free(This);
4131 return hr;
4134 IDWriteTextLayout_SetWordWrapping(This->layout, DWRITE_WORD_WRAPPING_NO_WRAP);
4135 *sign = &This->IDWriteInlineObject_iface;
4137 return S_OK;
4140 static HRESULT WINAPI dwritetextformat_QueryInterface(IDWriteTextFormat1 *iface, REFIID riid, void **obj)
4142 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4144 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4146 if (IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
4147 IsEqualIID(riid, &IID_IDWriteTextFormat) ||
4148 IsEqualIID(riid, &IID_IUnknown))
4150 *obj = iface;
4151 IDWriteTextFormat1_AddRef(iface);
4152 return S_OK;
4155 *obj = NULL;
4157 return E_NOINTERFACE;
4160 static ULONG WINAPI dwritetextformat_AddRef(IDWriteTextFormat1 *iface)
4162 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4163 ULONG ref = InterlockedIncrement(&This->ref);
4164 TRACE("(%p)->(%d)\n", This, ref);
4165 return ref;
4168 static ULONG WINAPI dwritetextformat_Release(IDWriteTextFormat1 *iface)
4170 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4171 ULONG ref = InterlockedDecrement(&This->ref);
4173 TRACE("(%p)->(%d)\n", This, ref);
4175 if (!ref)
4177 release_format_data(&This->format);
4178 heap_free(This);
4181 return ref;
4184 static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
4186 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4187 TRACE("(%p)->(%d)\n", This, alignment);
4188 return format_set_textalignment(&This->format, alignment, NULL);
4191 static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
4193 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4194 TRACE("(%p)->(%d)\n", This, alignment);
4195 return format_set_paralignment(&This->format, alignment, NULL);
4198 static HRESULT WINAPI dwritetextformat_SetWordWrapping(IDWriteTextFormat1 *iface, DWRITE_WORD_WRAPPING wrapping)
4200 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4201 TRACE("(%p)->(%d)\n", This, wrapping);
4202 return format_set_wordwrapping(&This->format, wrapping, NULL);
4205 static HRESULT WINAPI dwritetextformat_SetReadingDirection(IDWriteTextFormat1 *iface, DWRITE_READING_DIRECTION direction)
4207 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4208 TRACE("(%p)->(%d)\n", This, direction);
4209 return format_set_readingdirection(&This->format, direction, NULL);
4212 static HRESULT WINAPI dwritetextformat_SetFlowDirection(IDWriteTextFormat1 *iface, DWRITE_FLOW_DIRECTION direction)
4214 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4216 TRACE("(%p)->(%d)\n", This, direction);
4218 if ((UINT32)direction > DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT)
4219 return E_INVALIDARG;
4221 This->format.flow = direction;
4222 return S_OK;
4225 static HRESULT WINAPI dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat1 *iface, FLOAT tabstop)
4227 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4228 FIXME("(%p)->(%f): stub\n", This, tabstop);
4229 return E_NOTIMPL;
4232 static HRESULT WINAPI dwritetextformat_SetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING const *trimming,
4233 IDWriteInlineObject *trimming_sign)
4235 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4236 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
4238 This->format.trimming = *trimming;
4239 if (This->format.trimmingsign)
4240 IDWriteInlineObject_Release(This->format.trimmingsign);
4241 This->format.trimmingsign = trimming_sign;
4242 if (This->format.trimmingsign)
4243 IDWriteInlineObject_AddRef(This->format.trimmingsign);
4244 return S_OK;
4247 static HRESULT WINAPI dwritetextformat_SetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD method,
4248 FLOAT spacing, FLOAT baseline)
4250 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4252 TRACE("(%p)->(%d %f %f)\n", This, method, spacing, baseline);
4254 if (spacing < 0.0 || (UINT32)method > DWRITE_LINE_SPACING_METHOD_UNIFORM)
4255 return E_INVALIDARG;
4257 This->format.spacingmethod = method;
4258 This->format.spacing = spacing;
4259 This->format.baseline = baseline;
4260 return S_OK;
4263 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_GetTextAlignment(IDWriteTextFormat1 *iface)
4265 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4266 TRACE("(%p)\n", This);
4267 return This->format.textalignment;
4270 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_GetParagraphAlignment(IDWriteTextFormat1 *iface)
4272 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4273 TRACE("(%p)\n", This);
4274 return This->format.paralign;
4277 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_GetWordWrapping(IDWriteTextFormat1 *iface)
4279 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4280 TRACE("(%p)\n", This);
4281 return This->format.wrapping;
4284 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_GetReadingDirection(IDWriteTextFormat1 *iface)
4286 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4287 TRACE("(%p)\n", This);
4288 return This->format.readingdir;
4291 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_GetFlowDirection(IDWriteTextFormat1 *iface)
4293 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4294 TRACE("(%p)\n", This);
4295 return This->format.flow;
4298 static FLOAT WINAPI dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat1 *iface)
4300 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4301 FIXME("(%p): stub\n", This);
4302 return 0.0;
4305 static HRESULT WINAPI dwritetextformat_GetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING *options,
4306 IDWriteInlineObject **trimming_sign)
4308 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4309 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
4311 *options = This->format.trimming;
4312 if ((*trimming_sign = This->format.trimmingsign))
4313 IDWriteInlineObject_AddRef(*trimming_sign);
4315 return S_OK;
4318 static HRESULT WINAPI dwritetextformat_GetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD *method,
4319 FLOAT *spacing, FLOAT *baseline)
4321 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4322 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
4324 *method = This->format.spacingmethod;
4325 *spacing = This->format.spacing;
4326 *baseline = This->format.baseline;
4327 return S_OK;
4330 static HRESULT WINAPI dwritetextformat_GetFontCollection(IDWriteTextFormat1 *iface, IDWriteFontCollection **collection)
4332 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4334 TRACE("(%p)->(%p)\n", This, collection);
4336 *collection = This->format.collection;
4337 IDWriteFontCollection_AddRef(*collection);
4339 return S_OK;
4342 static UINT32 WINAPI dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat1 *iface)
4344 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4345 TRACE("(%p)\n", This);
4346 return This->format.family_len;
4349 static HRESULT WINAPI dwritetextformat_GetFontFamilyName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
4351 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4353 TRACE("(%p)->(%p %u)\n", This, name, size);
4355 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
4356 strcpyW(name, This->format.family_name);
4357 return S_OK;
4360 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_GetFontWeight(IDWriteTextFormat1 *iface)
4362 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4363 TRACE("(%p)\n", This);
4364 return This->format.weight;
4367 static DWRITE_FONT_STYLE WINAPI dwritetextformat_GetFontStyle(IDWriteTextFormat1 *iface)
4369 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4370 TRACE("(%p)\n", This);
4371 return This->format.style;
4374 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_GetFontStretch(IDWriteTextFormat1 *iface)
4376 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4377 TRACE("(%p)\n", This);
4378 return This->format.stretch;
4381 static FLOAT WINAPI dwritetextformat_GetFontSize(IDWriteTextFormat1 *iface)
4383 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4384 TRACE("(%p)\n", This);
4385 return This->format.fontsize;
4388 static UINT32 WINAPI dwritetextformat_GetLocaleNameLength(IDWriteTextFormat1 *iface)
4390 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4391 TRACE("(%p)\n", This);
4392 return This->format.locale_len;
4395 static HRESULT WINAPI dwritetextformat_GetLocaleName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
4397 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4399 TRACE("(%p)->(%p %u)\n", This, name, size);
4401 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
4402 strcpyW(name, This->format.locale);
4403 return S_OK;
4406 static HRESULT WINAPI dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat1 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4408 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4410 TRACE("(%p)->(%d)\n", This, orientation);
4412 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
4413 return E_INVALIDARG;
4415 This->format.vertical_orientation = orientation;
4416 return S_OK;
4419 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat1 *iface)
4421 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4422 TRACE("(%p)\n", This);
4423 return This->format.vertical_orientation;
4426 static HRESULT WINAPI dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat1 *iface, BOOL lastline_wrapping_enabled)
4428 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4429 FIXME("(%p)->(%d): stub\n", This, lastline_wrapping_enabled);
4430 return E_NOTIMPL;
4433 static BOOL WINAPI dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat1 *iface)
4435 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4436 FIXME("(%p): stub\n", This);
4437 return FALSE;
4440 static HRESULT WINAPI dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat1 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
4442 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4443 FIXME("(%p)->(%d): stub\n", This, alignment);
4444 return E_NOTIMPL;
4447 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat1 *iface)
4449 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4450 FIXME("(%p): stub\n", This);
4451 return DWRITE_OPTICAL_ALIGNMENT_NONE;
4454 static HRESULT WINAPI dwritetextformat1_SetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback *fallback)
4456 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4457 TRACE("(%p)->(%p)\n", This, fallback);
4458 return set_fontfallback_for_format(&This->format, fallback);
4461 static HRESULT WINAPI dwritetextformat1_GetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback **fallback)
4463 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4464 TRACE("(%p)->(%p)\n", This, fallback);
4465 return get_fontfallback_from_format(&This->format, fallback);
4468 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl = {
4469 dwritetextformat_QueryInterface,
4470 dwritetextformat_AddRef,
4471 dwritetextformat_Release,
4472 dwritetextformat_SetTextAlignment,
4473 dwritetextformat_SetParagraphAlignment,
4474 dwritetextformat_SetWordWrapping,
4475 dwritetextformat_SetReadingDirection,
4476 dwritetextformat_SetFlowDirection,
4477 dwritetextformat_SetIncrementalTabStop,
4478 dwritetextformat_SetTrimming,
4479 dwritetextformat_SetLineSpacing,
4480 dwritetextformat_GetTextAlignment,
4481 dwritetextformat_GetParagraphAlignment,
4482 dwritetextformat_GetWordWrapping,
4483 dwritetextformat_GetReadingDirection,
4484 dwritetextformat_GetFlowDirection,
4485 dwritetextformat_GetIncrementalTabStop,
4486 dwritetextformat_GetTrimming,
4487 dwritetextformat_GetLineSpacing,
4488 dwritetextformat_GetFontCollection,
4489 dwritetextformat_GetFontFamilyNameLength,
4490 dwritetextformat_GetFontFamilyName,
4491 dwritetextformat_GetFontWeight,
4492 dwritetextformat_GetFontStyle,
4493 dwritetextformat_GetFontStretch,
4494 dwritetextformat_GetFontSize,
4495 dwritetextformat_GetLocaleNameLength,
4496 dwritetextformat_GetLocaleName,
4497 dwritetextformat1_SetVerticalGlyphOrientation,
4498 dwritetextformat1_GetVerticalGlyphOrientation,
4499 dwritetextformat1_SetLastLineWrapping,
4500 dwritetextformat1_GetLastLineWrapping,
4501 dwritetextformat1_SetOpticalAlignment,
4502 dwritetextformat1_GetOpticalAlignment,
4503 dwritetextformat1_SetFontFallback,
4504 dwritetextformat1_GetFontFallback
4507 HRESULT create_textformat(const WCHAR *family_name, IDWriteFontCollection *collection, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style,
4508 DWRITE_FONT_STRETCH stretch, FLOAT size, const WCHAR *locale, IDWriteTextFormat **format)
4510 struct dwrite_textformat *This;
4512 *format = NULL;
4514 This = heap_alloc(sizeof(struct dwrite_textformat));
4515 if (!This) return E_OUTOFMEMORY;
4517 This->IDWriteTextFormat1_iface.lpVtbl = &dwritetextformatvtbl;
4518 This->ref = 1;
4519 This->format.family_name = heap_strdupW(family_name);
4520 This->format.family_len = strlenW(family_name);
4521 This->format.locale = heap_strdupW(locale);
4522 This->format.locale_len = strlenW(locale);
4523 This->format.weight = weight;
4524 This->format.style = style;
4525 This->format.fontsize = size;
4526 This->format.stretch = stretch;
4527 This->format.textalignment = DWRITE_TEXT_ALIGNMENT_LEADING;
4528 This->format.paralign = DWRITE_PARAGRAPH_ALIGNMENT_NEAR;
4529 This->format.wrapping = DWRITE_WORD_WRAPPING_WRAP;
4530 This->format.readingdir = DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
4531 This->format.flow = DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM;
4532 This->format.spacingmethod = DWRITE_LINE_SPACING_METHOD_DEFAULT;
4533 This->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
4534 This->format.spacing = 0.0;
4535 This->format.baseline = 0.0;
4536 This->format.trimming.granularity = DWRITE_TRIMMING_GRANULARITY_NONE;
4537 This->format.trimming.delimiter = 0;
4538 This->format.trimming.delimiterCount = 0;
4539 This->format.trimmingsign = NULL;
4540 This->format.collection = collection;
4541 This->format.fallback = NULL;
4542 IDWriteFontCollection_AddRef(collection);
4544 *format = (IDWriteTextFormat*)&This->IDWriteTextFormat1_iface;
4546 return S_OK;
4549 static HRESULT WINAPI dwritetypography_QueryInterface(IDWriteTypography *iface, REFIID riid, void **obj)
4551 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4553 TRACE("(%p)->(%s %p)\n", typography, debugstr_guid(riid), obj);
4555 if (IsEqualIID(riid, &IID_IDWriteTypography) || IsEqualIID(riid, &IID_IUnknown)) {
4556 *obj = iface;
4557 IDWriteTypography_AddRef(iface);
4558 return S_OK;
4561 *obj = NULL;
4563 return E_NOINTERFACE;
4566 static ULONG WINAPI dwritetypography_AddRef(IDWriteTypography *iface)
4568 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4569 ULONG ref = InterlockedIncrement(&typography->ref);
4570 TRACE("(%p)->(%d)\n", typography, ref);
4571 return ref;
4574 static ULONG WINAPI dwritetypography_Release(IDWriteTypography *iface)
4576 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4577 ULONG ref = InterlockedDecrement(&typography->ref);
4579 TRACE("(%p)->(%d)\n", typography, ref);
4581 if (!ref) {
4582 heap_free(typography->features);
4583 heap_free(typography);
4586 return ref;
4589 static HRESULT WINAPI dwritetypography_AddFontFeature(IDWriteTypography *iface, DWRITE_FONT_FEATURE feature)
4591 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4593 TRACE("(%p)->(%x %u)\n", typography, feature.nameTag, feature.parameter);
4595 if (typography->count == typography->allocated) {
4596 DWRITE_FONT_FEATURE *ptr = heap_realloc(typography->features, 2*typography->allocated*sizeof(DWRITE_FONT_FEATURE));
4597 if (!ptr)
4598 return E_OUTOFMEMORY;
4600 typography->features = ptr;
4601 typography->allocated *= 2;
4604 typography->features[typography->count++] = feature;
4605 return S_OK;
4608 static UINT32 WINAPI dwritetypography_GetFontFeatureCount(IDWriteTypography *iface)
4610 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4611 TRACE("(%p)\n", typography);
4612 return typography->count;
4615 static HRESULT WINAPI dwritetypography_GetFontFeature(IDWriteTypography *iface, UINT32 index, DWRITE_FONT_FEATURE *feature)
4617 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4619 TRACE("(%p)->(%u %p)\n", typography, index, feature);
4621 if (index >= typography->count)
4622 return E_INVALIDARG;
4624 *feature = typography->features[index];
4625 return S_OK;
4628 static const IDWriteTypographyVtbl dwritetypographyvtbl = {
4629 dwritetypography_QueryInterface,
4630 dwritetypography_AddRef,
4631 dwritetypography_Release,
4632 dwritetypography_AddFontFeature,
4633 dwritetypography_GetFontFeatureCount,
4634 dwritetypography_GetFontFeature
4637 HRESULT create_typography(IDWriteTypography **ret)
4639 struct dwrite_typography *typography;
4641 *ret = NULL;
4643 typography = heap_alloc(sizeof(*typography));
4644 if (!typography)
4645 return E_OUTOFMEMORY;
4647 typography->IDWriteTypography_iface.lpVtbl = &dwritetypographyvtbl;
4648 typography->ref = 1;
4649 typography->allocated = 2;
4650 typography->count = 0;
4652 typography->features = heap_alloc(typography->allocated*sizeof(DWRITE_FONT_FEATURE));
4653 if (!typography->features) {
4654 heap_free(typography);
4655 return E_OUTOFMEMORY;
4658 *ret = &typography->IDWriteTypography_iface;
4659 return S_OK;