dwrite: Validate per-range attribute values.
[wine.git] / dlls / dwrite / layout.c
blob150e34bea91d58067ab72b5d1ff61c322e092c9a
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>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "dwrite_private.h"
29 #include "scripts.h"
30 #include "wine/list.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
34 struct dwrite_textformat_data {
35 WCHAR *family_name;
36 UINT32 family_len;
37 WCHAR *locale;
38 UINT32 locale_len;
40 DWRITE_FONT_WEIGHT weight;
41 DWRITE_FONT_STYLE style;
42 DWRITE_FONT_STRETCH stretch;
44 DWRITE_PARAGRAPH_ALIGNMENT paralign;
45 DWRITE_READING_DIRECTION readingdir;
46 DWRITE_WORD_WRAPPING wrapping;
47 DWRITE_TEXT_ALIGNMENT textalignment;
48 DWRITE_FLOW_DIRECTION flow;
49 DWRITE_LINE_SPACING_METHOD spacingmethod;
50 DWRITE_VERTICAL_GLYPH_ORIENTATION vertical_orientation;
52 FLOAT spacing;
53 FLOAT baseline;
54 FLOAT fontsize;
56 DWRITE_TRIMMING trimming;
57 IDWriteInlineObject *trimmingsign;
59 IDWriteFontCollection *collection;
60 IDWriteFontFallback *fallback;
63 enum layout_range_attr_kind {
64 LAYOUT_RANGE_ATTR_WEIGHT,
65 LAYOUT_RANGE_ATTR_STYLE,
66 LAYOUT_RANGE_ATTR_STRETCH,
67 LAYOUT_RANGE_ATTR_FONTSIZE,
68 LAYOUT_RANGE_ATTR_EFFECT,
69 LAYOUT_RANGE_ATTR_INLINE,
70 LAYOUT_RANGE_ATTR_UNDERLINE,
71 LAYOUT_RANGE_ATTR_STRIKETHROUGH,
72 LAYOUT_RANGE_ATTR_PAIR_KERNING,
73 LAYOUT_RANGE_ATTR_FONTCOLL,
74 LAYOUT_RANGE_ATTR_LOCALE,
75 LAYOUT_RANGE_ATTR_FONTFAMILY
78 struct layout_range_attr_value {
79 DWRITE_TEXT_RANGE range;
80 union {
81 DWRITE_FONT_WEIGHT weight;
82 DWRITE_FONT_STYLE style;
83 DWRITE_FONT_STRETCH stretch;
84 FLOAT fontsize;
85 IDWriteInlineObject *object;
86 IUnknown *effect;
87 BOOL underline;
88 BOOL strikethrough;
89 BOOL pair_kerning;
90 IDWriteFontCollection *collection;
91 const WCHAR *locale;
92 const WCHAR *fontfamily;
93 } u;
96 enum layout_range_kind {
97 LAYOUT_RANGE_REGULAR,
98 LAYOUT_RANGE_STRIKETHROUGH
101 struct layout_range_header {
102 struct list entry;
103 enum layout_range_kind kind;
104 DWRITE_TEXT_RANGE range;
107 struct layout_range {
108 struct layout_range_header h;
109 DWRITE_FONT_WEIGHT weight;
110 DWRITE_FONT_STYLE style;
111 FLOAT fontsize;
112 DWRITE_FONT_STRETCH stretch;
113 IDWriteInlineObject *object;
114 IUnknown *effect;
115 BOOL underline;
116 BOOL pair_kerning;
117 IDWriteFontCollection *collection;
118 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
119 WCHAR *fontfamily;
122 struct layout_range_bool {
123 struct layout_range_header h;
124 BOOL value;
127 enum layout_run_kind {
128 LAYOUT_RUN_REGULAR,
129 LAYOUT_RUN_INLINE
132 struct inline_object_run {
133 IDWriteInlineObject *object;
134 UINT16 length;
137 struct regular_layout_run {
138 DWRITE_GLYPH_RUN_DESCRIPTION descr;
139 DWRITE_GLYPH_RUN run;
140 DWRITE_SCRIPT_ANALYSIS sa;
141 UINT16 *glyphs;
142 UINT16 *clustermap;
143 FLOAT *advances;
144 DWRITE_GLYPH_OFFSET *offsets;
145 /* this is actual glyph count after shaping, it's not necessary the same as reported to Draw() */
146 UINT32 glyphcount;
149 struct layout_run {
150 struct list entry;
151 enum layout_run_kind kind;
152 union {
153 struct inline_object_run object;
154 struct regular_layout_run regular;
155 } u;
156 IUnknown *effect;
159 struct layout_effective_run {
160 struct list entry;
161 const struct layout_run *run; /* nominal run this one is based on */
162 UINT32 start; /* relative text position, 0 means first text position of a nominal run */
163 UINT32 length; /* length in codepoints that this run covers */
164 UINT32 glyphcount; /* total glyph count in this run */
165 FLOAT origin_x; /* baseline X position */
166 FLOAT origin_y; /* baseline Y position */
167 UINT16 *clustermap; /* effective clustermap, allocated separately, is not reused from nominal map */
170 struct layout_effective_inline {
171 struct list entry;
172 IDWriteInlineObject *object;
173 FLOAT origin_x;
174 FLOAT origin_y;
175 BOOL is_sideways;
176 BOOL is_rtl;
179 struct layout_strikethrough {
180 struct list entry;
181 const struct layout_effective_run *run;
182 DWRITE_STRIKETHROUGH s;
185 struct layout_cluster {
186 const struct layout_run *run; /* link to nominal run this cluster belongs to */
187 UINT32 position; /* relative to run, first cluster has 0 position */
190 enum layout_recompute_mask {
191 RECOMPUTE_NOMINAL_RUNS = 1 << 0,
192 RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
193 RECOMPUTE_EFFECTIVE_RUNS = 1 << 2,
194 RECOMPUTE_EVERYTHING = 0xffff
197 struct dwrite_textlayout {
198 IDWriteTextLayout2 IDWriteTextLayout2_iface;
199 IDWriteTextFormat1 IDWriteTextFormat1_iface;
200 IDWriteTextAnalysisSink IDWriteTextAnalysisSink_iface;
201 IDWriteTextAnalysisSource IDWriteTextAnalysisSource_iface;
202 LONG ref;
204 WCHAR *str;
205 UINT32 len;
206 struct dwrite_textformat_data format;
207 FLOAT maxwidth;
208 FLOAT maxheight;
209 struct list strike_ranges;
210 struct list ranges;
211 struct list runs;
212 /* lists ready to use by Draw() */
213 struct list eruns;
214 struct list inlineobjects;
215 struct list strikethrough;
216 USHORT recompute;
218 DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
219 DWRITE_LINE_BREAKPOINT *actual_breakpoints;
221 struct layout_cluster *clusters;
222 DWRITE_CLUSTER_METRICS *clustermetrics;
223 UINT32 cluster_count;
224 FLOAT minwidth;
226 DWRITE_LINE_METRICS *lines;
227 UINT32 line_count;
228 UINT32 line_alloc;
230 /* gdi-compatible layout specifics */
231 BOOL gdicompatible;
232 FLOAT pixels_per_dip;
233 BOOL use_gdi_natural;
234 DWRITE_MATRIX transform;
237 struct dwrite_textformat {
238 IDWriteTextFormat1 IDWriteTextFormat1_iface;
239 LONG ref;
240 struct dwrite_textformat_data format;
243 struct dwrite_trimmingsign {
244 IDWriteInlineObject IDWriteInlineObject_iface;
245 LONG ref;
248 struct dwrite_typography {
249 IDWriteTypography IDWriteTypography_iface;
250 LONG ref;
252 DWRITE_FONT_FEATURE *features;
253 UINT32 allocated;
254 UINT32 count;
257 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl;
259 static void release_format_data(struct dwrite_textformat_data *data)
261 if (data->collection) IDWriteFontCollection_Release(data->collection);
262 if (data->fallback) IDWriteFontFallback_Release(data->fallback);
263 if (data->trimmingsign) IDWriteInlineObject_Release(data->trimmingsign);
264 heap_free(data->family_name);
265 heap_free(data->locale);
268 static inline struct dwrite_textlayout *impl_from_IDWriteTextLayout2(IDWriteTextLayout2 *iface)
270 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextLayout2_iface);
273 static inline struct dwrite_textlayout *impl_layout_form_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
275 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextFormat1_iface);
278 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSink(IDWriteTextAnalysisSink *iface)
280 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSink_iface);
283 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSource(IDWriteTextAnalysisSource *iface)
285 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSource_iface);
288 static inline struct dwrite_textformat *impl_from_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
290 return CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat1_iface);
293 static inline struct dwrite_trimmingsign *impl_from_IDWriteInlineObject(IDWriteInlineObject *iface)
295 return CONTAINING_RECORD(iface, struct dwrite_trimmingsign, IDWriteInlineObject_iface);
298 static inline struct dwrite_typography *impl_from_IDWriteTypography(IDWriteTypography *iface)
300 return CONTAINING_RECORD(iface, struct dwrite_typography, IDWriteTypography_iface);
303 static inline const char *debugstr_run(const struct regular_layout_run *run)
305 return wine_dbg_sprintf("[%u,%u)", run->descr.textPosition, run->descr.textPosition +
306 run->descr.stringLength);
309 static HRESULT get_fontfallback_from_format(const struct dwrite_textformat_data *format, IDWriteFontFallback **fallback)
311 *fallback = format->fallback;
312 if (*fallback)
313 IDWriteFontFallback_AddRef(*fallback);
314 return S_OK;
317 static HRESULT set_fontfallback_for_format(struct dwrite_textformat_data *format, IDWriteFontFallback *fallback)
319 if (format->fallback)
320 IDWriteFontFallback_Release(format->fallback);
321 format->fallback = fallback;
322 if (fallback)
323 IDWriteFontFallback_AddRef(fallback);
324 return S_OK;
327 static struct layout_run *alloc_layout_run(enum layout_run_kind kind)
329 struct layout_run *ret;
331 ret = heap_alloc(sizeof(*ret));
332 if (!ret) return NULL;
334 memset(ret, 0, sizeof(*ret));
335 ret->kind = kind;
336 if (kind == LAYOUT_RUN_REGULAR) {
337 ret->u.regular.sa.script = Script_Unknown;
338 ret->u.regular.sa.shapes = DWRITE_SCRIPT_SHAPES_DEFAULT;
341 return ret;
344 static void free_layout_runs(struct dwrite_textlayout *layout)
346 struct layout_run *cur, *cur2;
347 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->runs, struct layout_run, entry) {
348 list_remove(&cur->entry);
349 if (cur->kind == LAYOUT_RUN_REGULAR) {
350 if (cur->u.regular.run.fontFace)
351 IDWriteFontFace_Release(cur->u.regular.run.fontFace);
352 heap_free(cur->u.regular.glyphs);
353 heap_free(cur->u.regular.clustermap);
354 heap_free(cur->u.regular.advances);
355 heap_free(cur->u.regular.offsets);
357 heap_free(cur);
361 static void free_layout_eruns(struct dwrite_textlayout *layout)
363 struct layout_effective_inline *in, *in2;
364 struct layout_effective_run *cur, *cur2;
365 struct layout_strikethrough *s, *s2;
367 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->eruns, struct layout_effective_run, entry) {
368 list_remove(&cur->entry);
369 heap_free(cur->clustermap);
370 heap_free(cur);
373 LIST_FOR_EACH_ENTRY_SAFE(in, in2, &layout->inlineobjects, struct layout_effective_inline, entry) {
374 list_remove(&in->entry);
375 heap_free(in);
378 LIST_FOR_EACH_ENTRY_SAFE(s, s2, &layout->strikethrough, struct layout_strikethrough, entry) {
379 list_remove(&s->entry);
380 heap_free(s);
384 /* Used to resolve break condition by forcing stronger condition over weaker. */
385 static inline DWRITE_BREAK_CONDITION override_break_condition(DWRITE_BREAK_CONDITION existingbreak, DWRITE_BREAK_CONDITION newbreak)
387 switch (existingbreak) {
388 case DWRITE_BREAK_CONDITION_NEUTRAL:
389 return newbreak;
390 case DWRITE_BREAK_CONDITION_CAN_BREAK:
391 return newbreak == DWRITE_BREAK_CONDITION_NEUTRAL ? existingbreak : newbreak;
392 /* let's keep stronger conditions as is */
393 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK:
394 case DWRITE_BREAK_CONDITION_MUST_BREAK:
395 break;
396 default:
397 ERR("unknown break condition %d\n", existingbreak);
400 return existingbreak;
403 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
404 static HRESULT layout_update_breakpoints_range(struct dwrite_textlayout *layout, const struct layout_range *cur)
406 DWRITE_BREAK_CONDITION before, after;
407 HRESULT hr;
408 UINT32 i;
410 /* ignore returned conditions if failed */
411 hr = IDWriteInlineObject_GetBreakConditions(cur->object, &before, &after);
412 if (FAILED(hr))
413 after = before = DWRITE_BREAK_CONDITION_NEUTRAL;
415 if (!layout->actual_breakpoints) {
416 layout->actual_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
417 if (!layout->actual_breakpoints)
418 return E_OUTOFMEMORY;
419 memcpy(layout->actual_breakpoints, layout->nominal_breakpoints, sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
422 for (i = cur->h.range.startPosition; i < cur->h.range.length + cur->h.range.startPosition; i++) {
423 /* for first codepoint check if there's anything before it and update accordingly */
424 if (i == cur->h.range.startPosition) {
425 if (i > 0)
426 layout->actual_breakpoints[i].breakConditionBefore = layout->actual_breakpoints[i-1].breakConditionAfter =
427 override_break_condition(layout->actual_breakpoints[i-1].breakConditionAfter, before);
428 else
429 layout->actual_breakpoints[i].breakConditionBefore = before;
430 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
432 /* similar check for last codepoint */
433 else if (i == cur->h.range.startPosition + cur->h.range.length - 1) {
434 if (i == layout->len - 1)
435 layout->actual_breakpoints[i].breakConditionAfter = after;
436 else
437 layout->actual_breakpoints[i].breakConditionAfter = layout->actual_breakpoints[i+1].breakConditionBefore =
438 override_break_condition(layout->actual_breakpoints[i+1].breakConditionBefore, after);
439 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
441 /* for all positions within a range disable breaks */
442 else {
443 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
444 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
447 layout->actual_breakpoints[i].isWhitespace = FALSE;
448 layout->actual_breakpoints[i].isSoftHyphen = FALSE;
451 return S_OK;
454 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos);
456 static inline DWRITE_LINE_BREAKPOINT get_effective_breakpoint(const struct dwrite_textlayout *layout, UINT32 pos)
458 if (layout->actual_breakpoints)
459 return layout->actual_breakpoints[pos];
460 return layout->nominal_breakpoints[pos];
463 static inline void init_cluster_metrics(const struct dwrite_textlayout *layout, const struct regular_layout_run *run,
464 UINT16 start_glyph, UINT16 stop_glyph, UINT32 stop_position, DWRITE_CLUSTER_METRICS *metrics)
466 UINT8 breakcondition;
467 UINT32 position;
468 UINT16 j;
470 metrics->width = 0.0;
472 /* For clusters on control chars we report zero glyphs, and we need zero cluster
473 width as well; advances are already computed at this point and are not necessary zero. */
474 if (run->run.glyphCount) {
475 for (j = start_glyph; j < stop_glyph; j++)
476 metrics->width += run->run.glyphAdvances[j];
478 metrics->length = 0;
480 position = stop_position;
481 if (stop_glyph == run->glyphcount)
482 breakcondition = get_effective_breakpoint(layout, stop_position).breakConditionAfter;
483 else {
484 breakcondition = get_effective_breakpoint(layout, stop_position).breakConditionBefore;
485 if (stop_position) position = stop_position - 1;
488 metrics->canWrapLineAfter = breakcondition == DWRITE_BREAK_CONDITION_CAN_BREAK ||
489 breakcondition == DWRITE_BREAK_CONDITION_MUST_BREAK;
490 if (metrics->length == 1) {
491 WORD type;
493 GetStringTypeW(CT_CTYPE1, &layout->str[position], 1, &type);
494 metrics->isWhitespace = type == C1_SPACE;
495 metrics->isNewline = FALSE /* FIXME */;
496 metrics->isSoftHyphen = layout->str[position] == 0x00ad /* Unicode Soft Hyphen */;
498 else {
499 metrics->isWhitespace = FALSE;
500 metrics->isNewline = FALSE;
501 metrics->isSoftHyphen = FALSE;
503 metrics->isRightToLeft = run->run.bidiLevel & 1;
504 metrics->padding = 0;
509 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
510 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
511 Note that there's no need to reallocate anything at this point as we allocate one cluster per
512 codepoint initially.
515 static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 *cluster)
517 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[*cluster];
518 struct layout_cluster *c = &layout->clusters[*cluster];
519 const struct regular_layout_run *run = &r->u.regular;
520 UINT32 i, start = 0;
522 for (i = 0; i < run->descr.stringLength; i++) {
523 BOOL end = i == run->descr.stringLength - 1;
525 if (run->descr.clusterMap[start] != run->descr.clusterMap[i]) {
526 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->descr.clusterMap[i], i, metrics);
527 metrics->length = i - start;
528 c->position = start;
529 c->run = r;
531 *cluster += 1;
532 metrics++;
533 c++;
534 start = i;
537 if (end) {
538 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->glyphcount, i, metrics);
539 metrics->length = i - start + 1;
540 c->position = start;
541 c->run = r;
543 *cluster += 1;
544 return;
549 /* This helper should be used to get effective range length, in other words it returns number of text
550 positions from range starting point to the end of the range, limited by layout text length */
551 static inline UINT32 get_clipped_range_length(const struct dwrite_textlayout *layout, const struct layout_range *range)
553 if (range->h.range.startPosition + range->h.range.length <= layout->len)
554 return range->h.range.length;
555 return layout->len - range->h.range.startPosition;
558 static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
560 IDWriteTextAnalyzer *analyzer;
561 struct layout_range *range;
562 struct layout_run *r;
563 UINT32 cluster = 0;
564 HRESULT hr;
566 free_layout_eruns(layout);
567 free_layout_runs(layout);
569 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
570 if (!layout->clustermetrics) {
571 layout->clustermetrics = heap_alloc(layout->len*sizeof(*layout->clustermetrics));
572 layout->clusters = heap_alloc(layout->len*sizeof(*layout->clusters));
573 if (!layout->clustermetrics || !layout->clusters) {
574 heap_free(layout->clustermetrics);
575 heap_free(layout->clusters);
576 return E_OUTOFMEMORY;
579 layout->cluster_count = 0;
581 hr = get_textanalyzer(&analyzer);
582 if (FAILED(hr))
583 return hr;
585 LIST_FOR_EACH_ENTRY(range, &layout->ranges, struct layout_range, h.entry) {
586 /* we don't care about ranges that don't contain any text */
587 if (range->h.range.startPosition >= layout->len)
588 break;
590 /* inline objects override actual text in a range */
591 if (range->object) {
592 hr = layout_update_breakpoints_range(layout, range);
593 if (FAILED(hr))
594 return hr;
596 r = alloc_layout_run(LAYOUT_RUN_INLINE);
597 if (!r)
598 return E_OUTOFMEMORY;
600 r->u.object.object = range->object;
601 r->u.object.length = get_clipped_range_length(layout, range);
602 r->effect = range->effect;
603 list_add_tail(&layout->runs, &r->entry);
604 continue;
607 /* initial splitting by script */
608 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, &layout->IDWriteTextAnalysisSource_iface,
609 range->h.range.startPosition, get_clipped_range_length(layout, range), &layout->IDWriteTextAnalysisSink_iface);
610 if (FAILED(hr))
611 break;
613 /* this splits it further */
614 hr = IDWriteTextAnalyzer_AnalyzeBidi(analyzer, &layout->IDWriteTextAnalysisSource_iface,
615 range->h.range.startPosition, get_clipped_range_length(layout, range), &layout->IDWriteTextAnalysisSink_iface);
616 if (FAILED(hr))
617 break;
620 /* fill run info */
621 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
622 DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props = NULL;
623 DWRITE_SHAPING_TEXT_PROPERTIES *text_props = NULL;
624 struct regular_layout_run *run = &r->u.regular;
625 IDWriteFontFamily *family;
626 UINT32 index, max_count;
627 IDWriteFont *font;
628 BOOL exists = TRUE;
630 /* we need to do very little in case of inline objects */
631 if (r->kind == LAYOUT_RUN_INLINE) {
632 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[cluster];
633 struct layout_cluster *c = &layout->clusters[cluster];
634 DWRITE_INLINE_OBJECT_METRICS inlinemetrics;
636 metrics->width = 0.0;
637 metrics->length = r->u.object.length;
638 metrics->canWrapLineAfter = FALSE;
639 metrics->isWhitespace = FALSE;
640 metrics->isNewline = FALSE;
641 metrics->isSoftHyphen = FALSE;
642 metrics->isRightToLeft = FALSE;
643 metrics->padding = 0;
644 c->run = r;
645 c->position = 0; /* there's always one cluster per inline object, so 0 is valid value */
646 cluster++;
648 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
649 hr = IDWriteInlineObject_GetMetrics(r->u.object.object, &inlinemetrics);
650 if (FAILED(hr)) {
651 memset(&inlinemetrics, 0, sizeof(inlinemetrics));
652 hr = S_OK;
654 metrics->width = inlinemetrics.width;
656 /* FIXME: use resolved breakpoints in this case too */
658 continue;
661 range = get_layout_range_by_pos(layout, run->descr.textPosition);
662 r->effect = range->effect;
664 hr = IDWriteFontCollection_FindFamilyName(range->collection, range->fontfamily, &index, &exists);
665 if (FAILED(hr) || !exists) {
666 WARN("%s: family %s not found in collection %p\n", debugstr_run(run), debugstr_w(range->fontfamily), range->collection);
667 continue;
670 hr = IDWriteFontCollection_GetFontFamily(range->collection, index, &family);
671 if (FAILED(hr))
672 continue;
674 hr = IDWriteFontFamily_GetFirstMatchingFont(family, range->weight, range->stretch, range->style, &font);
675 IDWriteFontFamily_Release(family);
676 if (FAILED(hr)) {
677 WARN("%s: failed to get a matching font\n", debugstr_run(run));
678 continue;
681 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
682 IDWriteFont_Release(font);
683 if (FAILED(hr))
684 continue;
686 run->run.fontEmSize = range->fontsize;
687 run->descr.localeName = range->locale;
688 run->clustermap = heap_alloc(run->descr.stringLength*sizeof(UINT16));
690 max_count = 3*run->descr.stringLength/2 + 16;
691 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
692 if (!run->clustermap || !run->glyphs)
693 goto memerr;
695 text_props = heap_alloc(run->descr.stringLength*sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
696 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
697 if (!text_props || !glyph_props)
698 goto memerr;
700 while (1) {
701 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, run->descr.string, run->descr.stringLength,
702 run->run.fontFace, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
703 NULL /* FIXME */, NULL, NULL, 0, max_count, run->clustermap, text_props, run->glyphs, glyph_props,
704 &run->glyphcount);
705 if (hr == E_NOT_SUFFICIENT_BUFFER) {
706 heap_free(run->glyphs);
707 heap_free(glyph_props);
709 max_count = run->glyphcount;
711 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
712 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
713 if (!run->glyphs || !glyph_props)
714 goto memerr;
716 continue;
719 break;
722 if (FAILED(hr)) {
723 heap_free(text_props);
724 heap_free(glyph_props);
725 WARN("%s: shaping failed 0x%08x\n", debugstr_run(run), hr);
726 continue;
729 run->run.glyphIndices = run->glyphs;
730 run->descr.clusterMap = run->clustermap;
732 run->advances = heap_alloc(run->glyphcount*sizeof(FLOAT));
733 run->offsets = heap_alloc(run->glyphcount*sizeof(DWRITE_GLYPH_OFFSET));
734 if (!run->advances || !run->offsets)
735 goto memerr;
737 /* now set advances and offsets */
738 if (layout->gdicompatible)
739 hr = IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap,
740 text_props, run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount,
741 run->run.fontFace, run->run.fontEmSize, layout->pixels_per_dip, &layout->transform, layout->use_gdi_natural,
742 run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL, NULL, 0,
743 run->advances, run->offsets);
744 else
745 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap, text_props,
746 run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount, run->run.fontFace,
747 run->run.fontEmSize, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
748 NULL, NULL, 0, run->advances, run->offsets);
750 heap_free(text_props);
751 heap_free(glyph_props);
752 if (FAILED(hr))
753 WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_run(run), hr);
755 run->run.glyphAdvances = run->advances;
756 run->run.glyphOffsets = run->offsets;
758 /* Special treatment of control script, shaping code adds normal glyphs for it,
759 with non-zero advances, and layout code exposes those as zero width clusters,
760 so we have to do it manually. */
761 if (run->sa.script == Script_Common)
762 run->run.glyphCount = 0;
763 else
764 run->run.glyphCount = run->glyphcount;
765 layout_set_cluster_metrics(layout, r, &cluster);
767 continue;
769 memerr:
770 heap_free(text_props);
771 heap_free(glyph_props);
772 heap_free(run->clustermap);
773 heap_free(run->glyphs);
774 heap_free(run->advances);
775 heap_free(run->offsets);
776 run->advances = NULL;
777 run->offsets = NULL;
778 run->clustermap = run->glyphs = NULL;
779 hr = E_OUTOFMEMORY;
780 break;
783 if (hr == S_OK)
784 layout->cluster_count = cluster;
786 IDWriteTextAnalyzer_Release(analyzer);
787 return hr;
790 static HRESULT layout_compute(struct dwrite_textlayout *layout)
792 HRESULT hr;
794 if (!(layout->recompute & RECOMPUTE_NOMINAL_RUNS))
795 return S_OK;
797 /* nominal breakpoints are evaluated only once, because string never changes */
798 if (!layout->nominal_breakpoints) {
799 IDWriteTextAnalyzer *analyzer;
800 HRESULT hr;
802 layout->nominal_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
803 if (!layout->nominal_breakpoints)
804 return E_OUTOFMEMORY;
806 hr = get_textanalyzer(&analyzer);
807 if (FAILED(hr))
808 return hr;
810 hr = IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer, &layout->IDWriteTextAnalysisSource_iface,
811 0, layout->len, &layout->IDWriteTextAnalysisSink_iface);
812 IDWriteTextAnalyzer_Release(analyzer);
814 if (layout->actual_breakpoints) {
815 heap_free(layout->actual_breakpoints);
816 layout->actual_breakpoints = NULL;
819 hr = layout_compute_runs(layout);
821 if (TRACE_ON(dwrite)) {
822 struct layout_run *cur;
824 LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
825 if (cur->kind == LAYOUT_RUN_INLINE)
826 TRACE("run inline object %p, len %u\n", cur->u.object.object, cur->u.object.length);
827 else
828 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur->u.regular.descr.textPosition, cur->u.regular.descr.textPosition +
829 cur->u.regular.descr.stringLength-1, cur->u.regular.descr.stringLength, cur->u.regular.run.bidiLevel);
833 layout->recompute &= ~RECOMPUTE_NOMINAL_RUNS;
834 return hr;
837 static inline FLOAT get_cluster_range_width(struct dwrite_textlayout *layout, UINT32 start, UINT32 end)
839 FLOAT width = 0.0;
840 for (; start < end; start++)
841 width += layout->clustermetrics[start].width;
842 return width;
845 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
846 'cluster_count' indicates how many clusters to add, including first one. */
847 static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 first_cluster,
848 UINT32 cluster_count, FLOAT origin_x, BOOL strikethrough)
850 UINT32 i, start, length, last_cluster;
851 struct layout_effective_run *run;
853 if (r->kind == LAYOUT_RUN_INLINE) {
854 struct layout_effective_inline *inlineobject;
856 inlineobject = heap_alloc(sizeof(*inlineobject));
857 if (!inlineobject)
858 return E_OUTOFMEMORY;
860 inlineobject->object = r->u.object.object;
861 inlineobject->origin_x = origin_x;
862 inlineobject->origin_y = 0.0; /* FIXME */
863 /* It's not clear how these two are set, possibly directionality
864 is derived from surrounding text (replaced text could have
865 different ranges which differ in reading direction). */
866 inlineobject->is_sideways = FALSE;
867 inlineobject->is_rtl = FALSE;
868 list_add_tail(&layout->inlineobjects, &inlineobject->entry);
869 return S_OK;
872 run = heap_alloc(sizeof(*run));
873 if (!run)
874 return E_OUTOFMEMORY;
876 /* No need to iterate for that, use simple fact that:
877 <last cluster position> = first cluster position> + <sum of cluster lengths not including last one> */
878 last_cluster = first_cluster + cluster_count - 1;
879 length = layout->clusters[last_cluster].position - layout->clusters[first_cluster].position +
880 layout->clustermetrics[last_cluster].length;
882 run->clustermap = heap_alloc(sizeof(UINT16)*length);
883 if (!run->clustermap) {
884 heap_free(run);
885 return E_OUTOFMEMORY;
888 run->run = r;
889 run->start = start = layout->clusters[first_cluster].position;
890 run->length = length;
891 run->origin_x = origin_x;
892 run->origin_y = 0.0; /* FIXME: set after line is built */
894 if (r->u.regular.run.glyphCount) {
895 /* trim from the left */
896 run->glyphcount = r->u.regular.run.glyphCount - r->u.regular.clustermap[start];
897 /* trim from the right */
898 if (length < r->u.regular.descr.stringLength)
899 run->glyphcount -= r->u.regular.clustermap[start + length];
901 else
902 run->glyphcount = 0;
904 /* cluster map needs to be shifted */
905 for (i = 0; i < length; i++)
906 run->clustermap[i] = r->u.regular.clustermap[start] - start;
908 list_add_tail(&layout->eruns, &run->entry);
910 /* Strikethrough style is guaranteed to be consistent within effective run,
911 it's width equals to run width, thikness and offset are derived from
912 font metrics, rest of the values are from layout or run itself */
913 if (strikethrough) {
914 DWRITE_FONT_METRICS metrics = { 0 };
915 struct layout_strikethrough *s;
917 s = heap_alloc(sizeof(*s));
918 if (!s)
919 return E_OUTOFMEMORY;
921 if (layout->gdicompatible) {
922 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(
923 r->u.regular.run.fontFace,
924 r->u.regular.run.fontEmSize,
925 layout->pixels_per_dip,
926 &layout->transform,
927 &metrics);
928 if (FAILED(hr))
929 WARN("failed to get font metrics, 0x%08x\n", hr);
931 else
932 IDWriteFontFace_GetMetrics(r->u.regular.run.fontFace, &metrics);
934 s->s.width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
935 s->s.thickness = metrics.strikethroughThickness;
936 s->s.offset = metrics.strikethroughPosition;
937 s->s.readingDirection = layout->format.readingdir;
938 s->s.flowDirection = layout->format.flow;
939 s->s.localeName = r->u.regular.descr.localeName;
940 s->s.measuringMode = DWRITE_MEASURING_MODE_NATURAL; /* FIXME */
941 s->run = run;
943 list_add_tail(&layout->strikethrough, &s->entry);
946 return S_OK;
949 static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_LINE_METRICS *metrics, UINT32 *line)
951 if (!layout->line_alloc) {
952 layout->line_alloc = 5;
953 layout->lines = heap_alloc(layout->line_alloc*sizeof(*layout->lines));
954 if (!layout->lines)
955 return E_OUTOFMEMORY;
958 if (layout->line_count == layout->line_alloc) {
959 DWRITE_LINE_METRICS *l = heap_realloc(layout->lines, layout->line_alloc*2*sizeof(*layout->lines));
960 if (!l)
961 return E_OUTOFMEMORY;
962 layout->lines = l;
963 layout->line_alloc *= 2;
966 layout->lines[*line] = *metrics;
967 *line += 1;
968 return S_OK;
971 static struct layout_range_header *get_layout_range_header_by_pos(struct list *ranges, UINT32 pos)
973 struct layout_range_header *cur;
975 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
976 DWRITE_TEXT_RANGE *r = &cur->range;
977 if (r->startPosition <= pos && pos < r->startPosition + r->length)
978 return cur;
981 return NULL;
984 static inline BOOL layout_get_strikethrough_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
986 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->strike_ranges, pos);
987 return ((struct layout_range_bool*)h)->value;
990 static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
992 DWRITE_LINE_METRICS metrics;
993 const struct layout_run *run;
994 FLOAT width, origin_x;
995 UINT32 i, start, line, textpos;
996 HRESULT hr;
997 BOOL s[2];
999 if (!(layout->recompute & RECOMPUTE_EFFECTIVE_RUNS))
1000 return S_OK;
1002 hr = layout_compute(layout);
1003 if (FAILED(hr))
1004 return hr;
1006 layout->line_count = 0;
1007 origin_x = 0.0;
1008 line = 0;
1009 run = layout->clusters[0].run;
1010 memset(&metrics, 0, sizeof(metrics));
1011 s[0] = s[1] = layout_get_strikethrough_from_pos(layout, 0);
1013 for (i = 0, start = 0, textpos = 0, width = 0.0; i < layout->cluster_count; i++) {
1014 BOOL can_wrap_after = layout->clustermetrics[i].canWrapLineAfter;
1016 s[1] = layout_get_strikethrough_from_pos(layout, textpos);
1018 /* switched to next nominal run, at this point all previous pending clusters are already
1019 checked for layout line overflow, so new effective run will fit in current line */
1020 if (run != layout->clusters[i].run || s[0] != s[1]) {
1021 hr = layout_add_effective_run(layout, run, start, i - start, origin_x, s[0]);
1022 if (FAILED(hr))
1023 return hr;
1024 origin_x += get_cluster_range_width(layout, start, i);
1025 run = layout->clusters[i].run;
1026 start = i;
1029 /* check if we got new line */
1030 if (((can_wrap_after && (width + layout->clustermetrics[i].width > layout->maxwidth)) ||
1031 layout->clustermetrics[i].isNewline || /* always wrap on new line */
1032 i == layout->cluster_count - 1)) /* end of the text */ {
1034 UINT32 strlength = metrics.length, index = i;
1036 if (i >= start) {
1037 hr = layout_add_effective_run(layout, run, start, i - start + 1, origin_x, s[0]);
1038 if (FAILED(hr))
1039 return hr;
1040 /* we don't need to update origin for next run as we're going to wrap */
1043 /* take a look at clusters we got for this line in reverse order to set
1044 trailing properties for current line */
1045 while (strlength) {
1046 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1048 if (!cluster->isNewline && !cluster->isWhitespace)
1049 break;
1051 if (cluster->isNewline) {
1052 metrics.trailingWhitespaceLength += cluster->length;
1053 metrics.newlineLength += cluster->length;
1056 if (cluster->isWhitespace)
1057 metrics.trailingWhitespaceLength += cluster->length;
1059 strlength -= cluster->length;
1060 index--;
1063 metrics.height = 0.0; /* FIXME */
1064 metrics.baseline = 0.0; /* FIXME */
1065 metrics.isTrimmed = width > layout->maxwidth;
1066 hr = layout_set_line_metrics(layout, &metrics, &line);
1067 if (FAILED(hr))
1068 return hr;
1070 width = layout->clustermetrics[i].width;
1071 memset(&metrics, 0, sizeof(metrics));
1072 origin_x = 0.0;
1073 start = i;
1075 else {
1076 metrics.length += layout->clustermetrics[i].length;
1077 width += layout->clustermetrics[i].width;
1080 s[0] = s[1];
1081 textpos += layout->clustermetrics[i].length;
1084 layout->line_count = line;
1085 layout->recompute &= ~RECOMPUTE_EFFECTIVE_RUNS;
1086 return hr;
1089 static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
1091 struct layout_range_bool const *range_bool = (struct layout_range_bool*)h;
1092 struct layout_range const *range = (struct layout_range*)h;
1094 switch (attr) {
1095 case LAYOUT_RANGE_ATTR_WEIGHT:
1096 return range->weight == value->u.weight;
1097 case LAYOUT_RANGE_ATTR_STYLE:
1098 return range->style == value->u.style;
1099 case LAYOUT_RANGE_ATTR_STRETCH:
1100 return range->stretch == value->u.stretch;
1101 case LAYOUT_RANGE_ATTR_FONTSIZE:
1102 return range->fontsize == value->u.fontsize;
1103 case LAYOUT_RANGE_ATTR_INLINE:
1104 return range->object == value->u.object;
1105 case LAYOUT_RANGE_ATTR_EFFECT:
1106 return range->effect == value->u.effect;
1107 case LAYOUT_RANGE_ATTR_UNDERLINE:
1108 return range->underline == value->u.underline;
1109 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
1110 return range_bool->value == value->u.strikethrough;
1111 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
1112 return range->pair_kerning == value->u.pair_kerning;
1113 case LAYOUT_RANGE_ATTR_FONTCOLL:
1114 return range->collection == value->u.collection;
1115 case LAYOUT_RANGE_ATTR_LOCALE:
1116 return strcmpW(range->locale, value->u.locale) == 0;
1117 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1118 return strcmpW(range->fontfamily, value->u.fontfamily) == 0;
1119 default:
1123 return FALSE;
1126 static inline BOOL is_same_layout_attributes(struct layout_range_header const *hleft, struct layout_range_header const *hright)
1128 switch (hleft->kind)
1130 case LAYOUT_RANGE_REGULAR:
1132 struct layout_range const *left = (struct layout_range const*)hleft;
1133 struct layout_range const *right = (struct layout_range const*)hright;
1134 return left->weight == right->weight &&
1135 left->style == right->style &&
1136 left->stretch == right->stretch &&
1137 left->fontsize == right->fontsize &&
1138 left->object == right->object &&
1139 left->effect == right->effect &&
1140 left->underline == right->underline &&
1141 left->pair_kerning == right->pair_kerning &&
1142 left->collection == right->collection &&
1143 !strcmpW(left->locale, right->locale) &&
1144 !strcmpW(left->fontfamily, right->fontfamily);
1146 case LAYOUT_RANGE_STRIKETHROUGH:
1148 struct layout_range_bool const *left = (struct layout_range_bool const*)hleft;
1149 struct layout_range_bool const *right = (struct layout_range_bool const*)hright;
1150 return left->value == right->value;
1152 default:
1153 FIXME("unknown range kind %d\n", hleft->kind);
1154 return FALSE;
1158 static inline BOOL is_same_text_range(const DWRITE_TEXT_RANGE *left, const DWRITE_TEXT_RANGE *right)
1160 return left->startPosition == right->startPosition && left->length == right->length;
1163 /* Allocates range and inits it with default values from text format. */
1164 static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout *layout, const DWRITE_TEXT_RANGE *r,
1165 enum layout_range_kind kind)
1167 struct layout_range_header *h;
1169 switch (kind)
1171 case LAYOUT_RANGE_REGULAR:
1173 struct layout_range *range;
1175 range = heap_alloc(sizeof(*range));
1176 if (!range) return NULL;
1178 range->weight = layout->format.weight;
1179 range->style = layout->format.style;
1180 range->stretch = layout->format.stretch;
1181 range->fontsize = layout->format.fontsize;
1182 range->object = NULL;
1183 range->effect = NULL;
1184 range->underline = FALSE;
1185 range->pair_kerning = FALSE;
1187 range->fontfamily = heap_strdupW(layout->format.family_name);
1188 if (!range->fontfamily) {
1189 heap_free(range);
1190 return NULL;
1193 range->collection = layout->format.collection;
1194 if (range->collection)
1195 IDWriteFontCollection_AddRef(range->collection);
1196 strcpyW(range->locale, layout->format.locale);
1198 h = &range->h;
1199 break;
1201 case LAYOUT_RANGE_STRIKETHROUGH:
1203 struct layout_range_bool *range;
1205 range = heap_alloc(sizeof(*range));
1206 if (!range) return NULL;
1208 range->value = FALSE;
1209 h = &range->h;
1210 break;
1212 default:
1213 FIXME("unknown range kind %d\n", kind);
1214 return NULL;
1217 h->kind = kind;
1218 h->range = *r;
1219 return h;
1222 static struct layout_range_header *alloc_layout_range_from(struct layout_range_header *h, const DWRITE_TEXT_RANGE *r)
1224 struct layout_range_header *ret;
1226 switch (h->kind)
1228 case LAYOUT_RANGE_REGULAR:
1230 struct layout_range *from = (struct layout_range*)h;
1232 struct layout_range *range = heap_alloc(sizeof(*range));
1233 if (!range) return NULL;
1235 *range = *from;
1236 range->fontfamily = heap_strdupW(from->fontfamily);
1237 if (!range->fontfamily) {
1238 heap_free(range);
1239 return NULL;
1242 /* update refcounts */
1243 if (range->object)
1244 IDWriteInlineObject_AddRef(range->object);
1245 if (range->effect)
1246 IUnknown_AddRef(range->effect);
1247 if (range->collection)
1248 IDWriteFontCollection_AddRef(range->collection);
1249 ret = &range->h;
1250 break;
1252 case LAYOUT_RANGE_STRIKETHROUGH:
1254 struct layout_range_bool *strike = heap_alloc(sizeof(*strike));
1255 if (!strike) return NULL;
1257 *strike = *(struct layout_range_bool*)h;
1258 ret = &strike->h;
1259 break;
1261 default:
1262 FIXME("unknown range kind %d\n", h->kind);
1263 return NULL;
1266 ret->range = *r;
1267 return ret;
1270 static void free_layout_range(struct layout_range_header *h)
1272 if (!h)
1273 return;
1275 if (h->kind == LAYOUT_RANGE_REGULAR) {
1276 struct layout_range *range = (struct layout_range*)h;
1278 if (range->object)
1279 IDWriteInlineObject_Release(range->object);
1280 if (range->effect)
1281 IUnknown_Release(range->effect);
1282 if (range->collection)
1283 IDWriteFontCollection_Release(range->collection);
1284 heap_free(range->fontfamily);
1287 heap_free(h);
1290 static void free_layout_ranges_list(struct dwrite_textlayout *layout)
1292 struct layout_range_header *cur, *cur2;
1294 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->ranges, struct layout_range_header, entry) {
1295 list_remove(&cur->entry);
1296 free_layout_range(cur);
1299 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->strike_ranges, struct layout_range_header, entry) {
1300 list_remove(&cur->entry);
1301 free_layout_range(cur);
1305 static struct layout_range_header *find_outer_range(struct list *ranges, const DWRITE_TEXT_RANGE *range)
1307 struct layout_range_header *cur;
1309 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
1311 if (cur->range.startPosition > range->startPosition)
1312 return NULL;
1314 if ((cur->range.startPosition + cur->range.length < range->startPosition + range->length) &&
1315 (range->startPosition < cur->range.startPosition + cur->range.length))
1316 return NULL;
1317 if (cur->range.startPosition + cur->range.length >= range->startPosition + range->length)
1318 return cur;
1321 return NULL;
1324 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos)
1326 struct layout_range *cur;
1328 LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, h.entry) {
1329 DWRITE_TEXT_RANGE *r = &cur->h.range;
1330 if (r->startPosition <= pos && pos < r->startPosition + r->length)
1331 return cur;
1334 return NULL;
1337 static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
1339 if (*dest == value) return FALSE;
1341 if (*dest)
1342 IUnknown_Release(*dest);
1343 *dest = value;
1344 if (*dest)
1345 IUnknown_AddRef(*dest);
1347 return TRUE;
1350 static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
1352 struct layout_range_bool *dest_bool = (struct layout_range_bool*)h;
1353 struct layout_range *dest = (struct layout_range*)h;
1355 BOOL changed = FALSE;
1357 switch (attr) {
1358 case LAYOUT_RANGE_ATTR_WEIGHT:
1359 changed = dest->weight != value->u.weight;
1360 dest->weight = value->u.weight;
1361 break;
1362 case LAYOUT_RANGE_ATTR_STYLE:
1363 changed = dest->style != value->u.style;
1364 dest->style = value->u.style;
1365 break;
1366 case LAYOUT_RANGE_ATTR_STRETCH:
1367 changed = dest->stretch != value->u.stretch;
1368 dest->stretch = value->u.stretch;
1369 break;
1370 case LAYOUT_RANGE_ATTR_FONTSIZE:
1371 changed = dest->fontsize != value->u.fontsize;
1372 dest->fontsize = value->u.fontsize;
1373 break;
1374 case LAYOUT_RANGE_ATTR_INLINE:
1375 changed = set_layout_range_iface_attr((IUnknown**)&dest->object, (IUnknown*)value->u.object);
1376 break;
1377 case LAYOUT_RANGE_ATTR_EFFECT:
1378 changed = set_layout_range_iface_attr((IUnknown**)&dest->effect, (IUnknown*)value->u.effect);
1379 break;
1380 case LAYOUT_RANGE_ATTR_UNDERLINE:
1381 changed = dest->underline != value->u.underline;
1382 dest->underline = value->u.underline;
1383 break;
1384 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
1385 changed = dest_bool->value != value->u.strikethrough;
1386 dest_bool->value = value->u.strikethrough;
1387 break;
1388 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
1389 changed = dest->pair_kerning != value->u.pair_kerning;
1390 dest->pair_kerning = value->u.pair_kerning;
1391 break;
1392 case LAYOUT_RANGE_ATTR_FONTCOLL:
1393 changed = set_layout_range_iface_attr((IUnknown**)&dest->collection, (IUnknown*)value->u.collection);
1394 break;
1395 case LAYOUT_RANGE_ATTR_LOCALE:
1396 changed = strcmpW(dest->locale, value->u.locale) != 0;
1397 if (changed)
1398 strcpyW(dest->locale, value->u.locale);
1399 break;
1400 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1401 changed = strcmpW(dest->fontfamily, value->u.fontfamily) != 0;
1402 if (changed) {
1403 heap_free(dest->fontfamily);
1404 dest->fontfamily = heap_strdupW(value->u.fontfamily);
1406 break;
1407 default:
1411 return changed;
1414 static inline BOOL is_in_layout_range(const DWRITE_TEXT_RANGE *outer, const DWRITE_TEXT_RANGE *inner)
1416 return (inner->startPosition >= outer->startPosition) &&
1417 (inner->startPosition + inner->length <= outer->startPosition + outer->length);
1420 static inline HRESULT return_range(const struct layout_range_header *h, DWRITE_TEXT_RANGE *r)
1422 if (r) *r = h->range;
1423 return S_OK;
1426 /* Set attribute value for given range, does all needed splitting/merging of existing ranges. */
1427 static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
1429 struct layout_range_header *cur, *right, *left, *outer;
1430 BOOL changed = FALSE;
1431 struct list *ranges;
1432 DWRITE_TEXT_RANGE r;
1434 /* select from ranges lists */
1435 switch (attr)
1437 case LAYOUT_RANGE_ATTR_WEIGHT:
1438 case LAYOUT_RANGE_ATTR_STYLE:
1439 case LAYOUT_RANGE_ATTR_STRETCH:
1440 case LAYOUT_RANGE_ATTR_FONTSIZE:
1441 case LAYOUT_RANGE_ATTR_EFFECT:
1442 case LAYOUT_RANGE_ATTR_INLINE:
1443 case LAYOUT_RANGE_ATTR_UNDERLINE:
1444 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
1445 case LAYOUT_RANGE_ATTR_FONTCOLL:
1446 case LAYOUT_RANGE_ATTR_LOCALE:
1447 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1448 ranges = &layout->ranges;
1449 break;
1450 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
1451 ranges = &layout->strike_ranges;
1452 break;
1453 default:
1454 FIXME("unknown attr kind %d\n", attr);
1455 return E_FAIL;
1458 /* If new range is completely within existing range, split existing range in two */
1459 if ((outer = find_outer_range(ranges, &value->range))) {
1461 /* no need to add same range */
1462 if (is_same_layout_attrvalue(outer, attr, value))
1463 return S_OK;
1465 /* for matching range bounds just replace data */
1466 if (is_same_text_range(&outer->range, &value->range)) {
1467 changed = set_layout_range_attrval(outer, attr, value);
1468 goto done;
1471 /* add new range to the left */
1472 if (value->range.startPosition == outer->range.startPosition) {
1473 left = alloc_layout_range_from(outer, &value->range);
1474 if (!left) return E_OUTOFMEMORY;
1476 changed = set_layout_range_attrval(left, attr, value);
1477 list_add_before(&outer->entry, &left->entry);
1478 outer->range.startPosition += value->range.length;
1479 outer->range.length -= value->range.length;
1480 goto done;
1483 /* add new range to the right */
1484 if (value->range.startPosition + value->range.length == outer->range.startPosition + outer->range.length) {
1485 right = alloc_layout_range_from(outer, &value->range);
1486 if (!right) return E_OUTOFMEMORY;
1488 changed = set_layout_range_attrval(right, attr, value);
1489 list_add_after(&outer->entry, &right->entry);
1490 outer->range.length -= value->range.length;
1491 goto done;
1494 r.startPosition = value->range.startPosition + value->range.length;
1495 r.length = outer->range.length + outer->range.startPosition - r.startPosition;
1497 /* right part */
1498 right = alloc_layout_range_from(outer, &r);
1499 /* new range in the middle */
1500 cur = alloc_layout_range_from(outer, &value->range);
1501 if (!right || !cur) {
1502 free_layout_range(right);
1503 free_layout_range(cur);
1504 return E_OUTOFMEMORY;
1507 /* reuse container range as a left part */
1508 outer->range.length = value->range.startPosition - outer->range.startPosition;
1510 /* new part */
1511 set_layout_range_attrval(cur, attr, value);
1513 list_add_after(&outer->entry, &cur->entry);
1514 list_add_after(&cur->entry, &right->entry);
1516 return S_OK;
1519 /* Now it's only possible that given range contains some existing ranges, fully or partially.
1520 Update all of them. */
1521 left = get_layout_range_header_by_pos(ranges, value->range.startPosition);
1522 if (left->range.startPosition == value->range.startPosition)
1523 changed = set_layout_range_attrval(left, attr, value);
1524 else /* need to split */ {
1525 r.startPosition = value->range.startPosition;
1526 r.length = left->range.length - value->range.startPosition + left->range.startPosition;
1527 left->range.length -= r.length;
1528 cur = alloc_layout_range_from(left, &r);
1529 changed = set_layout_range_attrval(cur, attr, value);
1530 list_add_after(&left->entry, &cur->entry);
1532 cur = LIST_ENTRY(list_next(ranges, &left->entry), struct layout_range_header, entry);
1534 /* for all existing ranges covered by new one update value */
1535 while (cur && is_in_layout_range(&value->range, &cur->range)) {
1536 changed = set_layout_range_attrval(cur, attr, value);
1537 cur = LIST_ENTRY(list_next(ranges, &cur->entry), struct layout_range_header, entry);
1540 /* it's possible rightmost range intersects */
1541 if (cur && (cur->range.startPosition < value->range.startPosition + value->range.length)) {
1542 r.startPosition = cur->range.startPosition;
1543 r.length = value->range.startPosition + value->range.length - cur->range.startPosition;
1544 left = alloc_layout_range_from(cur, &r);
1545 changed = set_layout_range_attrval(left, attr, value);
1546 cur->range.startPosition += left->range.length;
1547 cur->range.length -= left->range.length;
1548 list_add_before(&cur->entry, &left->entry);
1551 done:
1552 if (changed) {
1553 struct list *next, *i;
1555 layout->recompute = RECOMPUTE_EVERYTHING;
1556 i = list_head(ranges);
1557 while ((next = list_next(ranges, i))) {
1558 struct layout_range_header *next_range = LIST_ENTRY(next, struct layout_range_header, entry);
1560 cur = LIST_ENTRY(i, struct layout_range_header, entry);
1561 if (is_same_layout_attributes(cur, next_range)) {
1562 /* remove similar range */
1563 cur->range.length += next_range->range.length;
1564 list_remove(next);
1565 free_layout_range(next_range);
1567 else
1568 i = list_next(ranges, i);
1572 return S_OK;
1575 static inline const WCHAR *get_string_attribute_ptr(struct layout_range *range, enum layout_range_attr_kind kind)
1577 const WCHAR *str;
1579 switch (kind) {
1580 case LAYOUT_RANGE_ATTR_LOCALE:
1581 str = range->locale;
1582 break;
1583 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1584 str = range->fontfamily;
1585 break;
1586 default:
1587 str = NULL;
1590 return str;
1593 static HRESULT get_string_attribute_length(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
1594 UINT32 *length, DWRITE_TEXT_RANGE *r)
1596 struct layout_range *range;
1597 const WCHAR *str;
1599 range = get_layout_range_by_pos(layout, position);
1600 if (!range) {
1601 *length = 0;
1602 return S_OK;
1605 str = get_string_attribute_ptr(range, kind);
1606 *length = strlenW(str);
1607 return return_range(&range->h, r);
1610 static HRESULT get_string_attribute_value(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
1611 WCHAR *ret, UINT32 length, DWRITE_TEXT_RANGE *r)
1613 struct layout_range *range;
1614 const WCHAR *str;
1616 if (length == 0)
1617 return E_INVALIDARG;
1619 ret[0] = 0;
1620 range = get_layout_range_by_pos(layout, position);
1621 if (!range)
1622 return E_INVALIDARG;
1624 str = get_string_attribute_ptr(range, kind);
1625 if (length < strlenW(str) + 1)
1626 return E_NOT_SUFFICIENT_BUFFER;
1628 strcpyW(ret, str);
1629 return return_range(&range->h, r);
1632 static HRESULT WINAPI dwritetextlayout_QueryInterface(IDWriteTextLayout2 *iface, REFIID riid, void **obj)
1634 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1636 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1638 *obj = NULL;
1640 if (IsEqualIID(riid, &IID_IDWriteTextLayout2) ||
1641 IsEqualIID(riid, &IID_IDWriteTextLayout1) ||
1642 IsEqualIID(riid, &IID_IDWriteTextLayout) ||
1643 IsEqualIID(riid, &IID_IUnknown))
1645 *obj = iface;
1647 else if (IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
1648 IsEqualIID(riid, &IID_IDWriteTextFormat))
1649 *obj = &This->IDWriteTextFormat1_iface;
1651 if (*obj) {
1652 IDWriteTextLayout2_AddRef(iface);
1653 return S_OK;
1656 return E_NOINTERFACE;
1659 static ULONG WINAPI dwritetextlayout_AddRef(IDWriteTextLayout2 *iface)
1661 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1662 ULONG ref = InterlockedIncrement(&This->ref);
1663 TRACE("(%p)->(%d)\n", This, ref);
1664 return ref;
1667 static ULONG WINAPI dwritetextlayout_Release(IDWriteTextLayout2 *iface)
1669 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1670 ULONG ref = InterlockedDecrement(&This->ref);
1672 TRACE("(%p)->(%d)\n", This, ref);
1674 if (!ref) {
1675 free_layout_ranges_list(This);
1676 free_layout_eruns(This);
1677 free_layout_runs(This);
1678 release_format_data(&This->format);
1679 heap_free(This->nominal_breakpoints);
1680 heap_free(This->actual_breakpoints);
1681 heap_free(This->clustermetrics);
1682 heap_free(This->clusters);
1683 heap_free(This->lines);
1684 heap_free(This->str);
1685 heap_free(This);
1688 return ref;
1691 static HRESULT WINAPI dwritetextlayout_SetTextAlignment(IDWriteTextLayout2 *iface, DWRITE_TEXT_ALIGNMENT alignment)
1693 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1694 TRACE("(%p)->(%d)\n", This, alignment);
1695 return IDWriteTextFormat1_SetTextAlignment(&This->IDWriteTextFormat1_iface, alignment);
1698 static HRESULT WINAPI dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout2 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
1700 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1701 TRACE("(%p)->(%d)\n", This, alignment);
1702 return IDWriteTextFormat1_SetParagraphAlignment(&This->IDWriteTextFormat1_iface, alignment);
1705 static HRESULT WINAPI dwritetextlayout_SetWordWrapping(IDWriteTextLayout2 *iface, DWRITE_WORD_WRAPPING wrapping)
1707 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1708 TRACE("(%p)->(%d)\n", This, wrapping);
1709 return IDWriteTextFormat1_SetWordWrapping(&This->IDWriteTextFormat1_iface, wrapping);
1712 static HRESULT WINAPI dwritetextlayout_SetReadingDirection(IDWriteTextLayout2 *iface, DWRITE_READING_DIRECTION direction)
1714 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1715 TRACE("(%p)->(%d)\n", This, direction);
1716 return IDWriteTextFormat1_SetReadingDirection(&This->IDWriteTextFormat1_iface, direction);
1719 static HRESULT WINAPI dwritetextlayout_SetFlowDirection(IDWriteTextLayout2 *iface, DWRITE_FLOW_DIRECTION direction)
1721 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1722 TRACE("(%p)->(%d)\n", This, direction);
1723 return IDWriteTextFormat1_SetFlowDirection(&This->IDWriteTextFormat1_iface, direction);
1726 static HRESULT WINAPI dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout2 *iface, FLOAT tabstop)
1728 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1729 TRACE("(%p)->(%.2f)\n", This, tabstop);
1730 return IDWriteTextFormat1_SetIncrementalTabStop(&This->IDWriteTextFormat1_iface, tabstop);
1733 static HRESULT WINAPI dwritetextlayout_SetTrimming(IDWriteTextLayout2 *iface, DWRITE_TRIMMING const *trimming,
1734 IDWriteInlineObject *trimming_sign)
1736 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1737 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
1738 return IDWriteTextFormat1_SetTrimming(&This->IDWriteTextFormat1_iface, trimming, trimming_sign);
1741 static HRESULT WINAPI dwritetextlayout_SetLineSpacing(IDWriteTextLayout2 *iface, DWRITE_LINE_SPACING_METHOD spacing,
1742 FLOAT line_spacing, FLOAT baseline)
1744 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1745 TRACE("(%p)->(%d %.2f %.2f)\n", This, spacing, line_spacing, baseline);
1746 return IDWriteTextFormat1_SetLineSpacing(&This->IDWriteTextFormat1_iface, spacing, line_spacing, baseline);
1749 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextlayout_GetTextAlignment(IDWriteTextLayout2 *iface)
1751 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1752 TRACE("(%p)\n", This);
1753 return IDWriteTextFormat1_GetTextAlignment(&This->IDWriteTextFormat1_iface);
1756 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout2 *iface)
1758 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1759 TRACE("(%p)\n", This);
1760 return IDWriteTextFormat1_GetParagraphAlignment(&This->IDWriteTextFormat1_iface);
1763 static DWRITE_WORD_WRAPPING WINAPI dwritetextlayout_GetWordWrapping(IDWriteTextLayout2 *iface)
1765 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1766 TRACE("(%p)\n", This);
1767 return IDWriteTextFormat1_GetWordWrapping(&This->IDWriteTextFormat1_iface);
1770 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_GetReadingDirection(IDWriteTextLayout2 *iface)
1772 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1773 TRACE("(%p)\n", This);
1774 return IDWriteTextFormat1_GetReadingDirection(&This->IDWriteTextFormat1_iface);
1777 static DWRITE_FLOW_DIRECTION WINAPI dwritetextlayout_GetFlowDirection(IDWriteTextLayout2 *iface)
1779 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1780 TRACE("(%p)\n", This);
1781 return IDWriteTextFormat1_GetFlowDirection(&This->IDWriteTextFormat1_iface);
1784 static FLOAT WINAPI dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout2 *iface)
1786 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1787 TRACE("(%p)\n", This);
1788 return IDWriteTextFormat1_GetIncrementalTabStop(&This->IDWriteTextFormat1_iface);
1791 static HRESULT WINAPI dwritetextlayout_GetTrimming(IDWriteTextLayout2 *iface, DWRITE_TRIMMING *options,
1792 IDWriteInlineObject **trimming_sign)
1794 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1795 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
1796 return IDWriteTextFormat1_GetTrimming(&This->IDWriteTextFormat1_iface, options, trimming_sign);
1799 static HRESULT WINAPI dwritetextlayout_GetLineSpacing(IDWriteTextLayout2 *iface, DWRITE_LINE_SPACING_METHOD *method,
1800 FLOAT *spacing, FLOAT *baseline)
1802 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1803 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
1804 return IDWriteTextFormat1_GetLineSpacing(&This->IDWriteTextFormat1_iface, method, spacing, baseline);
1807 static HRESULT WINAPI dwritetextlayout_GetFontCollection(IDWriteTextLayout2 *iface, IDWriteFontCollection **collection)
1809 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1810 TRACE("(%p)->(%p)\n", This, collection);
1811 return IDWriteTextFormat1_GetFontCollection(&This->IDWriteTextFormat1_iface, collection);
1814 static UINT32 WINAPI dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout2 *iface)
1816 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1817 TRACE("(%p)\n", This);
1818 return IDWriteTextFormat1_GetFontFamilyNameLength(&This->IDWriteTextFormat1_iface);
1821 static HRESULT WINAPI dwritetextlayout_GetFontFamilyName(IDWriteTextLayout2 *iface, WCHAR *name, UINT32 size)
1823 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1824 TRACE("(%p)->(%p %u)\n", This, name, size);
1825 return IDWriteTextFormat1_GetFontFamilyName(&This->IDWriteTextFormat1_iface, name, size);
1828 static DWRITE_FONT_WEIGHT WINAPI dwritetextlayout_GetFontWeight(IDWriteTextLayout2 *iface)
1830 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1831 TRACE("(%p)\n", This);
1832 return IDWriteTextFormat1_GetFontWeight(&This->IDWriteTextFormat1_iface);
1835 static DWRITE_FONT_STYLE WINAPI dwritetextlayout_GetFontStyle(IDWriteTextLayout2 *iface)
1837 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1838 TRACE("(%p)\n", This);
1839 return IDWriteTextFormat1_GetFontStyle(&This->IDWriteTextFormat1_iface);
1842 static DWRITE_FONT_STRETCH WINAPI dwritetextlayout_GetFontStretch(IDWriteTextLayout2 *iface)
1844 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1845 TRACE("(%p)\n", This);
1846 return IDWriteTextFormat1_GetFontStretch(&This->IDWriteTextFormat1_iface);
1849 static FLOAT WINAPI dwritetextlayout_GetFontSize(IDWriteTextLayout2 *iface)
1851 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1852 TRACE("(%p)\n", This);
1853 return IDWriteTextFormat1_GetFontSize(&This->IDWriteTextFormat1_iface);
1856 static UINT32 WINAPI dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout2 *iface)
1858 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1859 TRACE("(%p)\n", This);
1860 return IDWriteTextFormat1_GetLocaleNameLength(&This->IDWriteTextFormat1_iface);
1863 static HRESULT WINAPI dwritetextlayout_GetLocaleName(IDWriteTextLayout2 *iface, WCHAR *name, UINT32 size)
1865 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1866 TRACE("(%p)->(%p %u)\n", This, name, size);
1867 return IDWriteTextFormat1_GetLocaleName(&This->IDWriteTextFormat1_iface, name, size);
1870 static HRESULT WINAPI dwritetextlayout_SetMaxWidth(IDWriteTextLayout2 *iface, FLOAT maxWidth)
1872 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1873 TRACE("(%p)->(%.1f)\n", This, maxWidth);
1875 if (maxWidth < 0.0)
1876 return E_INVALIDARG;
1878 This->maxwidth = maxWidth;
1879 return S_OK;
1882 static HRESULT WINAPI dwritetextlayout_SetMaxHeight(IDWriteTextLayout2 *iface, FLOAT maxHeight)
1884 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1885 TRACE("(%p)->(%.1f)\n", This, maxHeight);
1887 if (maxHeight < 0.0)
1888 return E_INVALIDARG;
1890 This->maxheight = maxHeight;
1891 return S_OK;
1894 static HRESULT WINAPI dwritetextlayout_SetFontCollection(IDWriteTextLayout2 *iface, IDWriteFontCollection* collection, DWRITE_TEXT_RANGE range)
1896 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1897 struct layout_range_attr_value value;
1899 TRACE("(%p)->(%p %s)\n", This, collection, debugstr_range(&range));
1901 value.range = range;
1902 value.u.collection = collection;
1903 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTCOLL, &value);
1906 static HRESULT WINAPI dwritetextlayout_SetFontFamilyName(IDWriteTextLayout2 *iface, WCHAR const *name, DWRITE_TEXT_RANGE range)
1908 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1909 struct layout_range_attr_value value;
1911 TRACE("(%p)->(%s %s)\n", This, debugstr_w(name), debugstr_range(&range));
1913 if (!name)
1914 return E_INVALIDARG;
1916 value.range = range;
1917 value.u.fontfamily = name;
1918 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTFAMILY, &value);
1921 static HRESULT WINAPI dwritetextlayout_SetFontWeight(IDWriteTextLayout2 *iface, DWRITE_FONT_WEIGHT weight, DWRITE_TEXT_RANGE range)
1923 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1924 struct layout_range_attr_value value;
1926 TRACE("(%p)->(%d %s)\n", This, weight, debugstr_range(&range));
1928 value.range = range;
1929 value.u.weight = weight;
1930 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_WEIGHT, &value);
1933 static HRESULT WINAPI dwritetextlayout_SetFontStyle(IDWriteTextLayout2 *iface, DWRITE_FONT_STYLE style, DWRITE_TEXT_RANGE range)
1935 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1936 struct layout_range_attr_value value;
1938 TRACE("(%p)->(%d %s)\n", This, style, debugstr_range(&range));
1940 if ((UINT32)style > DWRITE_FONT_STYLE_ITALIC)
1941 return E_INVALIDARG;
1943 value.range = range;
1944 value.u.style = style;
1945 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STYLE, &value);
1948 static HRESULT WINAPI dwritetextlayout_SetFontStretch(IDWriteTextLayout2 *iface, DWRITE_FONT_STRETCH stretch, DWRITE_TEXT_RANGE range)
1950 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1951 struct layout_range_attr_value value;
1953 TRACE("(%p)->(%d %s)\n", This, stretch, debugstr_range(&range));
1955 if (stretch == DWRITE_FONT_STRETCH_UNDEFINED || (UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
1956 return E_INVALIDARG;
1958 value.range = range;
1959 value.u.stretch = stretch;
1960 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRETCH, &value);
1963 static HRESULT WINAPI dwritetextlayout_SetFontSize(IDWriteTextLayout2 *iface, FLOAT size, DWRITE_TEXT_RANGE range)
1965 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1966 struct layout_range_attr_value value;
1968 TRACE("(%p)->(%.2f %s)\n", This, size, debugstr_range(&range));
1970 if (size <= 0.0)
1971 return E_INVALIDARG;
1973 value.range = range;
1974 value.u.fontsize = size;
1975 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTSIZE, &value);
1978 static HRESULT WINAPI dwritetextlayout_SetUnderline(IDWriteTextLayout2 *iface, BOOL underline, DWRITE_TEXT_RANGE range)
1980 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1981 struct layout_range_attr_value value;
1983 TRACE("(%p)->(%d %s)\n", This, underline, debugstr_range(&range));
1985 value.range = range;
1986 value.u.underline = underline;
1987 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_UNDERLINE, &value);
1990 static HRESULT WINAPI dwritetextlayout_SetStrikethrough(IDWriteTextLayout2 *iface, BOOL strikethrough, DWRITE_TEXT_RANGE range)
1992 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1993 struct layout_range_attr_value value;
1995 TRACE("(%p)->(%d %s)\n", This, strikethrough, debugstr_range(&range));
1997 value.range = range;
1998 value.u.strikethrough = strikethrough;
1999 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRIKETHROUGH, &value);
2002 static HRESULT WINAPI dwritetextlayout_SetDrawingEffect(IDWriteTextLayout2 *iface, IUnknown* effect, DWRITE_TEXT_RANGE range)
2004 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2005 struct layout_range_attr_value value;
2007 TRACE("(%p)->(%p %s)\n", This, effect, debugstr_range(&range));
2009 value.range = range;
2010 value.u.effect = effect;
2011 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_EFFECT, &value);
2014 static HRESULT WINAPI dwritetextlayout_SetInlineObject(IDWriteTextLayout2 *iface, IDWriteInlineObject *object, DWRITE_TEXT_RANGE range)
2016 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2017 struct layout_range_attr_value value;
2019 TRACE("(%p)->(%p %s)\n", This, object, debugstr_range(&range));
2021 value.range = range;
2022 value.u.object = object;
2023 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_INLINE, &value);
2026 static HRESULT WINAPI dwritetextlayout_SetTypography(IDWriteTextLayout2 *iface, IDWriteTypography* typography, DWRITE_TEXT_RANGE range)
2028 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2029 FIXME("(%p)->(%p %s): stub\n", This, typography, debugstr_range(&range));
2030 return E_NOTIMPL;
2033 static HRESULT WINAPI dwritetextlayout_SetLocaleName(IDWriteTextLayout2 *iface, WCHAR const* locale, DWRITE_TEXT_RANGE range)
2035 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2036 struct layout_range_attr_value value;
2038 TRACE("(%p)->(%s %s)\n", This, debugstr_w(locale), debugstr_range(&range));
2040 if (!locale || strlenW(locale) > LOCALE_NAME_MAX_LENGTH-1)
2041 return E_INVALIDARG;
2043 value.range = range;
2044 value.u.locale = locale;
2045 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_LOCALE, &value);
2048 static FLOAT WINAPI dwritetextlayout_GetMaxWidth(IDWriteTextLayout2 *iface)
2050 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2051 TRACE("(%p)\n", This);
2052 return This->maxwidth;
2055 static FLOAT WINAPI dwritetextlayout_GetMaxHeight(IDWriteTextLayout2 *iface)
2057 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2058 TRACE("(%p)\n", This);
2059 return This->maxheight;
2062 static HRESULT WINAPI dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout2 *iface, UINT32 position,
2063 IDWriteFontCollection** collection, DWRITE_TEXT_RANGE *r)
2065 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2066 struct layout_range *range;
2068 TRACE("(%p)->(%u %p %p)\n", This, position, collection, r);
2070 if (position >= This->len)
2071 return S_OK;
2073 range = get_layout_range_by_pos(This, position);
2074 *collection = range->collection;
2075 if (*collection)
2076 IDWriteFontCollection_AddRef(*collection);
2078 return return_range(&range->h, r);
2081 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout2 *iface,
2082 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
2084 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2085 TRACE("(%p)->(%d %p %p)\n", This, position, length, r);
2086 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, length, r);
2089 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout2 *iface,
2090 UINT32 position, WCHAR *name, UINT32 length, DWRITE_TEXT_RANGE *r)
2092 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2093 TRACE("(%p)->(%u %p %u %p)\n", This, position, name, length, r);
2094 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, name, length, r);
2097 static HRESULT WINAPI dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout2 *iface,
2098 UINT32 position, DWRITE_FONT_WEIGHT *weight, DWRITE_TEXT_RANGE *r)
2100 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2101 struct layout_range *range;
2103 TRACE("(%p)->(%u %p %p)\n", This, position, weight, r);
2105 if (position >= This->len)
2106 return S_OK;
2108 range = get_layout_range_by_pos(This, position);
2109 *weight = range->weight;
2111 return return_range(&range->h, r);
2114 static HRESULT WINAPI dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout2 *iface,
2115 UINT32 position, DWRITE_FONT_STYLE *style, DWRITE_TEXT_RANGE *r)
2117 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2118 struct layout_range *range;
2120 TRACE("(%p)->(%u %p %p)\n", This, position, style, r);
2122 range = get_layout_range_by_pos(This, position);
2123 *style = range->style;
2124 return return_range(&range->h, r);
2127 static HRESULT WINAPI dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout2 *iface,
2128 UINT32 position, DWRITE_FONT_STRETCH *stretch, DWRITE_TEXT_RANGE *r)
2130 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2131 struct layout_range *range;
2133 TRACE("(%p)->(%u %p %p)\n", This, position, stretch, r);
2135 range = get_layout_range_by_pos(This, position);
2136 *stretch = range->stretch;
2137 return return_range(&range->h, r);
2140 static HRESULT WINAPI dwritetextlayout_layout_GetFontSize(IDWriteTextLayout2 *iface,
2141 UINT32 position, FLOAT *size, DWRITE_TEXT_RANGE *r)
2143 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2144 struct layout_range *range;
2146 TRACE("(%p)->(%u %p %p)\n", This, position, size, r);
2148 range = get_layout_range_by_pos(This, position);
2149 *size = range->fontsize;
2150 return return_range(&range->h, r);
2153 static HRESULT WINAPI dwritetextlayout_GetUnderline(IDWriteTextLayout2 *iface,
2154 UINT32 position, BOOL *underline, DWRITE_TEXT_RANGE *r)
2156 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2157 struct layout_range *range;
2159 TRACE("(%p)->(%u %p %p)\n", This, position, underline, r);
2161 if (position >= This->len)
2162 return S_OK;
2164 range = get_layout_range_by_pos(This, position);
2165 *underline = range->underline;
2167 return return_range(&range->h, r);
2170 static HRESULT WINAPI dwritetextlayout_GetStrikethrough(IDWriteTextLayout2 *iface,
2171 UINT32 position, BOOL *strikethrough, DWRITE_TEXT_RANGE *r)
2173 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2174 struct layout_range_bool *range;
2176 TRACE("(%p)->(%u %p %p)\n", This, position, strikethrough, r);
2178 if (position >= This->len)
2179 return S_OK;
2181 range = (struct layout_range_bool*)get_layout_range_header_by_pos(&This->strike_ranges, position);
2182 *strikethrough = range->value;
2184 return return_range(&range->h, r);
2187 static HRESULT WINAPI dwritetextlayout_GetDrawingEffect(IDWriteTextLayout2 *iface,
2188 UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r)
2190 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2191 struct layout_range *range;
2193 TRACE("(%p)->(%u %p %p)\n", This, position, effect, r);
2195 if (position >= This->len)
2196 return S_OK;
2198 range = get_layout_range_by_pos(This, position);
2199 *effect = range->effect;
2200 if (*effect)
2201 IUnknown_AddRef(*effect);
2203 return return_range(&range->h, r);
2206 static HRESULT WINAPI dwritetextlayout_GetInlineObject(IDWriteTextLayout2 *iface,
2207 UINT32 position, IDWriteInlineObject **object, DWRITE_TEXT_RANGE *r)
2209 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2210 struct layout_range *range;
2212 TRACE("(%p)->(%u %p %p)\n", This, position, object, r);
2214 if (position >= This->len)
2215 return S_OK;
2217 range = get_layout_range_by_pos(This, position);
2218 *object = range->object;
2219 if (*object)
2220 IDWriteInlineObject_AddRef(*object);
2222 return return_range(&range->h, r);
2225 static HRESULT WINAPI dwritetextlayout_GetTypography(IDWriteTextLayout2 *iface,
2226 UINT32 position, IDWriteTypography** typography, DWRITE_TEXT_RANGE *range)
2228 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2229 FIXME("(%p)->(%u %p %p): stub\n", This, position, typography, range);
2230 return E_NOTIMPL;
2233 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout2 *iface,
2234 UINT32 position, UINT32* length, DWRITE_TEXT_RANGE *r)
2236 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2237 TRACE("(%p)->(%u %p %p)\n", This, position, length, r);
2238 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_LOCALE, position, length, r);
2241 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout2 *iface,
2242 UINT32 position, WCHAR* locale, UINT32 length, DWRITE_TEXT_RANGE *r)
2244 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2245 TRACE("(%p)->(%u %p %u %p)\n", This, position, locale, length, r);
2246 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_LOCALE, position, locale, length, r);
2249 static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface,
2250 void *context, IDWriteTextRenderer* renderer, FLOAT origin_x, FLOAT origin_y)
2252 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2253 struct layout_effective_inline *inlineobject;
2254 struct layout_effective_run *run;
2255 struct layout_strikethrough *s;
2256 HRESULT hr;
2258 TRACE("(%p)->(%p %p %.2f %.2f)\n", This, context, renderer, origin_x, origin_y);
2260 hr = layout_compute_effective_runs(This);
2261 if (FAILED(hr))
2262 return hr;
2264 /* 1. Regular runs */
2265 LIST_FOR_EACH_ENTRY(run, &This->eruns, struct layout_effective_run, entry) {
2266 const struct regular_layout_run *regular = &run->run->u.regular;
2267 UINT32 start_glyph = regular->clustermap[run->start];
2268 DWRITE_GLYPH_RUN_DESCRIPTION descr;
2269 DWRITE_GLYPH_RUN glyph_run;
2271 /* Everything but cluster map will be reused from nominal run, as we only need
2272 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
2273 it can't be reused because it has to start with 0 index for each reported run. */
2274 glyph_run = regular->run;
2275 glyph_run.glyphCount = run->glyphcount;
2277 /* fixup glyph data arrays */
2278 glyph_run.glyphIndices += start_glyph;
2279 glyph_run.glyphAdvances += start_glyph;
2280 glyph_run.glyphOffsets += start_glyph;
2282 /* description */
2283 descr = regular->descr;
2284 descr.stringLength = run->length;
2285 descr.string += run->start;
2286 descr.clusterMap = run->clustermap;
2287 descr.textPosition += run->start;
2289 /* return value is ignored */
2290 IDWriteTextRenderer_DrawGlyphRun(renderer,
2291 context,
2292 run->origin_x + origin_x,
2293 run->origin_y + origin_y,
2294 DWRITE_MEASURING_MODE_NATURAL,
2295 &glyph_run,
2296 &descr,
2297 run->run->effect);
2300 /* 2. Inline objects */
2301 LIST_FOR_EACH_ENTRY(inlineobject, &This->inlineobjects, struct layout_effective_inline, entry) {
2302 IDWriteTextRenderer_DrawInlineObject(renderer,
2303 context,
2304 inlineobject->origin_x,
2305 inlineobject->origin_y,
2306 inlineobject->object,
2307 inlineobject->is_sideways,
2308 inlineobject->is_rtl,
2309 run->run->effect);
2312 /* TODO: 3. Underlines */
2314 /* 4. Strikethrough */
2315 LIST_FOR_EACH_ENTRY(s, &This->strikethrough, struct layout_strikethrough, entry) {
2316 IDWriteTextRenderer_DrawStrikethrough(renderer,
2317 context,
2318 s->run->origin_x,
2319 s->run->origin_y,
2320 &s->s,
2321 s->run->run->effect);
2324 return S_OK;
2327 static HRESULT WINAPI dwritetextlayout_GetLineMetrics(IDWriteTextLayout2 *iface,
2328 DWRITE_LINE_METRICS *metrics, UINT32 max_count, UINT32 *count)
2330 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2331 HRESULT hr;
2333 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
2335 hr = layout_compute_effective_runs(This);
2336 if (FAILED(hr))
2337 return hr;
2339 if (metrics)
2340 memcpy(metrics, This->lines, sizeof(DWRITE_LINE_METRICS)*min(max_count, This->line_count));
2342 *count = This->line_count;
2343 return max_count >= This->line_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
2346 static HRESULT WINAPI dwritetextlayout_GetMetrics(IDWriteTextLayout2 *iface, DWRITE_TEXT_METRICS *metrics)
2348 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2349 DWRITE_TEXT_METRICS1 metrics1;
2350 HRESULT hr;
2352 TRACE("(%p)->(%p)\n", This, metrics);
2354 hr = IDWriteTextLayout2_GetMetrics(iface, &metrics1);
2355 if (hr == S_OK)
2356 memcpy(metrics, &metrics1, sizeof(*metrics));
2358 return hr;
2361 static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout2 *iface, DWRITE_OVERHANG_METRICS *overhangs)
2363 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2364 FIXME("(%p)->(%p): stub\n", This, overhangs);
2365 return E_NOTIMPL;
2368 static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout2 *iface,
2369 DWRITE_CLUSTER_METRICS *metrics, UINT32 max_count, UINT32 *count)
2371 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2372 HRESULT hr;
2374 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
2376 hr = layout_compute(This);
2377 if (FAILED(hr))
2378 return hr;
2380 if (metrics)
2381 memcpy(metrics, This->clustermetrics, sizeof(DWRITE_CLUSTER_METRICS)*min(max_count, This->cluster_count));
2383 *count = This->cluster_count;
2384 return max_count >= This->cluster_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
2387 /* Only to be used with DetermineMinWidth() to find the longest cluster sequence that we don't want to try
2388 too hard to break. */
2389 static inline BOOL is_terminal_cluster(struct dwrite_textlayout *layout, UINT32 index)
2391 if (layout->clustermetrics[index].isWhitespace || layout->clustermetrics[index].isNewline ||
2392 (index == layout->cluster_count - 1))
2393 return TRUE;
2394 /* check next one */
2395 return (index < layout->cluster_count - 1) && layout->clustermetrics[index+1].isWhitespace;
2398 static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout2 *iface, FLOAT* min_width)
2400 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2401 FLOAT width;
2402 HRESULT hr;
2403 UINT32 i;
2405 TRACE("(%p)->(%p)\n", This, min_width);
2407 if (!min_width)
2408 return E_INVALIDARG;
2410 if (!(This->recompute & RECOMPUTE_MINIMAL_WIDTH))
2411 goto width_done;
2413 *min_width = 0.0;
2414 hr = layout_compute(This);
2415 if (FAILED(hr))
2416 return hr;
2418 for (i = 0; i < This->cluster_count;) {
2419 if (is_terminal_cluster(This, i)) {
2420 width = This->clustermetrics[i].width;
2421 i++;
2423 else {
2424 width = 0.0;
2425 while (!is_terminal_cluster(This, i)) {
2426 width += This->clustermetrics[i].width;
2427 i++;
2429 /* count last one too */
2430 width += This->clustermetrics[i].width;
2433 if (width > This->minwidth)
2434 This->minwidth = width;
2436 This->recompute &= ~RECOMPUTE_MINIMAL_WIDTH;
2438 width_done:
2439 *min_width = This->minwidth;
2440 return S_OK;
2443 static HRESULT WINAPI dwritetextlayout_HitTestPoint(IDWriteTextLayout2 *iface,
2444 FLOAT pointX, FLOAT pointY, BOOL* is_trailinghit, BOOL* is_inside, DWRITE_HIT_TEST_METRICS *metrics)
2446 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2447 FIXME("(%p)->(%f %f %p %p %p): stub\n", This, pointX, pointY, is_trailinghit, is_inside, metrics);
2448 return E_NOTIMPL;
2451 static HRESULT WINAPI dwritetextlayout_HitTestTextPosition(IDWriteTextLayout2 *iface,
2452 UINT32 textPosition, BOOL is_trailinghit, FLOAT* pointX, FLOAT* pointY, DWRITE_HIT_TEST_METRICS *metrics)
2454 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2455 FIXME("(%p)->(%u %d %p %p %p): stub\n", This, textPosition, is_trailinghit, pointX, pointY, metrics);
2456 return E_NOTIMPL;
2459 static HRESULT WINAPI dwritetextlayout_HitTestTextRange(IDWriteTextLayout2 *iface,
2460 UINT32 textPosition, UINT32 textLength, FLOAT originX, FLOAT originY,
2461 DWRITE_HIT_TEST_METRICS *metrics, UINT32 max_metricscount, UINT32* actual_metricscount)
2463 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2464 FIXME("(%p)->(%u %u %f %f %p %u %p): stub\n", This, textPosition, textLength, originX, originY, metrics,
2465 max_metricscount, actual_metricscount);
2466 return E_NOTIMPL;
2469 static HRESULT WINAPI dwritetextlayout1_SetPairKerning(IDWriteTextLayout2 *iface, BOOL is_pairkerning_enabled,
2470 DWRITE_TEXT_RANGE range)
2472 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2473 struct layout_range_attr_value value;
2475 TRACE("(%p)->(%d %s)\n", This, is_pairkerning_enabled, debugstr_range(&range));
2477 value.range = range;
2478 value.u.pair_kerning = !!is_pairkerning_enabled;
2479 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_PAIR_KERNING, &value);
2482 static HRESULT WINAPI dwritetextlayout1_GetPairKerning(IDWriteTextLayout2 *iface, UINT32 position, BOOL *is_pairkerning_enabled,
2483 DWRITE_TEXT_RANGE *r)
2485 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2486 struct layout_range *range;
2488 TRACE("(%p)->(%u %p %p)\n", This, position, is_pairkerning_enabled, r);
2490 if (position >= This->len)
2491 return S_OK;
2493 range = get_layout_range_by_pos(This, position);
2494 *is_pairkerning_enabled = range->pair_kerning;
2496 return return_range(&range->h, r);
2499 static HRESULT WINAPI dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout2 *iface, FLOAT leading_spacing, FLOAT trailing_spacing,
2500 FLOAT minimum_advance_width, DWRITE_TEXT_RANGE range)
2502 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2503 FIXME("(%p)->(%f %f %f %s): stub\n", This, leading_spacing, trailing_spacing, minimum_advance_width, debugstr_range(&range));
2504 return E_NOTIMPL;
2507 static HRESULT WINAPI dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout2 *iface, UINT32 position, FLOAT* leading_spacing,
2508 FLOAT* trailing_spacing, FLOAT* minimum_advance_width, DWRITE_TEXT_RANGE *range)
2510 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2511 FIXME("(%p)->(%u %p %p %p %p): stub\n", This, position, leading_spacing, trailing_spacing, minimum_advance_width, range);
2512 return E_NOTIMPL;
2515 static HRESULT WINAPI dwritetextlayout2_GetMetrics(IDWriteTextLayout2 *iface, DWRITE_TEXT_METRICS1 *metrics)
2517 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2518 FIXME("(%p)->(%p): stub\n", This, metrics);
2519 return E_NOTIMPL;
2522 static HRESULT WINAPI dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout2 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
2524 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2526 TRACE("(%p)->(%d)\n", This, orientation);
2528 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
2529 return E_INVALIDARG;
2531 This->format.vertical_orientation = orientation;
2532 return S_OK;
2535 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout2 *iface)
2537 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2538 TRACE("(%p)\n", This);
2539 return This->format.vertical_orientation;
2542 static HRESULT WINAPI dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout2 *iface, BOOL lastline_wrapping_enabled)
2544 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2545 FIXME("(%p)->(%d): stub\n", This, lastline_wrapping_enabled);
2546 return E_NOTIMPL;
2549 static BOOL WINAPI dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout2 *iface)
2551 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2552 FIXME("(%p): stub\n", This);
2553 return FALSE;
2556 static HRESULT WINAPI dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout2 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
2558 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2559 FIXME("(%p)->(%d): stub\n", This, alignment);
2560 return E_NOTIMPL;
2563 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout2 *iface)
2565 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2566 FIXME("(%p): stub\n", This);
2567 return DWRITE_OPTICAL_ALIGNMENT_NONE;
2570 static HRESULT WINAPI dwritetextlayout2_SetFontFallback(IDWriteTextLayout2 *iface, IDWriteFontFallback *fallback)
2572 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2573 TRACE("(%p)->(%p)\n", This, fallback);
2574 return set_fontfallback_for_format(&This->format, fallback);
2577 static HRESULT WINAPI dwritetextlayout2_GetFontFallback(IDWriteTextLayout2 *iface, IDWriteFontFallback **fallback)
2579 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2580 TRACE("(%p)->(%p)\n", This, fallback);
2581 return get_fontfallback_from_format(&This->format, fallback);
2584 static const IDWriteTextLayout2Vtbl dwritetextlayoutvtbl = {
2585 dwritetextlayout_QueryInterface,
2586 dwritetextlayout_AddRef,
2587 dwritetextlayout_Release,
2588 dwritetextlayout_SetTextAlignment,
2589 dwritetextlayout_SetParagraphAlignment,
2590 dwritetextlayout_SetWordWrapping,
2591 dwritetextlayout_SetReadingDirection,
2592 dwritetextlayout_SetFlowDirection,
2593 dwritetextlayout_SetIncrementalTabStop,
2594 dwritetextlayout_SetTrimming,
2595 dwritetextlayout_SetLineSpacing,
2596 dwritetextlayout_GetTextAlignment,
2597 dwritetextlayout_GetParagraphAlignment,
2598 dwritetextlayout_GetWordWrapping,
2599 dwritetextlayout_GetReadingDirection,
2600 dwritetextlayout_GetFlowDirection,
2601 dwritetextlayout_GetIncrementalTabStop,
2602 dwritetextlayout_GetTrimming,
2603 dwritetextlayout_GetLineSpacing,
2604 dwritetextlayout_GetFontCollection,
2605 dwritetextlayout_GetFontFamilyNameLength,
2606 dwritetextlayout_GetFontFamilyName,
2607 dwritetextlayout_GetFontWeight,
2608 dwritetextlayout_GetFontStyle,
2609 dwritetextlayout_GetFontStretch,
2610 dwritetextlayout_GetFontSize,
2611 dwritetextlayout_GetLocaleNameLength,
2612 dwritetextlayout_GetLocaleName,
2613 dwritetextlayout_SetMaxWidth,
2614 dwritetextlayout_SetMaxHeight,
2615 dwritetextlayout_SetFontCollection,
2616 dwritetextlayout_SetFontFamilyName,
2617 dwritetextlayout_SetFontWeight,
2618 dwritetextlayout_SetFontStyle,
2619 dwritetextlayout_SetFontStretch,
2620 dwritetextlayout_SetFontSize,
2621 dwritetextlayout_SetUnderline,
2622 dwritetextlayout_SetStrikethrough,
2623 dwritetextlayout_SetDrawingEffect,
2624 dwritetextlayout_SetInlineObject,
2625 dwritetextlayout_SetTypography,
2626 dwritetextlayout_SetLocaleName,
2627 dwritetextlayout_GetMaxWidth,
2628 dwritetextlayout_GetMaxHeight,
2629 dwritetextlayout_layout_GetFontCollection,
2630 dwritetextlayout_layout_GetFontFamilyNameLength,
2631 dwritetextlayout_layout_GetFontFamilyName,
2632 dwritetextlayout_layout_GetFontWeight,
2633 dwritetextlayout_layout_GetFontStyle,
2634 dwritetextlayout_layout_GetFontStretch,
2635 dwritetextlayout_layout_GetFontSize,
2636 dwritetextlayout_GetUnderline,
2637 dwritetextlayout_GetStrikethrough,
2638 dwritetextlayout_GetDrawingEffect,
2639 dwritetextlayout_GetInlineObject,
2640 dwritetextlayout_GetTypography,
2641 dwritetextlayout_layout_GetLocaleNameLength,
2642 dwritetextlayout_layout_GetLocaleName,
2643 dwritetextlayout_Draw,
2644 dwritetextlayout_GetLineMetrics,
2645 dwritetextlayout_GetMetrics,
2646 dwritetextlayout_GetOverhangMetrics,
2647 dwritetextlayout_GetClusterMetrics,
2648 dwritetextlayout_DetermineMinWidth,
2649 dwritetextlayout_HitTestPoint,
2650 dwritetextlayout_HitTestTextPosition,
2651 dwritetextlayout_HitTestTextRange,
2652 dwritetextlayout1_SetPairKerning,
2653 dwritetextlayout1_GetPairKerning,
2654 dwritetextlayout1_SetCharacterSpacing,
2655 dwritetextlayout1_GetCharacterSpacing,
2656 dwritetextlayout2_GetMetrics,
2657 dwritetextlayout2_SetVerticalGlyphOrientation,
2658 dwritetextlayout2_GetVerticalGlyphOrientation,
2659 dwritetextlayout2_SetLastLineWrapping,
2660 dwritetextlayout2_GetLastLineWrapping,
2661 dwritetextlayout2_SetOpticalAlignment,
2662 dwritetextlayout2_GetOpticalAlignment,
2663 dwritetextlayout2_SetFontFallback,
2664 dwritetextlayout2_GetFontFallback
2667 static HRESULT WINAPI dwritetextformat1_layout_QueryInterface(IDWriteTextFormat1 *iface, REFIID riid, void **obj)
2669 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2670 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2671 return IDWriteTextLayout2_QueryInterface(&This->IDWriteTextLayout2_iface, riid, obj);
2674 static ULONG WINAPI dwritetextformat1_layout_AddRef(IDWriteTextFormat1 *iface)
2676 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2677 return IDWriteTextLayout2_AddRef(&This->IDWriteTextLayout2_iface);
2680 static ULONG WINAPI dwritetextformat1_layout_Release(IDWriteTextFormat1 *iface)
2682 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2683 return IDWriteTextLayout2_Release(&This->IDWriteTextLayout2_iface);
2686 static HRESULT WINAPI dwritetextformat1_layout_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
2688 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2689 FIXME("(%p)->(%d): stub\n", This, alignment);
2690 return E_NOTIMPL;
2693 static HRESULT WINAPI dwritetextformat1_layout_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
2695 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2696 FIXME("(%p)->(%d): stub\n", This, alignment);
2697 return E_NOTIMPL;
2700 static HRESULT WINAPI dwritetextformat1_layout_SetWordWrapping(IDWriteTextFormat1 *iface, DWRITE_WORD_WRAPPING wrapping)
2702 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2703 FIXME("(%p)->(%d): stub\n", This, wrapping);
2704 return E_NOTIMPL;
2707 static HRESULT WINAPI dwritetextformat1_layout_SetReadingDirection(IDWriteTextFormat1 *iface, DWRITE_READING_DIRECTION direction)
2709 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2710 FIXME("(%p)->(%d): stub\n", This, direction);
2711 return E_NOTIMPL;
2714 static HRESULT WINAPI dwritetextformat1_layout_SetFlowDirection(IDWriteTextFormat1 *iface, DWRITE_FLOW_DIRECTION direction)
2716 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2717 FIXME("(%p)->(%d): stub\n", This, direction);
2718 return E_NOTIMPL;
2721 static HRESULT WINAPI dwritetextformat1_layout_SetIncrementalTabStop(IDWriteTextFormat1 *iface, FLOAT tabstop)
2723 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2724 FIXME("(%p)->(%f): stub\n", This, tabstop);
2725 return E_NOTIMPL;
2728 static HRESULT WINAPI dwritetextformat1_layout_SetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING const *trimming,
2729 IDWriteInlineObject *trimming_sign)
2731 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2732 FIXME("(%p)->(%p %p): stub\n", This, trimming, trimming_sign);
2733 return E_NOTIMPL;
2736 static HRESULT WINAPI dwritetextformat1_layout_SetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD spacing,
2737 FLOAT line_spacing, FLOAT baseline)
2739 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2740 FIXME("(%p)->(%d %f %f): stub\n", This, spacing, line_spacing, baseline);
2741 return E_NOTIMPL;
2744 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat1_layout_GetTextAlignment(IDWriteTextFormat1 *iface)
2746 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2747 TRACE("(%p)\n", This);
2748 return This->format.textalignment;
2751 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat1_layout_GetParagraphAlignment(IDWriteTextFormat1 *iface)
2753 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2754 TRACE("(%p)\n", This);
2755 return This->format.paralign;
2758 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat1_layout_GetWordWrapping(IDWriteTextFormat1 *iface)
2760 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2761 FIXME("(%p): stub\n", This);
2762 return This->format.wrapping;
2765 static DWRITE_READING_DIRECTION WINAPI dwritetextformat1_layout_GetReadingDirection(IDWriteTextFormat1 *iface)
2767 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2768 TRACE("(%p)\n", This);
2769 return This->format.readingdir;
2772 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat1_layout_GetFlowDirection(IDWriteTextFormat1 *iface)
2774 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2775 TRACE("(%p)\n", This);
2776 return This->format.flow;
2779 static FLOAT WINAPI dwritetextformat1_layout_GetIncrementalTabStop(IDWriteTextFormat1 *iface)
2781 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2782 FIXME("(%p): stub\n", This);
2783 return 0.0;
2786 static HRESULT WINAPI dwritetextformat1_layout_GetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING *options,
2787 IDWriteInlineObject **trimming_sign)
2789 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2791 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
2793 *options = This->format.trimming;
2794 *trimming_sign = This->format.trimmingsign;
2795 if (*trimming_sign)
2796 IDWriteInlineObject_AddRef(*trimming_sign);
2797 return S_OK;
2800 static HRESULT WINAPI dwritetextformat1_layout_GetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD *method,
2801 FLOAT *spacing, FLOAT *baseline)
2803 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2805 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
2807 *method = This->format.spacingmethod;
2808 *spacing = This->format.spacing;
2809 *baseline = This->format.baseline;
2810 return S_OK;
2813 static HRESULT WINAPI dwritetextformat1_layout_GetFontCollection(IDWriteTextFormat1 *iface, IDWriteFontCollection **collection)
2815 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2817 TRACE("(%p)->(%p)\n", This, collection);
2819 *collection = This->format.collection;
2820 if (*collection)
2821 IDWriteFontCollection_AddRef(*collection);
2822 return S_OK;
2825 static UINT32 WINAPI dwritetextformat1_layout_GetFontFamilyNameLength(IDWriteTextFormat1 *iface)
2827 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2828 TRACE("(%p)\n", This);
2829 return This->format.family_len;
2832 static HRESULT WINAPI dwritetextformat1_layout_GetFontFamilyName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
2834 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2836 TRACE("(%p)->(%p %u)\n", This, name, size);
2838 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
2839 strcpyW(name, This->format.family_name);
2840 return S_OK;
2843 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat1_layout_GetFontWeight(IDWriteTextFormat1 *iface)
2845 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2846 TRACE("(%p)\n", This);
2847 return This->format.weight;
2850 static DWRITE_FONT_STYLE WINAPI dwritetextformat1_layout_GetFontStyle(IDWriteTextFormat1 *iface)
2852 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2853 TRACE("(%p)\n", This);
2854 return This->format.style;
2857 static DWRITE_FONT_STRETCH WINAPI dwritetextformat1_layout_GetFontStretch(IDWriteTextFormat1 *iface)
2859 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2860 TRACE("(%p)\n", This);
2861 return This->format.stretch;
2864 static FLOAT WINAPI dwritetextformat1_layout_GetFontSize(IDWriteTextFormat1 *iface)
2866 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2867 TRACE("(%p)\n", This);
2868 return This->format.fontsize;
2871 static UINT32 WINAPI dwritetextformat1_layout_GetLocaleNameLength(IDWriteTextFormat1 *iface)
2873 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2874 TRACE("(%p)\n", This);
2875 return This->format.locale_len;
2878 static HRESULT WINAPI dwritetextformat1_layout_GetLocaleName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
2880 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2882 TRACE("(%p)->(%p %u)\n", This, name, size);
2884 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
2885 strcpyW(name, This->format.locale);
2886 return S_OK;
2889 static HRESULT WINAPI dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat1 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
2891 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2892 FIXME("(%p)->(%d): stub\n", This, orientation);
2893 return E_NOTIMPL;
2896 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat1 *iface)
2898 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2899 FIXME("(%p): stub\n", This);
2900 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
2903 static HRESULT WINAPI dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat1 *iface, BOOL lastline_wrapping_enabled)
2905 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2906 FIXME("(%p)->(%d): stub\n", This, lastline_wrapping_enabled);
2907 return E_NOTIMPL;
2910 static BOOL WINAPI dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat1 *iface)
2912 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2913 FIXME("(%p): stub\n", This);
2914 return FALSE;
2917 static HRESULT WINAPI dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat1 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
2919 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2920 FIXME("(%p)->(%d): stub\n", This, alignment);
2921 return E_NOTIMPL;
2924 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat1 *iface)
2926 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2927 FIXME("(%p): stub\n", This);
2928 return DWRITE_OPTICAL_ALIGNMENT_NONE;
2931 static HRESULT WINAPI dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback *fallback)
2933 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2934 TRACE("(%p)->(%p)\n", This, fallback);
2935 return IDWriteTextLayout2_SetFontFallback(&This->IDWriteTextLayout2_iface, fallback);
2938 static HRESULT WINAPI dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback **fallback)
2940 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2941 TRACE("(%p)->(%p)\n", This, fallback);
2942 return IDWriteTextLayout2_GetFontFallback(&This->IDWriteTextLayout2_iface, fallback);
2945 static const IDWriteTextFormat1Vtbl dwritetextformat1_layout_vtbl = {
2946 dwritetextformat1_layout_QueryInterface,
2947 dwritetextformat1_layout_AddRef,
2948 dwritetextformat1_layout_Release,
2949 dwritetextformat1_layout_SetTextAlignment,
2950 dwritetextformat1_layout_SetParagraphAlignment,
2951 dwritetextformat1_layout_SetWordWrapping,
2952 dwritetextformat1_layout_SetReadingDirection,
2953 dwritetextformat1_layout_SetFlowDirection,
2954 dwritetextformat1_layout_SetIncrementalTabStop,
2955 dwritetextformat1_layout_SetTrimming,
2956 dwritetextformat1_layout_SetLineSpacing,
2957 dwritetextformat1_layout_GetTextAlignment,
2958 dwritetextformat1_layout_GetParagraphAlignment,
2959 dwritetextformat1_layout_GetWordWrapping,
2960 dwritetextformat1_layout_GetReadingDirection,
2961 dwritetextformat1_layout_GetFlowDirection,
2962 dwritetextformat1_layout_GetIncrementalTabStop,
2963 dwritetextformat1_layout_GetTrimming,
2964 dwritetextformat1_layout_GetLineSpacing,
2965 dwritetextformat1_layout_GetFontCollection,
2966 dwritetextformat1_layout_GetFontFamilyNameLength,
2967 dwritetextformat1_layout_GetFontFamilyName,
2968 dwritetextformat1_layout_GetFontWeight,
2969 dwritetextformat1_layout_GetFontStyle,
2970 dwritetextformat1_layout_GetFontStretch,
2971 dwritetextformat1_layout_GetFontSize,
2972 dwritetextformat1_layout_GetLocaleNameLength,
2973 dwritetextformat1_layout_GetLocaleName,
2974 dwritetextformat1_layout_SetVerticalGlyphOrientation,
2975 dwritetextformat1_layout_GetVerticalGlyphOrientation,
2976 dwritetextformat1_layout_SetLastLineWrapping,
2977 dwritetextformat1_layout_GetLastLineWrapping,
2978 dwritetextformat1_layout_SetOpticalAlignment,
2979 dwritetextformat1_layout_GetOpticalAlignment,
2980 dwritetextformat1_layout_SetFontFallback,
2981 dwritetextformat1_layout_GetFontFallback
2984 static HRESULT WINAPI dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink *iface,
2985 REFIID riid, void **obj)
2987 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) || IsEqualIID(riid, &IID_IUnknown)) {
2988 *obj = iface;
2989 IDWriteTextAnalysisSink_AddRef(iface);
2990 return S_OK;
2993 *obj = NULL;
2994 return E_NOINTERFACE;
2997 static ULONG WINAPI dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink *iface)
2999 return 2;
3002 static ULONG WINAPI dwritetextlayout_sink_Release(IDWriteTextAnalysisSink *iface)
3004 return 1;
3007 static HRESULT WINAPI dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink *iface,
3008 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
3010 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
3011 struct layout_run *run;
3013 TRACE("%u %u script=%d\n", position, length, sa->script);
3015 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
3016 if (!run)
3017 return E_OUTOFMEMORY;
3019 run->u.regular.descr.string = &layout->str[position];
3020 run->u.regular.descr.stringLength = length;
3021 run->u.regular.descr.textPosition = position;
3022 run->u.regular.sa = *sa;
3023 list_add_tail(&layout->runs, &run->entry);
3024 return S_OK;
3027 static HRESULT WINAPI dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink *iface,
3028 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
3030 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
3032 if (position + length > layout->len)
3033 return E_FAIL;
3035 memcpy(&layout->nominal_breakpoints[position], breakpoints, length*sizeof(DWRITE_LINE_BREAKPOINT));
3036 return S_OK;
3039 static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink *iface, UINT32 position,
3040 UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
3042 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
3043 struct layout_run *cur_run;
3045 TRACE("%u %u %u %u\n", position, length, explicitLevel, resolvedLevel);
3047 LIST_FOR_EACH_ENTRY(cur_run, &layout->runs, struct layout_run, entry) {
3048 struct regular_layout_run *cur = &cur_run->u.regular;
3049 struct layout_run *run;
3051 if (cur_run->kind == LAYOUT_RUN_INLINE)
3052 continue;
3054 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
3055 if (position < cur->descr.textPosition || position >= cur->descr.textPosition + cur->descr.stringLength)
3056 continue;
3058 /* full hit - just set run level */
3059 if (cur->descr.textPosition == position && cur->descr.stringLength == length) {
3060 cur->run.bidiLevel = resolvedLevel;
3061 break;
3064 /* current run is fully covered, move to next one */
3065 if (cur->descr.textPosition == position && cur->descr.stringLength < length) {
3066 cur->run.bidiLevel = resolvedLevel;
3067 position += cur->descr.stringLength;
3068 length -= cur->descr.stringLength;
3069 continue;
3072 /* all fully covered runs are processed at this point, reuse existing run for remaining
3073 reported bidi range and add another run for the rest of original one */
3075 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
3076 if (!run)
3077 return E_OUTOFMEMORY;
3079 *run = *cur_run;
3080 run->u.regular.descr.textPosition = position + length;
3081 run->u.regular.descr.stringLength = cur->descr.stringLength - length;
3082 run->u.regular.descr.string = &layout->str[position + length];
3084 /* reduce existing run */
3085 cur->run.bidiLevel = resolvedLevel;
3086 cur->descr.stringLength -= length;
3088 list_add_after(&cur_run->entry, &run->entry);
3089 break;
3092 return S_OK;
3095 static HRESULT WINAPI dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink *iface,
3096 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
3098 return E_NOTIMPL;
3101 static const IDWriteTextAnalysisSinkVtbl dwritetextlayoutsinkvtbl = {
3102 dwritetextlayout_sink_QueryInterface,
3103 dwritetextlayout_sink_AddRef,
3104 dwritetextlayout_sink_Release,
3105 dwritetextlayout_sink_SetScriptAnalysis,
3106 dwritetextlayout_sink_SetLineBreakpoints,
3107 dwritetextlayout_sink_SetBidiLevel,
3108 dwritetextlayout_sink_SetNumberSubstitution
3111 static HRESULT WINAPI dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource *iface,
3112 REFIID riid, void **obj)
3114 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) ||
3115 IsEqualIID(riid, &IID_IUnknown))
3117 *obj = iface;
3118 IDWriteTextAnalysisSource_AddRef(iface);
3119 return S_OK;
3122 *obj = NULL;
3123 return E_NOINTERFACE;
3126 static ULONG WINAPI dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource *iface)
3128 return 2;
3131 static ULONG WINAPI dwritetextlayout_source_Release(IDWriteTextAnalysisSource *iface)
3133 return 1;
3136 static HRESULT WINAPI dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource *iface,
3137 UINT32 position, WCHAR const** text, UINT32* text_len)
3139 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource(iface);
3141 TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
3143 if (position < layout->len) {
3144 *text = &layout->str[position];
3145 *text_len = layout->len - position;
3147 else {
3148 *text = NULL;
3149 *text_len = 0;
3152 return S_OK;
3155 static HRESULT WINAPI dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource *iface,
3156 UINT32 position, WCHAR const** text, UINT32* text_len)
3158 FIXME("%u %p %p: stub\n", position, text, text_len);
3159 return E_NOTIMPL;
3162 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource *iface)
3164 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource(iface);
3165 return IDWriteTextLayout2_GetReadingDirection(&layout->IDWriteTextLayout2_iface);
3168 static HRESULT WINAPI dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource *iface,
3169 UINT32 position, UINT32* text_len, WCHAR const** locale)
3171 FIXME("%u %p %p: stub\n", position, text_len, locale);
3172 return E_NOTIMPL;
3175 static HRESULT WINAPI dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource *iface,
3176 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
3178 FIXME("%u %p %p: stub\n", position, text_len, substitution);
3179 return E_NOTIMPL;
3182 static const IDWriteTextAnalysisSourceVtbl dwritetextlayoutsourcevtbl = {
3183 dwritetextlayout_source_QueryInterface,
3184 dwritetextlayout_source_AddRef,
3185 dwritetextlayout_source_Release,
3186 dwritetextlayout_source_GetTextAtPosition,
3187 dwritetextlayout_source_GetTextBeforePosition,
3188 dwritetextlayout_source_GetParagraphReadingDirection,
3189 dwritetextlayout_source_GetLocaleName,
3190 dwritetextlayout_source_GetNumberSubstitution
3193 static HRESULT layout_format_from_textformat(struct dwrite_textlayout *layout, IDWriteTextFormat *format)
3195 IDWriteTextFormat1 *format1;
3196 UINT32 len;
3197 HRESULT hr;
3199 layout->format.weight = IDWriteTextFormat_GetFontWeight(format);
3200 layout->format.style = IDWriteTextFormat_GetFontStyle(format);
3201 layout->format.stretch = IDWriteTextFormat_GetFontStretch(format);
3202 layout->format.fontsize= IDWriteTextFormat_GetFontSize(format);
3203 layout->format.textalignment = IDWriteTextFormat_GetTextAlignment(format);
3204 layout->format.paralign = IDWriteTextFormat_GetParagraphAlignment(format);
3205 layout->format.wrapping = IDWriteTextFormat_GetWordWrapping(format);
3206 layout->format.readingdir = IDWriteTextFormat_GetReadingDirection(format);
3207 layout->format.flow = IDWriteTextFormat_GetFlowDirection(format);
3208 layout->format.fallback = NULL;
3209 hr = IDWriteTextFormat_GetLineSpacing(format, &layout->format.spacingmethod,
3210 &layout->format.spacing, &layout->format.baseline);
3211 if (FAILED(hr))
3212 return hr;
3214 hr = IDWriteTextFormat_GetTrimming(format, &layout->format.trimming, &layout->format.trimmingsign);
3215 if (FAILED(hr))
3216 return hr;
3218 /* locale name and length */
3219 len = IDWriteTextFormat_GetLocaleNameLength(format);
3220 layout->format.locale = heap_alloc((len+1)*sizeof(WCHAR));
3221 if (!layout->format.locale)
3222 return E_OUTOFMEMORY;
3224 hr = IDWriteTextFormat_GetLocaleName(format, layout->format.locale, len+1);
3225 if (FAILED(hr))
3226 return hr;
3227 layout->format.locale_len = len;
3229 /* font family name and length */
3230 len = IDWriteTextFormat_GetFontFamilyNameLength(format);
3231 layout->format.family_name = heap_alloc((len+1)*sizeof(WCHAR));
3232 if (!layout->format.family_name)
3233 return E_OUTOFMEMORY;
3235 hr = IDWriteTextFormat_GetFontFamilyName(format, layout->format.family_name, len+1);
3236 if (FAILED(hr))
3237 return hr;
3238 layout->format.family_len = len;
3240 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
3241 if (hr == S_OK) {
3242 layout->format.vertical_orientation = IDWriteTextFormat1_GetVerticalGlyphOrientation(format1);
3243 IDWriteTextFormat1_GetFontFallback(format1, &layout->format.fallback);
3244 IDWriteTextFormat1_Release(format1);
3246 else
3247 layout->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
3249 return IDWriteTextFormat_GetFontCollection(format, &layout->format.collection);
3252 static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, struct dwrite_textlayout *layout)
3254 struct layout_range_header *range, *strike;
3255 DWRITE_TEXT_RANGE r;
3256 HRESULT hr;
3258 layout->IDWriteTextLayout2_iface.lpVtbl = &dwritetextlayoutvtbl;
3259 layout->IDWriteTextFormat1_iface.lpVtbl = &dwritetextformat1_layout_vtbl;
3260 layout->IDWriteTextAnalysisSink_iface.lpVtbl = &dwritetextlayoutsinkvtbl;
3261 layout->IDWriteTextAnalysisSource_iface.lpVtbl = &dwritetextlayoutsourcevtbl;
3262 layout->ref = 1;
3263 layout->len = len;
3264 layout->maxwidth = maxwidth;
3265 layout->maxheight = maxheight;
3266 layout->recompute = RECOMPUTE_EVERYTHING;
3267 layout->nominal_breakpoints = NULL;
3268 layout->actual_breakpoints = NULL;
3269 layout->cluster_count = 0;
3270 layout->clustermetrics = NULL;
3271 layout->clusters = NULL;
3272 layout->lines = NULL;
3273 layout->line_count = 0;
3274 layout->line_alloc = 0;
3275 layout->minwidth = 0.0;
3276 list_init(&layout->eruns);
3277 list_init(&layout->inlineobjects);
3278 list_init(&layout->strikethrough);
3279 list_init(&layout->runs);
3280 list_init(&layout->ranges);
3281 list_init(&layout->strike_ranges);
3282 memset(&layout->format, 0, sizeof(layout->format));
3284 layout->gdicompatible = FALSE;
3285 layout->pixels_per_dip = 0.0;
3286 layout->use_gdi_natural = FALSE;
3287 memset(&layout->transform, 0, sizeof(layout->transform));
3289 layout->str = heap_strdupnW(str, len);
3290 if (len && !layout->str) {
3291 hr = E_OUTOFMEMORY;
3292 goto fail;
3295 hr = layout_format_from_textformat(layout, format);
3296 if (FAILED(hr))
3297 goto fail;
3299 r.startPosition = 0;
3300 r.length = ~0u;
3301 range = alloc_layout_range(layout, &r, LAYOUT_RANGE_REGULAR);
3302 r.startPosition = 0;
3303 r.length = len;
3304 strike = alloc_layout_range(layout, &r, LAYOUT_RANGE_STRIKETHROUGH);
3305 if (!range || !strike) {
3306 free_layout_range(range);
3307 free_layout_range(strike);
3308 hr = E_OUTOFMEMORY;
3309 goto fail;
3312 list_add_head(&layout->ranges, &range->entry);
3313 list_add_head(&layout->strike_ranges, &strike->entry);
3314 return S_OK;
3316 fail:
3317 IDWriteTextLayout2_Release(&layout->IDWriteTextLayout2_iface);
3318 return hr;
3321 HRESULT create_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, IDWriteTextLayout **ret)
3323 struct dwrite_textlayout *layout;
3324 HRESULT hr;
3326 *ret = NULL;
3328 layout = heap_alloc(sizeof(struct dwrite_textlayout));
3329 if (!layout) return E_OUTOFMEMORY;
3331 hr = init_textlayout(str, len, format, maxwidth, maxheight, layout);
3332 if (hr == S_OK)
3333 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout2_iface;
3335 return hr;
3338 HRESULT create_gdicompat_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight,
3339 FLOAT pixels_per_dip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural, IDWriteTextLayout **ret)
3341 struct dwrite_textlayout *layout;
3342 HRESULT hr;
3344 *ret = NULL;
3346 layout = heap_alloc(sizeof(struct dwrite_textlayout));
3347 if (!layout) return E_OUTOFMEMORY;
3349 hr = init_textlayout(str, len, format, maxwidth, maxheight, layout);
3350 if (hr == S_OK) {
3351 /* set gdi-specific properties */
3352 layout->gdicompatible = TRUE;
3353 layout->pixels_per_dip = pixels_per_dip;
3354 layout->use_gdi_natural = use_gdi_natural;
3355 layout->transform = transform ? *transform : identity;
3357 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout2_iface;
3360 return hr;
3363 static HRESULT WINAPI dwritetrimmingsign_QueryInterface(IDWriteInlineObject *iface, REFIID riid, void **obj)
3365 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3367 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3369 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteInlineObject)) {
3370 *obj = iface;
3371 IDWriteInlineObject_AddRef(iface);
3372 return S_OK;
3375 *obj = NULL;
3376 return E_NOINTERFACE;
3380 static ULONG WINAPI dwritetrimmingsign_AddRef(IDWriteInlineObject *iface)
3382 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3383 ULONG ref = InterlockedIncrement(&This->ref);
3384 TRACE("(%p)->(%d)\n", This, ref);
3385 return ref;
3388 static ULONG WINAPI dwritetrimmingsign_Release(IDWriteInlineObject *iface)
3390 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3391 ULONG ref = InterlockedDecrement(&This->ref);
3393 TRACE("(%p)->(%d)\n", This, ref);
3395 if (!ref)
3396 heap_free(This);
3398 return ref;
3401 static HRESULT WINAPI dwritetrimmingsign_Draw(IDWriteInlineObject *iface, void *context, IDWriteTextRenderer *renderer,
3402 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *drawing_effect)
3404 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3405 FIXME("(%p)->(%p %p %f %f %d %d %p): stub\n", This, context, renderer, originX, originY, is_sideways, is_rtl, drawing_effect);
3406 return E_NOTIMPL;
3409 static HRESULT WINAPI dwritetrimmingsign_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *metrics)
3411 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3412 FIXME("(%p)->(%p): stub\n", This, metrics);
3413 memset(metrics, 0, sizeof(*metrics));
3414 return S_OK;
3417 static HRESULT WINAPI dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
3419 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3420 FIXME("(%p)->(%p): stub\n", This, overhangs);
3421 return E_NOTIMPL;
3424 static HRESULT WINAPI dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
3425 DWRITE_BREAK_CONDITION *after)
3427 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3429 TRACE("(%p)->(%p %p)\n", This, before, after);
3431 *before = *after = DWRITE_BREAK_CONDITION_NEUTRAL;
3432 return S_OK;
3435 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl = {
3436 dwritetrimmingsign_QueryInterface,
3437 dwritetrimmingsign_AddRef,
3438 dwritetrimmingsign_Release,
3439 dwritetrimmingsign_Draw,
3440 dwritetrimmingsign_GetMetrics,
3441 dwritetrimmingsign_GetOverhangMetrics,
3442 dwritetrimmingsign_GetBreakConditions
3445 HRESULT create_trimmingsign(IDWriteInlineObject **sign)
3447 struct dwrite_trimmingsign *This;
3449 *sign = NULL;
3451 This = heap_alloc(sizeof(struct dwrite_trimmingsign));
3452 if (!This) return E_OUTOFMEMORY;
3454 This->IDWriteInlineObject_iface.lpVtbl = &dwritetrimmingsignvtbl;
3455 This->ref = 1;
3457 *sign = &This->IDWriteInlineObject_iface;
3459 return S_OK;
3462 static HRESULT WINAPI dwritetextformat_QueryInterface(IDWriteTextFormat1 *iface, REFIID riid, void **obj)
3464 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3466 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3468 if (IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
3469 IsEqualIID(riid, &IID_IDWriteTextFormat) ||
3470 IsEqualIID(riid, &IID_IUnknown))
3472 *obj = iface;
3473 IDWriteTextFormat1_AddRef(iface);
3474 return S_OK;
3477 *obj = NULL;
3479 return E_NOINTERFACE;
3482 static ULONG WINAPI dwritetextformat_AddRef(IDWriteTextFormat1 *iface)
3484 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3485 ULONG ref = InterlockedIncrement(&This->ref);
3486 TRACE("(%p)->(%d)\n", This, ref);
3487 return ref;
3490 static ULONG WINAPI dwritetextformat_Release(IDWriteTextFormat1 *iface)
3492 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3493 ULONG ref = InterlockedDecrement(&This->ref);
3495 TRACE("(%p)->(%d)\n", This, ref);
3497 if (!ref)
3499 release_format_data(&This->format);
3500 heap_free(This);
3503 return ref;
3506 static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
3508 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3509 TRACE("(%p)->(%d)\n", This, alignment);
3510 This->format.textalignment = alignment;
3511 return S_OK;
3514 static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
3516 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3517 TRACE("(%p)->(%d)\n", This, alignment);
3518 This->format.paralign = alignment;
3519 return S_OK;
3522 static HRESULT WINAPI dwritetextformat_SetWordWrapping(IDWriteTextFormat1 *iface, DWRITE_WORD_WRAPPING wrapping)
3524 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3525 TRACE("(%p)->(%d)\n", This, wrapping);
3526 This->format.wrapping = wrapping;
3527 return S_OK;
3530 static HRESULT WINAPI dwritetextformat_SetReadingDirection(IDWriteTextFormat1 *iface, DWRITE_READING_DIRECTION direction)
3532 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3533 TRACE("(%p)->(%d)\n", This, direction);
3534 This->format.readingdir = direction;
3535 return S_OK;
3538 static HRESULT WINAPI dwritetextformat_SetFlowDirection(IDWriteTextFormat1 *iface, DWRITE_FLOW_DIRECTION direction)
3540 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3541 TRACE("(%p)->(%d)\n", This, direction);
3542 This->format.flow = direction;
3543 return S_OK;
3546 static HRESULT WINAPI dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat1 *iface, FLOAT tabstop)
3548 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3549 FIXME("(%p)->(%f): stub\n", This, tabstop);
3550 return E_NOTIMPL;
3553 static HRESULT WINAPI dwritetextformat_SetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING const *trimming,
3554 IDWriteInlineObject *trimming_sign)
3556 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3557 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
3559 This->format.trimming = *trimming;
3560 if (This->format.trimmingsign)
3561 IDWriteInlineObject_Release(This->format.trimmingsign);
3562 This->format.trimmingsign = trimming_sign;
3563 if (This->format.trimmingsign)
3564 IDWriteInlineObject_AddRef(This->format.trimmingsign);
3565 return S_OK;
3568 static HRESULT WINAPI dwritetextformat_SetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD method,
3569 FLOAT spacing, FLOAT baseline)
3571 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3572 TRACE("(%p)->(%d %f %f)\n", This, method, spacing, baseline);
3573 This->format.spacingmethod = method;
3574 This->format.spacing = spacing;
3575 This->format.baseline = baseline;
3576 return S_OK;
3579 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_GetTextAlignment(IDWriteTextFormat1 *iface)
3581 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3582 TRACE("(%p)\n", This);
3583 return This->format.textalignment;
3586 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_GetParagraphAlignment(IDWriteTextFormat1 *iface)
3588 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3589 TRACE("(%p)\n", This);
3590 return This->format.paralign;
3593 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_GetWordWrapping(IDWriteTextFormat1 *iface)
3595 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3596 TRACE("(%p)\n", This);
3597 return This->format.wrapping;
3600 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_GetReadingDirection(IDWriteTextFormat1 *iface)
3602 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3603 TRACE("(%p)\n", This);
3604 return This->format.readingdir;
3607 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_GetFlowDirection(IDWriteTextFormat1 *iface)
3609 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3610 TRACE("(%p)\n", This);
3611 return This->format.flow;
3614 static FLOAT WINAPI dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat1 *iface)
3616 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3617 FIXME("(%p): stub\n", This);
3618 return 0.0;
3621 static HRESULT WINAPI dwritetextformat_GetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING *options,
3622 IDWriteInlineObject **trimming_sign)
3624 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3625 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
3627 *options = This->format.trimming;
3628 if ((*trimming_sign = This->format.trimmingsign))
3629 IDWriteInlineObject_AddRef(*trimming_sign);
3631 return S_OK;
3634 static HRESULT WINAPI dwritetextformat_GetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD *method,
3635 FLOAT *spacing, FLOAT *baseline)
3637 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3638 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
3640 *method = This->format.spacingmethod;
3641 *spacing = This->format.spacing;
3642 *baseline = This->format.baseline;
3643 return S_OK;
3646 static HRESULT WINAPI dwritetextformat_GetFontCollection(IDWriteTextFormat1 *iface, IDWriteFontCollection **collection)
3648 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3650 TRACE("(%p)->(%p)\n", This, collection);
3652 *collection = This->format.collection;
3653 IDWriteFontCollection_AddRef(*collection);
3655 return S_OK;
3658 static UINT32 WINAPI dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat1 *iface)
3660 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3661 TRACE("(%p)\n", This);
3662 return This->format.family_len;
3665 static HRESULT WINAPI dwritetextformat_GetFontFamilyName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
3667 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3669 TRACE("(%p)->(%p %u)\n", This, name, size);
3671 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
3672 strcpyW(name, This->format.family_name);
3673 return S_OK;
3676 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_GetFontWeight(IDWriteTextFormat1 *iface)
3678 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3679 TRACE("(%p)\n", This);
3680 return This->format.weight;
3683 static DWRITE_FONT_STYLE WINAPI dwritetextformat_GetFontStyle(IDWriteTextFormat1 *iface)
3685 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3686 TRACE("(%p)\n", This);
3687 return This->format.style;
3690 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_GetFontStretch(IDWriteTextFormat1 *iface)
3692 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3693 TRACE("(%p)\n", This);
3694 return This->format.stretch;
3697 static FLOAT WINAPI dwritetextformat_GetFontSize(IDWriteTextFormat1 *iface)
3699 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3700 TRACE("(%p)\n", This);
3701 return This->format.fontsize;
3704 static UINT32 WINAPI dwritetextformat_GetLocaleNameLength(IDWriteTextFormat1 *iface)
3706 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3707 TRACE("(%p)\n", This);
3708 return This->format.locale_len;
3711 static HRESULT WINAPI dwritetextformat_GetLocaleName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
3713 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3715 TRACE("(%p)->(%p %u)\n", This, name, size);
3717 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
3718 strcpyW(name, This->format.locale);
3719 return S_OK;
3722 static HRESULT WINAPI dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat1 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
3724 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3726 TRACE("(%p)->(%d)\n", This, orientation);
3728 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
3729 return E_INVALIDARG;
3731 This->format.vertical_orientation = orientation;
3732 return S_OK;
3735 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat1 *iface)
3737 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3738 TRACE("(%p)\n", This);
3739 return This->format.vertical_orientation;
3742 static HRESULT WINAPI dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat1 *iface, BOOL lastline_wrapping_enabled)
3744 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3745 FIXME("(%p)->(%d): stub\n", This, lastline_wrapping_enabled);
3746 return E_NOTIMPL;
3749 static BOOL WINAPI dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat1 *iface)
3751 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3752 FIXME("(%p): stub\n", This);
3753 return FALSE;
3756 static HRESULT WINAPI dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat1 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
3758 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3759 FIXME("(%p)->(%d): stub\n", This, alignment);
3760 return E_NOTIMPL;
3763 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat1 *iface)
3765 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3766 FIXME("(%p): stub\n", This);
3767 return DWRITE_OPTICAL_ALIGNMENT_NONE;
3770 static HRESULT WINAPI dwritetextformat1_SetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback *fallback)
3772 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3773 TRACE("(%p)->(%p)\n", This, fallback);
3774 return set_fontfallback_for_format(&This->format, fallback);
3777 static HRESULT WINAPI dwritetextformat1_GetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback **fallback)
3779 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3780 TRACE("(%p)->(%p)\n", This, fallback);
3781 return get_fontfallback_from_format(&This->format, fallback);
3784 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl = {
3785 dwritetextformat_QueryInterface,
3786 dwritetextformat_AddRef,
3787 dwritetextformat_Release,
3788 dwritetextformat_SetTextAlignment,
3789 dwritetextformat_SetParagraphAlignment,
3790 dwritetextformat_SetWordWrapping,
3791 dwritetextformat_SetReadingDirection,
3792 dwritetextformat_SetFlowDirection,
3793 dwritetextformat_SetIncrementalTabStop,
3794 dwritetextformat_SetTrimming,
3795 dwritetextformat_SetLineSpacing,
3796 dwritetextformat_GetTextAlignment,
3797 dwritetextformat_GetParagraphAlignment,
3798 dwritetextformat_GetWordWrapping,
3799 dwritetextformat_GetReadingDirection,
3800 dwritetextformat_GetFlowDirection,
3801 dwritetextformat_GetIncrementalTabStop,
3802 dwritetextformat_GetTrimming,
3803 dwritetextformat_GetLineSpacing,
3804 dwritetextformat_GetFontCollection,
3805 dwritetextformat_GetFontFamilyNameLength,
3806 dwritetextformat_GetFontFamilyName,
3807 dwritetextformat_GetFontWeight,
3808 dwritetextformat_GetFontStyle,
3809 dwritetextformat_GetFontStretch,
3810 dwritetextformat_GetFontSize,
3811 dwritetextformat_GetLocaleNameLength,
3812 dwritetextformat_GetLocaleName,
3813 dwritetextformat1_SetVerticalGlyphOrientation,
3814 dwritetextformat1_GetVerticalGlyphOrientation,
3815 dwritetextformat1_SetLastLineWrapping,
3816 dwritetextformat1_GetLastLineWrapping,
3817 dwritetextformat1_SetOpticalAlignment,
3818 dwritetextformat1_GetOpticalAlignment,
3819 dwritetextformat1_SetFontFallback,
3820 dwritetextformat1_GetFontFallback
3823 HRESULT create_textformat(const WCHAR *family_name, IDWriteFontCollection *collection, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style,
3824 DWRITE_FONT_STRETCH stretch, FLOAT size, const WCHAR *locale, IDWriteTextFormat **format)
3826 struct dwrite_textformat *This;
3828 *format = NULL;
3830 This = heap_alloc(sizeof(struct dwrite_textformat));
3831 if (!This) return E_OUTOFMEMORY;
3833 This->IDWriteTextFormat1_iface.lpVtbl = &dwritetextformatvtbl;
3834 This->ref = 1;
3835 This->format.family_name = heap_strdupW(family_name);
3836 This->format.family_len = strlenW(family_name);
3837 This->format.locale = heap_strdupW(locale);
3838 This->format.locale_len = strlenW(locale);
3839 This->format.weight = weight;
3840 This->format.style = style;
3841 This->format.fontsize = size;
3842 This->format.stretch = stretch;
3843 This->format.textalignment = DWRITE_TEXT_ALIGNMENT_LEADING;
3844 This->format.paralign = DWRITE_PARAGRAPH_ALIGNMENT_NEAR;
3845 This->format.wrapping = DWRITE_WORD_WRAPPING_WRAP;
3846 This->format.readingdir = DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
3847 This->format.flow = DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM;
3848 This->format.spacingmethod = DWRITE_LINE_SPACING_METHOD_DEFAULT;
3849 This->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
3850 This->format.spacing = 0.0;
3851 This->format.baseline = 0.0;
3852 This->format.trimming.granularity = DWRITE_TRIMMING_GRANULARITY_NONE;
3853 This->format.trimming.delimiter = 0;
3854 This->format.trimming.delimiterCount = 0;
3855 This->format.trimmingsign = NULL;
3856 This->format.collection = collection;
3857 This->format.fallback = NULL;
3858 IDWriteFontCollection_AddRef(collection);
3860 *format = (IDWriteTextFormat*)&This->IDWriteTextFormat1_iface;
3862 return S_OK;
3865 static HRESULT WINAPI dwritetypography_QueryInterface(IDWriteTypography *iface, REFIID riid, void **obj)
3867 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
3869 TRACE("(%p)->(%s %p)\n", typography, debugstr_guid(riid), obj);
3871 if (IsEqualIID(riid, &IID_IDWriteTypography) || IsEqualIID(riid, &IID_IUnknown)) {
3872 *obj = iface;
3873 IDWriteTypography_AddRef(iface);
3874 return S_OK;
3877 *obj = NULL;
3879 return E_NOINTERFACE;
3882 static ULONG WINAPI dwritetypography_AddRef(IDWriteTypography *iface)
3884 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
3885 ULONG ref = InterlockedIncrement(&typography->ref);
3886 TRACE("(%p)->(%d)\n", typography, ref);
3887 return ref;
3890 static ULONG WINAPI dwritetypography_Release(IDWriteTypography *iface)
3892 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
3893 ULONG ref = InterlockedDecrement(&typography->ref);
3895 TRACE("(%p)->(%d)\n", typography, ref);
3897 if (!ref) {
3898 heap_free(typography->features);
3899 heap_free(typography);
3902 return ref;
3905 static HRESULT WINAPI dwritetypography_AddFontFeature(IDWriteTypography *iface, DWRITE_FONT_FEATURE feature)
3907 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
3909 TRACE("(%p)->(%x %u)\n", typography, feature.nameTag, feature.parameter);
3911 if (typography->count == typography->allocated) {
3912 DWRITE_FONT_FEATURE *ptr = heap_realloc(typography->features, 2*typography->allocated*sizeof(DWRITE_FONT_FEATURE));
3913 if (!ptr)
3914 return E_OUTOFMEMORY;
3916 typography->features = ptr;
3917 typography->allocated *= 2;
3920 typography->features[typography->count++] = feature;
3921 return S_OK;
3924 static UINT32 WINAPI dwritetypography_GetFontFeatureCount(IDWriteTypography *iface)
3926 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
3927 TRACE("(%p)\n", typography);
3928 return typography->count;
3931 static HRESULT WINAPI dwritetypography_GetFontFeature(IDWriteTypography *iface, UINT32 index, DWRITE_FONT_FEATURE *feature)
3933 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
3935 TRACE("(%p)->(%u %p)\n", typography, index, feature);
3937 if (index >= typography->count)
3938 return E_INVALIDARG;
3940 *feature = typography->features[index];
3941 return S_OK;
3944 static const IDWriteTypographyVtbl dwritetypographyvtbl = {
3945 dwritetypography_QueryInterface,
3946 dwritetypography_AddRef,
3947 dwritetypography_Release,
3948 dwritetypography_AddFontFeature,
3949 dwritetypography_GetFontFeatureCount,
3950 dwritetypography_GetFontFeature
3953 HRESULT create_typography(IDWriteTypography **ret)
3955 struct dwrite_typography *typography;
3957 *ret = NULL;
3959 typography = heap_alloc(sizeof(*typography));
3960 if (!typography)
3961 return E_OUTOFMEMORY;
3963 typography->IDWriteTypography_iface.lpVtbl = &dwritetypographyvtbl;
3964 typography->ref = 1;
3965 typography->allocated = 2;
3966 typography->count = 0;
3968 typography->features = heap_alloc(typography->allocated*sizeof(DWRITE_FONT_FEATURE));
3969 if (!typography->features) {
3970 heap_free(typography);
3971 return E_OUTOFMEMORY;
3974 *ret = &typography->IDWriteTypography_iface;
3975 return S_OK;