dwrite: Initial implementation of Draw().
[wine/multimedia.git] / dlls / dwrite / layout.c
blob11d69d87b2ad5f049d18a90e4626face9f32d997
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 struct layout_range {
97 struct list entry;
98 DWRITE_TEXT_RANGE range;
99 DWRITE_FONT_WEIGHT weight;
100 DWRITE_FONT_STYLE style;
101 FLOAT fontsize;
102 DWRITE_FONT_STRETCH stretch;
103 IDWriteInlineObject *object;
104 IUnknown *effect;
105 BOOL underline;
106 BOOL strikethrough;
107 BOOL pair_kerning;
108 IDWriteFontCollection *collection;
109 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
110 WCHAR *fontfamily;
113 enum layout_run_kind {
114 LAYOUT_RUN_REGULAR,
115 LAYOUT_RUN_INLINE
118 struct inline_object_run {
119 IDWriteInlineObject *object;
120 UINT16 length;
123 struct regular_layout_run {
124 DWRITE_GLYPH_RUN_DESCRIPTION descr;
125 DWRITE_GLYPH_RUN run;
126 DWRITE_SCRIPT_ANALYSIS sa;
127 UINT16 *glyphs;
128 UINT16 *clustermap;
129 FLOAT *advances;
130 DWRITE_GLYPH_OFFSET *offsets;
133 struct layout_run {
134 struct list entry;
135 enum layout_run_kind kind;
136 union {
137 struct inline_object_run object;
138 struct regular_layout_run regular;
139 } u;
142 struct layout_effective_run {
143 struct list entry;
144 const struct layout_run *run; /* nominal run this one is based on */
145 UINT32 start; /* relative text position, 0 means first text position of a nominal run */
146 UINT32 length; /* length in codepoints that this run covers */
147 UINT32 glyphcount; /* total glyph count in this run */
148 FLOAT origin_x; /* baseline X position */
149 FLOAT origin_y; /* baseline Y position */
150 UINT16 *clustermap; /* effective clustermap, allocated separately, is not reused from nominal map */
153 struct layout_cluster {
154 const struct layout_run *run; /* link to nominal run this cluster belongs to */
155 UINT32 position; /* relative to run, first cluster has 0 position */
158 enum layout_recompute_mask {
159 RECOMPUTE_NOMINAL_RUNS = 1 << 0,
160 RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
161 RECOMPUTE_EFFECTIVE_RUNS = 1 << 2,
162 RECOMPUTE_EVERYTHING = 0xffff
165 struct dwrite_textlayout {
166 IDWriteTextLayout2 IDWriteTextLayout2_iface;
167 IDWriteTextFormat1 IDWriteTextFormat1_iface;
168 IDWriteTextAnalysisSink IDWriteTextAnalysisSink_iface;
169 IDWriteTextAnalysisSource IDWriteTextAnalysisSource_iface;
170 LONG ref;
172 WCHAR *str;
173 UINT32 len;
174 struct dwrite_textformat_data format;
175 FLOAT maxwidth;
176 FLOAT maxheight;
177 struct list ranges;
178 struct list eruns;
179 struct list runs;
180 USHORT recompute;
182 DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
183 DWRITE_LINE_BREAKPOINT *actual_breakpoints;
185 struct layout_cluster *clusters;
186 DWRITE_CLUSTER_METRICS *clustermetrics;
187 UINT32 cluster_count;
188 FLOAT minwidth;
190 DWRITE_LINE_METRICS *lines;
191 UINT32 line_count;
192 UINT32 line_alloc;
194 /* gdi-compatible layout specifics */
195 BOOL gdicompatible;
196 FLOAT pixels_per_dip;
197 BOOL use_gdi_natural;
198 DWRITE_MATRIX transform;
201 struct dwrite_textformat {
202 IDWriteTextFormat1 IDWriteTextFormat1_iface;
203 LONG ref;
204 struct dwrite_textformat_data format;
207 struct dwrite_trimmingsign {
208 IDWriteInlineObject IDWriteInlineObject_iface;
209 LONG ref;
212 struct dwrite_typography {
213 IDWriteTypography IDWriteTypography_iface;
214 LONG ref;
216 DWRITE_FONT_FEATURE *features;
217 UINT32 allocated;
218 UINT32 count;
221 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl;
223 static void release_format_data(struct dwrite_textformat_data *data)
225 if (data->collection) IDWriteFontCollection_Release(data->collection);
226 if (data->fallback) IDWriteFontFallback_Release(data->fallback);
227 if (data->trimmingsign) IDWriteInlineObject_Release(data->trimmingsign);
228 heap_free(data->family_name);
229 heap_free(data->locale);
232 static inline struct dwrite_textlayout *impl_from_IDWriteTextLayout2(IDWriteTextLayout2 *iface)
234 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextLayout2_iface);
237 static inline struct dwrite_textlayout *impl_layout_form_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
239 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextFormat1_iface);
242 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSink(IDWriteTextAnalysisSink *iface)
244 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSink_iface);
247 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSource(IDWriteTextAnalysisSource *iface)
249 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSource_iface);
252 static inline struct dwrite_textformat *impl_from_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
254 return CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat1_iface);
257 static inline struct dwrite_trimmingsign *impl_from_IDWriteInlineObject(IDWriteInlineObject *iface)
259 return CONTAINING_RECORD(iface, struct dwrite_trimmingsign, IDWriteInlineObject_iface);
262 static inline struct dwrite_typography *impl_from_IDWriteTypography(IDWriteTypography *iface)
264 return CONTAINING_RECORD(iface, struct dwrite_typography, IDWriteTypography_iface);
267 static inline const char *debugstr_run(const struct regular_layout_run *run)
269 return wine_dbg_sprintf("[%u,%u)", run->descr.textPosition, run->descr.textPosition +
270 run->descr.stringLength);
273 static HRESULT get_fontfallback_from_format(const struct dwrite_textformat_data *format, IDWriteFontFallback **fallback)
275 *fallback = format->fallback;
276 if (*fallback)
277 IDWriteFontFallback_AddRef(*fallback);
278 return S_OK;
281 static HRESULT set_fontfallback_for_format(struct dwrite_textformat_data *format, IDWriteFontFallback *fallback)
283 if (format->fallback)
284 IDWriteFontFallback_Release(format->fallback);
285 format->fallback = fallback;
286 if (fallback)
287 IDWriteFontFallback_AddRef(fallback);
288 return S_OK;
291 static struct layout_run *alloc_layout_run(enum layout_run_kind kind)
293 struct layout_run *ret;
295 ret = heap_alloc(sizeof(*ret));
296 if (!ret) return NULL;
298 memset(ret, 0, sizeof(*ret));
299 ret->kind = kind;
300 if (kind == LAYOUT_RUN_REGULAR) {
301 ret->u.regular.sa.script = Script_Unknown;
302 ret->u.regular.sa.shapes = DWRITE_SCRIPT_SHAPES_DEFAULT;
305 return ret;
308 static void free_layout_runs(struct dwrite_textlayout *layout)
310 struct layout_run *cur, *cur2;
311 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->runs, struct layout_run, entry) {
312 list_remove(&cur->entry);
313 if (cur->kind == LAYOUT_RUN_REGULAR) {
314 if (cur->u.regular.run.fontFace)
315 IDWriteFontFace_Release(cur->u.regular.run.fontFace);
316 heap_free(cur->u.regular.glyphs);
317 heap_free(cur->u.regular.clustermap);
318 heap_free(cur->u.regular.advances);
319 heap_free(cur->u.regular.offsets);
321 heap_free(cur);
325 static void free_layout_eruns(struct dwrite_textlayout *layout)
327 struct layout_effective_run *cur, *cur2;
328 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->eruns, struct layout_effective_run, entry) {
329 list_remove(&cur->entry);
330 heap_free(cur->clustermap);
331 heap_free(cur);
335 /* Used to resolve break condition by forcing stronger condition over weaker. */
336 static inline DWRITE_BREAK_CONDITION override_break_condition(DWRITE_BREAK_CONDITION existingbreak, DWRITE_BREAK_CONDITION newbreak)
338 switch (existingbreak) {
339 case DWRITE_BREAK_CONDITION_NEUTRAL:
340 return newbreak;
341 case DWRITE_BREAK_CONDITION_CAN_BREAK:
342 return newbreak == DWRITE_BREAK_CONDITION_NEUTRAL ? existingbreak : newbreak;
343 /* let's keep stronger conditions as is */
344 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK:
345 case DWRITE_BREAK_CONDITION_MUST_BREAK:
346 break;
347 default:
348 ERR("unknown break condition %d\n", existingbreak);
351 return existingbreak;
354 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
355 static HRESULT layout_update_breakpoints_range(struct dwrite_textlayout *layout, const struct layout_range *cur)
357 DWRITE_BREAK_CONDITION before, after;
358 HRESULT hr;
359 UINT32 i;
361 hr = IDWriteInlineObject_GetBreakConditions(cur->object, &before, &after);
362 if (FAILED(hr))
363 return hr;
365 if (!layout->actual_breakpoints) {
366 layout->actual_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
367 if (!layout->actual_breakpoints)
368 return E_OUTOFMEMORY;
370 memcpy(layout->actual_breakpoints, layout->nominal_breakpoints, sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
372 for (i = cur->range.startPosition; i < cur->range.length + cur->range.startPosition; i++) {
373 UINT32 j = i + cur->range.startPosition;
374 if (i == 0) {
375 if (j)
376 layout->actual_breakpoints[j].breakConditionBefore = layout->actual_breakpoints[j-1].breakConditionAfter =
377 override_break_condition(layout->actual_breakpoints[j-1].breakConditionAfter, before);
378 else
379 layout->actual_breakpoints[j].breakConditionBefore = before;
381 layout->actual_breakpoints[j].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
384 layout->actual_breakpoints[j].isWhitespace = 0;
385 layout->actual_breakpoints[j].isSoftHyphen = 0;
387 if (i == cur->range.length - 1) {
388 layout->actual_breakpoints[j].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
389 if (j < layout->len - 1)
390 layout->actual_breakpoints[j].breakConditionAfter = layout->actual_breakpoints[j+1].breakConditionAfter =
391 override_break_condition(layout->actual_breakpoints[j+1].breakConditionAfter, before);
392 else
393 layout->actual_breakpoints[j].breakConditionAfter = before;
397 return S_OK;
400 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos);
402 static inline DWRITE_LINE_BREAKPOINT get_effective_breakpoint(const struct dwrite_textlayout *layout, UINT32 pos)
404 if (layout->actual_breakpoints)
405 return layout->actual_breakpoints[pos];
406 return layout->nominal_breakpoints[pos];
409 static inline void init_cluster_metrics(const struct dwrite_textlayout *layout, const struct regular_layout_run *run,
410 UINT16 start_glyph, UINT16 stop_glyph, UINT32 stop_position, DWRITE_CLUSTER_METRICS *metrics)
412 UINT8 breakcondition;
413 UINT32 position;
414 UINT16 j;
416 metrics->width = 0.0;
417 for (j = start_glyph; j < stop_glyph; j++)
418 metrics->width += run->run.glyphAdvances[j];
419 metrics->length = 0;
421 position = stop_position;
422 if (stop_glyph == run->run.glyphCount)
423 breakcondition = get_effective_breakpoint(layout, stop_position).breakConditionAfter;
424 else {
425 breakcondition = get_effective_breakpoint(layout, stop_position).breakConditionBefore;
426 if (stop_position) position = stop_position - 1;
429 metrics->canWrapLineAfter = breakcondition == DWRITE_BREAK_CONDITION_CAN_BREAK ||
430 breakcondition == DWRITE_BREAK_CONDITION_MUST_BREAK;
431 if (metrics->length == 1) {
432 WORD type;
434 GetStringTypeW(CT_CTYPE1, &layout->str[position], 1, &type);
435 metrics->isWhitespace = type == C1_SPACE;
436 metrics->isNewline = FALSE /* FIXME */;
437 metrics->isSoftHyphen = layout->str[position] == 0x00ad /* Unicode Soft Hyphen */;
439 else {
440 metrics->isWhitespace = FALSE;
441 metrics->isNewline = FALSE;
442 metrics->isSoftHyphen = FALSE;
444 metrics->isRightToLeft = run->run.bidiLevel & 1;
445 metrics->padding = 0;
450 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
451 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
452 Note that there's no need to reallocate anything at this point as we allocate one cluster per
453 codepoint initially.
456 static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 *cluster)
458 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[*cluster];
459 struct layout_cluster *c = &layout->clusters[*cluster];
460 const struct regular_layout_run *run = &r->u.regular;
461 UINT32 i, start = 0;
463 for (i = 0; i < run->descr.stringLength; i++) {
464 BOOL end = i == run->descr.stringLength - 1;
466 if (run->descr.clusterMap[start] != run->descr.clusterMap[i]) {
467 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->descr.clusterMap[i], i, metrics);
468 metrics->length = i - start;
469 c->position = start;
470 c->run = r;
472 *cluster += 1;
473 metrics++;
474 c++;
475 start = i;
478 if (end) {
479 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->run.glyphCount, i, metrics);
480 metrics->length = i - start + 1;
481 c->position = start;
482 c->run = r;
484 *cluster += 1;
485 return;
490 static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
492 IDWriteTextAnalyzer *analyzer;
493 struct layout_range *range;
494 struct layout_run *r;
495 UINT32 cluster = 0;
496 HRESULT hr;
498 free_layout_runs(layout);
500 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
501 if (!layout->clustermetrics) {
502 layout->clustermetrics = heap_alloc(layout->len*sizeof(*layout->clustermetrics));
503 layout->clusters = heap_alloc(layout->len*sizeof(*layout->clusters));
504 if (!layout->clustermetrics || !layout->clusters) {
505 heap_free(layout->clustermetrics);
506 heap_free(layout->clusters);
507 return E_OUTOFMEMORY;
510 layout->cluster_count = 0;
512 hr = get_textanalyzer(&analyzer);
513 if (FAILED(hr))
514 return hr;
516 LIST_FOR_EACH_ENTRY(range, &layout->ranges, struct layout_range, entry) {
517 /* inline objects override actual text in a range */
518 if (range->object) {
519 hr = layout_update_breakpoints_range(layout, range);
520 if (FAILED(hr))
521 return hr;
523 r = alloc_layout_run(LAYOUT_RUN_INLINE);
524 if (!r)
525 return E_OUTOFMEMORY;
527 r->u.object.object = range->object;
528 r->u.object.length = range->range.length;
529 list_add_tail(&layout->runs, &r->entry);
530 continue;
533 /* initial splitting by script */
534 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, &layout->IDWriteTextAnalysisSource_iface,
535 range->range.startPosition, range->range.length, &layout->IDWriteTextAnalysisSink_iface);
536 if (FAILED(hr))
537 break;
539 /* this splits it further */
540 hr = IDWriteTextAnalyzer_AnalyzeBidi(analyzer, &layout->IDWriteTextAnalysisSource_iface,
541 range->range.startPosition, range->range.length, &layout->IDWriteTextAnalysisSink_iface);
542 if (FAILED(hr))
543 break;
546 /* fill run info */
547 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
548 DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props = NULL;
549 DWRITE_SHAPING_TEXT_PROPERTIES *text_props = NULL;
550 struct regular_layout_run *run = &r->u.regular;
551 IDWriteFontFamily *family;
552 UINT32 index, max_count;
553 IDWriteFont *font;
554 BOOL exists = TRUE;
556 /* we need to do very little in case of inline objects */
557 if (r->kind == LAYOUT_RUN_INLINE) {
558 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[cluster];
559 struct layout_cluster *c = &layout->clusters[cluster];
560 DWRITE_INLINE_OBJECT_METRICS inlinemetrics;
562 metrics->width = 0.0;
563 metrics->length = r->u.object.length;
564 metrics->canWrapLineAfter = FALSE;
565 metrics->isWhitespace = FALSE;
566 metrics->isNewline = FALSE;
567 metrics->isSoftHyphen = FALSE;
568 metrics->isRightToLeft = FALSE;
569 metrics->padding = 0;
570 c->run = r;
571 c->position = 0; /* there's always one cluster per inline object, so 0 is valid value */
572 cluster++;
574 /* TODO: is it fatal if GetMetrics() fails? */
575 hr = IDWriteInlineObject_GetMetrics(r->u.object.object, &inlinemetrics);
576 if (FAILED(hr)) {
577 FIXME("failed to get inline object metrics, 0x%08x\n", hr);
578 continue;
580 metrics->width = inlinemetrics.width;
582 /* FIXME: use resolved breakpoints in this case too */
584 continue;
587 range = get_layout_range_by_pos(layout, run->descr.textPosition);
589 hr = IDWriteFontCollection_FindFamilyName(range->collection, range->fontfamily, &index, &exists);
590 if (FAILED(hr) || !exists) {
591 WARN("%s: family %s not found in collection %p\n", debugstr_run(run), debugstr_w(range->fontfamily), range->collection);
592 continue;
595 hr = IDWriteFontCollection_GetFontFamily(range->collection, index, &family);
596 if (FAILED(hr))
597 continue;
599 hr = IDWriteFontFamily_GetFirstMatchingFont(family, range->weight, range->stretch, range->style, &font);
600 IDWriteFontFamily_Release(family);
601 if (FAILED(hr)) {
602 WARN("%s: failed to get a matching font\n", debugstr_run(run));
603 continue;
606 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
607 IDWriteFont_Release(font);
608 if (FAILED(hr))
609 continue;
611 run->run.fontEmSize = range->fontsize;
612 run->descr.localeName = range->locale;
613 run->clustermap = heap_alloc(run->descr.stringLength*sizeof(UINT16));
615 max_count = 3*run->descr.stringLength/2 + 16;
616 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
617 if (!run->clustermap || !run->glyphs)
618 goto memerr;
620 text_props = heap_alloc(run->descr.stringLength*sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
621 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
622 if (!text_props || !glyph_props)
623 goto memerr;
625 while (1) {
626 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, run->descr.string, run->descr.stringLength,
627 run->run.fontFace, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
628 NULL /* FIXME */, NULL, NULL, 0, max_count, run->clustermap, text_props, run->glyphs, glyph_props,
629 &run->run.glyphCount);
630 if (hr == E_NOT_SUFFICIENT_BUFFER) {
631 heap_free(run->glyphs);
632 heap_free(glyph_props);
634 max_count = run->run.glyphCount;
636 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
637 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
638 if (!run->glyphs || !glyph_props)
639 goto memerr;
641 continue;
644 break;
647 if (FAILED(hr)) {
648 heap_free(text_props);
649 heap_free(glyph_props);
650 WARN("%s: shaping failed 0x%08x\n", debugstr_run(run), hr);
651 continue;
654 run->run.glyphIndices = run->glyphs;
655 run->descr.clusterMap = run->clustermap;
657 run->advances = heap_alloc(run->run.glyphCount*sizeof(FLOAT));
658 run->offsets = heap_alloc(run->run.glyphCount*sizeof(DWRITE_GLYPH_OFFSET));
659 if (!run->advances || !run->offsets)
660 goto memerr;
662 /* now set advances and offsets */
663 if (layout->gdicompatible)
664 hr = IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap,
665 text_props, run->descr.stringLength, run->run.glyphIndices, glyph_props, run->run.glyphCount,
666 run->run.fontFace, run->run.fontEmSize, layout->pixels_per_dip, &layout->transform, layout->use_gdi_natural,
667 run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL, NULL, 0,
668 run->advances, run->offsets);
669 else
670 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap, text_props,
671 run->descr.stringLength, run->run.glyphIndices, glyph_props, run->run.glyphCount, run->run.fontFace,
672 run->run.fontEmSize, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
673 NULL, NULL, 0, run->advances, run->offsets);
675 heap_free(text_props);
676 heap_free(glyph_props);
677 if (FAILED(hr))
678 WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_run(run), hr);
680 run->run.glyphAdvances = run->advances;
681 run->run.glyphOffsets = run->offsets;
683 layout_set_cluster_metrics(layout, r, &cluster);
685 continue;
687 memerr:
688 heap_free(text_props);
689 heap_free(glyph_props);
690 heap_free(run->clustermap);
691 heap_free(run->glyphs);
692 heap_free(run->advances);
693 heap_free(run->offsets);
694 run->advances = NULL;
695 run->offsets = NULL;
696 run->clustermap = run->glyphs = NULL;
697 hr = E_OUTOFMEMORY;
698 break;
701 if (hr == S_OK)
702 layout->cluster_count = cluster;
704 IDWriteTextAnalyzer_Release(analyzer);
705 return hr;
708 static HRESULT layout_compute(struct dwrite_textlayout *layout)
710 HRESULT hr;
712 if (!(layout->recompute & RECOMPUTE_NOMINAL_RUNS))
713 return S_OK;
715 /* nominal breakpoints are evaluated only once, because string never changes */
716 if (!layout->nominal_breakpoints) {
717 IDWriteTextAnalyzer *analyzer;
718 HRESULT hr;
720 layout->nominal_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
721 if (!layout->nominal_breakpoints)
722 return E_OUTOFMEMORY;
724 hr = get_textanalyzer(&analyzer);
725 if (FAILED(hr))
726 return hr;
728 hr = IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer, &layout->IDWriteTextAnalysisSource_iface,
729 0, layout->len, &layout->IDWriteTextAnalysisSink_iface);
730 IDWriteTextAnalyzer_Release(analyzer);
732 if (layout->actual_breakpoints) {
733 heap_free(layout->actual_breakpoints);
734 layout->actual_breakpoints = NULL;
737 hr = layout_compute_runs(layout);
739 if (TRACE_ON(dwrite)) {
740 struct layout_run *cur;
742 LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
743 if (cur->kind == LAYOUT_RUN_INLINE)
744 TRACE("run inline object %p, len %u\n", cur->u.object.object, cur->u.object.length);
745 else
746 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur->u.regular.descr.textPosition, cur->u.regular.descr.textPosition +
747 cur->u.regular.descr.stringLength-1, cur->u.regular.descr.stringLength, cur->u.regular.run.bidiLevel);
751 layout->recompute &= ~RECOMPUTE_NOMINAL_RUNS;
752 return hr;
755 static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 start,
756 UINT32 length, FLOAT origin_x)
758 struct layout_effective_run *run;
759 UINT32 i;
761 run = heap_alloc(sizeof(*run));
762 if (!run)
763 return E_OUTOFMEMORY;
765 run->clustermap = heap_alloc(sizeof(UINT16)*length);
766 if (!run->clustermap) {
767 heap_free(run);
768 return E_OUTOFMEMORY;
771 run->run = r;
772 run->start = start;
773 run->length = length;
774 run->origin_x = origin_x;
775 run->origin_y = 0.0; /* FIXME: set after line is built */
777 /* trim from the left */
778 run->glyphcount = r->u.regular.run.glyphCount - r->u.regular.clustermap[start];
779 /* trim from the right */
780 if (length < r->u.regular.descr.stringLength)
781 run->glyphcount -= r->u.regular.clustermap[start + length];
783 /* cluster map needs to be shifted */
784 for (i = 0; i < length; i++)
785 run->clustermap[i] = r->u.regular.clustermap[start] - start;
787 list_add_tail(&layout->eruns, &run->entry);
788 return S_OK;
791 static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_LINE_METRICS *metrics, UINT32 *line)
793 if (!layout->line_alloc) {
794 layout->line_alloc = 5;
795 layout->lines = heap_alloc(layout->line_alloc*sizeof(*layout->lines));
796 if (!layout->lines)
797 return E_OUTOFMEMORY;
800 if (layout->line_count == layout->line_alloc) {
801 DWRITE_LINE_METRICS *l = heap_realloc(layout->lines, layout->line_alloc*2*sizeof(*layout->lines));
802 if (!l)
803 return E_OUTOFMEMORY;
804 layout->lines = l;
805 layout->line_alloc *= 2;
808 layout->lines[*line] = *metrics;
809 *line += 1;
810 return S_OK;
813 static inline FLOAT get_cluster_range_width(struct dwrite_textlayout *layout, UINT32 start, UINT32 end)
815 FLOAT width = 0.0;
816 for (; start < end; start++)
817 width += layout->clustermetrics[start].width;
818 return width;
821 static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
823 DWRITE_LINE_METRICS metrics;
824 const struct layout_run *run;
825 FLOAT width, origin_x;
826 UINT32 i, start, line;
827 BOOL can_wrap_after;
828 HRESULT hr;
830 if (!(layout->recompute & RECOMPUTE_EFFECTIVE_RUNS))
831 return S_OK;
833 hr = layout_compute(layout);
834 if (FAILED(hr))
835 return hr;
837 layout->line_count = 0;
838 origin_x = 0.0;
839 line = 0;
840 run = layout->clusters[0].run;
841 can_wrap_after = layout->clustermetrics[0].canWrapLineAfter;
842 memset(&metrics, 0, sizeof(metrics));
844 for (i = 0, start = 0, width = 0.0; i < layout->cluster_count; i++) {
845 if (run != layout->clusters[i].run) {
846 /* switched to next nominal run */
847 hr = layout_add_effective_run(layout, run, start, i - start, origin_x);
848 if (FAILED(hr))
849 return hr;
850 origin_x += get_cluster_range_width(layout, start, i);
851 start = i;
854 /* check if we got new line */
855 if (((can_wrap_after && (width + layout->clustermetrics[i].width > layout->maxwidth)) ||
856 layout->clustermetrics[i].isNewline || /* always wrap on new line */
857 i == layout->cluster_count - 1)) /* end of the text */ {
859 UINT32 strlength = metrics.length, index = i;
861 if (i > start) {
862 hr = layout_add_effective_run(layout, run, start, i - start, origin_x);
863 if (FAILED(hr))
864 return hr;
865 /* we don't need to update origin for next run as we're going to wrap */
868 /* take a look at clusters we got for this line in reverse order */
869 while (strlength) {
870 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
872 if (!cluster->isNewline && !cluster->isWhitespace)
873 break;
875 if (cluster->isNewline) {
876 metrics.trailingWhitespaceLength += cluster->length;
877 metrics.newlineLength += cluster->length;
880 if (cluster->isWhitespace)
881 metrics.trailingWhitespaceLength += cluster->length;
883 strlength -= cluster->length;
884 index--;
887 metrics.height = 0.0; /* FIXME */
888 metrics.baseline = 0.0; /* FIXME */
889 metrics.isTrimmed = width > layout->maxwidth;
890 hr = layout_set_line_metrics(layout, &metrics, &line);
891 if (FAILED(hr))
892 return hr;
894 width = layout->clustermetrics[i].width;
895 memset(&metrics, 0, sizeof(metrics));
896 origin_x = 0.0;
897 start = i;
899 else {
900 metrics.length += layout->clustermetrics[i].length;
901 width += layout->clustermetrics[i].width;
904 can_wrap_after = layout->clustermetrics[i].canWrapLineAfter;
907 layout->line_count = line;
908 layout->recompute &= ~RECOMPUTE_EFFECTIVE_RUNS;
909 return hr;
912 /* To be used in IDWriteTextLayout methods to validate and fix passed range */
913 static inline BOOL validate_text_range(struct dwrite_textlayout *layout, DWRITE_TEXT_RANGE *r)
915 if (r->startPosition >= layout->len)
916 return FALSE;
918 if (r->startPosition + r->length > layout->len)
919 r->length = layout->len - r->startPosition;
921 return TRUE;
924 static BOOL is_same_layout_attrvalue(struct layout_range const *range, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
926 switch (attr) {
927 case LAYOUT_RANGE_ATTR_WEIGHT:
928 return range->weight == value->u.weight;
929 case LAYOUT_RANGE_ATTR_STYLE:
930 return range->style == value->u.style;
931 case LAYOUT_RANGE_ATTR_STRETCH:
932 return range->stretch == value->u.stretch;
933 case LAYOUT_RANGE_ATTR_FONTSIZE:
934 return range->fontsize == value->u.fontsize;
935 case LAYOUT_RANGE_ATTR_INLINE:
936 return range->object == value->u.object;
937 case LAYOUT_RANGE_ATTR_EFFECT:
938 return range->effect == value->u.effect;
939 case LAYOUT_RANGE_ATTR_UNDERLINE:
940 return range->underline == value->u.underline;
941 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
942 return range->strikethrough == value->u.strikethrough;
943 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
944 return range->pair_kerning == value->u.pair_kerning;
945 case LAYOUT_RANGE_ATTR_FONTCOLL:
946 return range->collection == value->u.collection;
947 case LAYOUT_RANGE_ATTR_LOCALE:
948 return strcmpW(range->locale, value->u.locale) == 0;
949 case LAYOUT_RANGE_ATTR_FONTFAMILY:
950 return strcmpW(range->fontfamily, value->u.fontfamily) == 0;
951 default:
955 return FALSE;
958 static inline BOOL is_same_layout_attributes(struct layout_range const *left, struct layout_range const *right)
960 return left->weight == right->weight &&
961 left->style == right->style &&
962 left->stretch == right->stretch &&
963 left->fontsize == right->fontsize &&
964 left->object == right->object &&
965 left->effect == right->effect &&
966 left->underline == right->underline &&
967 left->strikethrough == right->strikethrough &&
968 left->pair_kerning == right->pair_kerning &&
969 left->collection == right->collection &&
970 !strcmpW(left->locale, right->locale) &&
971 !strcmpW(left->fontfamily, right->fontfamily);
974 static inline BOOL is_same_text_range(const DWRITE_TEXT_RANGE *left, const DWRITE_TEXT_RANGE *right)
976 return left->startPosition == right->startPosition && left->length == right->length;
979 /* Allocates range and inits it with default values from text format. */
980 static struct layout_range *alloc_layout_range(struct dwrite_textlayout *layout, const DWRITE_TEXT_RANGE *r)
982 struct layout_range *range;
984 range = heap_alloc(sizeof(*range));
985 if (!range) return NULL;
987 range->range = *r;
988 range->weight = layout->format.weight;
989 range->style = layout->format.style;
990 range->stretch = layout->format.stretch;
991 range->fontsize = layout->format.fontsize;
992 range->object = NULL;
993 range->effect = NULL;
994 range->underline = FALSE;
995 range->strikethrough = FALSE;
996 range->pair_kerning = FALSE;
998 range->fontfamily = heap_strdupW(layout->format.family_name);
999 if (!range->fontfamily) {
1000 heap_free(range);
1001 return NULL;
1004 range->collection = layout->format.collection;
1005 if (range->collection)
1006 IDWriteFontCollection_AddRef(range->collection);
1007 strcpyW(range->locale, layout->format.locale);
1009 return range;
1012 static struct layout_range *alloc_layout_range_from(struct layout_range *from, const DWRITE_TEXT_RANGE *r)
1014 struct layout_range *range;
1016 range = heap_alloc(sizeof(*range));
1017 if (!range) return NULL;
1019 *range = *from;
1020 range->range = *r;
1022 range->fontfamily = heap_strdupW(from->fontfamily);
1023 if (!range->fontfamily) {
1024 heap_free(range);
1025 return NULL;
1028 /* update refcounts */
1029 if (range->object)
1030 IDWriteInlineObject_AddRef(range->object);
1031 if (range->effect)
1032 IUnknown_AddRef(range->effect);
1033 if (range->collection)
1034 IDWriteFontCollection_AddRef(range->collection);
1036 return range;
1039 static void free_layout_range(struct layout_range *range)
1041 if (!range)
1042 return;
1043 if (range->object)
1044 IDWriteInlineObject_Release(range->object);
1045 if (range->effect)
1046 IUnknown_Release(range->effect);
1047 if (range->collection)
1048 IDWriteFontCollection_Release(range->collection);
1049 heap_free(range->fontfamily);
1050 heap_free(range);
1053 static void free_layout_ranges_list(struct dwrite_textlayout *layout)
1055 struct layout_range *cur, *cur2;
1056 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->ranges, struct layout_range, entry) {
1057 list_remove(&cur->entry);
1058 free_layout_range(cur);
1062 static struct layout_range *find_outer_range(struct dwrite_textlayout *layout, const DWRITE_TEXT_RANGE *range)
1064 struct layout_range *cur;
1066 LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, entry) {
1068 if (cur->range.startPosition > range->startPosition)
1069 return NULL;
1071 if ((cur->range.startPosition + cur->range.length < range->startPosition + range->length) &&
1072 (range->startPosition < cur->range.startPosition + cur->range.length))
1073 return NULL;
1074 if (cur->range.startPosition + cur->range.length >= range->startPosition + range->length)
1075 return cur;
1078 return NULL;
1081 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos)
1083 struct layout_range *cur;
1085 LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, entry) {
1086 DWRITE_TEXT_RANGE *r = &cur->range;
1087 if (r->startPosition <= pos && pos < r->startPosition + r->length)
1088 return cur;
1091 return NULL;
1094 static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
1096 if (*dest == value) return FALSE;
1098 if (*dest)
1099 IUnknown_Release(*dest);
1100 *dest = value;
1101 if (*dest)
1102 IUnknown_AddRef(*dest);
1104 return TRUE;
1107 static BOOL set_layout_range_attrval(struct layout_range *dest, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
1109 BOOL changed = FALSE;
1111 switch (attr) {
1112 case LAYOUT_RANGE_ATTR_WEIGHT:
1113 changed = dest->weight != value->u.weight;
1114 dest->weight = value->u.weight;
1115 break;
1116 case LAYOUT_RANGE_ATTR_STYLE:
1117 changed = dest->style != value->u.style;
1118 dest->style = value->u.style;
1119 break;
1120 case LAYOUT_RANGE_ATTR_STRETCH:
1121 changed = dest->stretch != value->u.stretch;
1122 dest->stretch = value->u.stretch;
1123 break;
1124 case LAYOUT_RANGE_ATTR_FONTSIZE:
1125 changed = dest->fontsize != value->u.fontsize;
1126 dest->fontsize = value->u.fontsize;
1127 break;
1128 case LAYOUT_RANGE_ATTR_INLINE:
1129 changed = set_layout_range_iface_attr((IUnknown**)&dest->object, (IUnknown*)value->u.object);
1130 break;
1131 case LAYOUT_RANGE_ATTR_EFFECT:
1132 changed = set_layout_range_iface_attr((IUnknown**)&dest->effect, (IUnknown*)value->u.effect);
1133 break;
1134 case LAYOUT_RANGE_ATTR_UNDERLINE:
1135 changed = dest->underline != value->u.underline;
1136 dest->underline = value->u.underline;
1137 break;
1138 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
1139 changed = dest->strikethrough != value->u.strikethrough;
1140 dest->strikethrough = value->u.strikethrough;
1141 break;
1142 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
1143 changed = dest->pair_kerning != value->u.pair_kerning;
1144 dest->pair_kerning = value->u.pair_kerning;
1145 break;
1146 case LAYOUT_RANGE_ATTR_FONTCOLL:
1147 changed = set_layout_range_iface_attr((IUnknown**)&dest->collection, (IUnknown*)value->u.collection);
1148 break;
1149 case LAYOUT_RANGE_ATTR_LOCALE:
1150 changed = strcmpW(dest->locale, value->u.locale) != 0;
1151 if (changed)
1152 strcpyW(dest->locale, value->u.locale);
1153 break;
1154 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1155 changed = strcmpW(dest->fontfamily, value->u.fontfamily) != 0;
1156 if (changed) {
1157 heap_free(dest->fontfamily);
1158 dest->fontfamily = heap_strdupW(value->u.fontfamily);
1160 break;
1161 default:
1165 return changed;
1168 static inline BOOL is_in_layout_range(const DWRITE_TEXT_RANGE *outer, const DWRITE_TEXT_RANGE *inner)
1170 return (inner->startPosition >= outer->startPosition) &&
1171 (inner->startPosition + inner->length <= outer->startPosition + outer->length);
1174 static inline HRESULT return_range(const struct layout_range *range, DWRITE_TEXT_RANGE *r)
1176 if (r) *r = range->range;
1177 return S_OK;
1180 /* Set attribute value for given range, does all needed splitting/merging of existing ranges. */
1181 static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
1183 struct layout_range *outer, *right, *left, *cur;
1184 struct list *ranges = &layout->ranges;
1185 BOOL changed = FALSE;
1186 DWRITE_TEXT_RANGE r;
1188 if (!validate_text_range(layout, &value->range))
1189 return S_OK;
1191 /* If new range is completely within existing range, split existing range in two */
1192 if ((outer = find_outer_range(layout, &value->range))) {
1194 /* no need to add same range */
1195 if (is_same_layout_attrvalue(outer, attr, value))
1196 return S_OK;
1198 /* for matching range bounds just replace data */
1199 if (is_same_text_range(&outer->range, &value->range)) {
1200 changed = set_layout_range_attrval(outer, attr, value);
1201 goto done;
1204 /* add new range to the left */
1205 if (value->range.startPosition == outer->range.startPosition) {
1206 left = alloc_layout_range_from(outer, &value->range);
1207 if (!left) return E_OUTOFMEMORY;
1209 changed = set_layout_range_attrval(left, attr, value);
1210 list_add_before(&outer->entry, &left->entry);
1211 outer->range.startPosition += value->range.length;
1212 outer->range.length -= value->range.length;
1213 goto done;
1216 /* add new range to the right */
1217 if (value->range.startPosition + value->range.length == outer->range.startPosition + outer->range.length) {
1218 right = alloc_layout_range_from(outer, &value->range);
1219 if (!right) return E_OUTOFMEMORY;
1221 changed = set_layout_range_attrval(right, attr, value);
1222 list_add_after(&outer->entry, &right->entry);
1223 outer->range.length -= value->range.length;
1224 goto done;
1227 r.startPosition = value->range.startPosition + value->range.length;
1228 r.length = outer->range.length + outer->range.startPosition - r.startPosition;
1230 /* right part */
1231 right = alloc_layout_range_from(outer, &r);
1232 /* new range in the middle */
1233 cur = alloc_layout_range_from(outer, &value->range);
1234 if (!right || !cur) {
1235 free_layout_range(right);
1236 free_layout_range(cur);
1237 return E_OUTOFMEMORY;
1240 /* reuse container range as a left part */
1241 outer->range.length = value->range.startPosition - outer->range.startPosition;
1243 /* new part */
1244 set_layout_range_attrval(cur, attr, value);
1246 list_add_after(&outer->entry, &cur->entry);
1247 list_add_after(&cur->entry, &right->entry);
1249 return S_OK;
1252 /* Now it's only possible that given range contains some existing ranges, fully or partially.
1253 Update all of them. */
1254 left = get_layout_range_by_pos(layout, value->range.startPosition);
1255 if (left->range.startPosition == value->range.startPosition)
1256 changed = set_layout_range_attrval(left, attr, value);
1257 else /* need to split */ {
1258 r.startPosition = value->range.startPosition;
1259 r.length = left->range.length - value->range.startPosition + left->range.startPosition;
1260 left->range.length -= r.length;
1261 cur = alloc_layout_range_from(left, &r);
1262 changed = set_layout_range_attrval(cur, attr, value);
1263 list_add_after(&left->entry, &cur->entry);
1265 cur = LIST_ENTRY(list_next(ranges, &left->entry), struct layout_range, entry);
1267 /* for all existing ranges covered by new one update value */
1268 while (is_in_layout_range(&value->range, &cur->range)) {
1269 changed = set_layout_range_attrval(cur, attr, value);
1270 cur = LIST_ENTRY(list_next(ranges, &cur->entry), struct layout_range, entry);
1273 /* it's possible rightmost range intersects */
1274 if (cur && (cur->range.startPosition < value->range.startPosition + value->range.length)) {
1275 r.startPosition = cur->range.startPosition;
1276 r.length = value->range.startPosition + value->range.length - cur->range.startPosition;
1277 left = alloc_layout_range_from(cur, &r);
1278 changed = set_layout_range_attrval(left, attr, value);
1279 cur->range.startPosition += left->range.length;
1280 cur->range.length -= left->range.length;
1281 list_add_before(&cur->entry, &left->entry);
1284 done:
1285 if (changed) {
1286 struct list *next, *i;
1288 layout->recompute = RECOMPUTE_EVERYTHING;
1289 i = list_head(ranges);
1290 while ((next = list_next(ranges, i))) {
1291 struct layout_range *next_range = LIST_ENTRY(next, struct layout_range, entry);
1293 cur = LIST_ENTRY(i, struct layout_range, entry);
1294 if (is_same_layout_attributes(cur, next_range)) {
1295 /* remove similar range */
1296 cur->range.length += next_range->range.length;
1297 list_remove(next);
1298 free_layout_range(next_range);
1300 else
1301 i = list_next(ranges, i);
1305 return S_OK;
1308 static inline const WCHAR *get_string_attribute_ptr(struct layout_range *range, enum layout_range_attr_kind kind)
1310 const WCHAR *str;
1312 switch (kind) {
1313 case LAYOUT_RANGE_ATTR_LOCALE:
1314 str = range->locale;
1315 break;
1316 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1317 str = range->fontfamily;
1318 break;
1319 default:
1320 str = NULL;
1323 return str;
1326 static HRESULT get_string_attribute_length(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
1327 UINT32 *length, DWRITE_TEXT_RANGE *r)
1329 struct layout_range *range;
1330 const WCHAR *str;
1332 range = get_layout_range_by_pos(layout, position);
1333 if (!range) {
1334 *length = 0;
1335 return S_OK;
1338 str = get_string_attribute_ptr(range, kind);
1339 *length = strlenW(str);
1340 return return_range(range, r);
1343 static HRESULT get_string_attribute_value(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
1344 WCHAR *ret, UINT32 length, DWRITE_TEXT_RANGE *r)
1346 struct layout_range *range;
1347 const WCHAR *str;
1349 if (length == 0)
1350 return E_INVALIDARG;
1352 ret[0] = 0;
1353 range = get_layout_range_by_pos(layout, position);
1354 if (!range)
1355 return E_INVALIDARG;
1357 str = get_string_attribute_ptr(range, kind);
1358 if (length < strlenW(str) + 1)
1359 return E_NOT_SUFFICIENT_BUFFER;
1361 strcpyW(ret, str);
1362 return return_range(range, r);
1365 static HRESULT WINAPI dwritetextlayout_QueryInterface(IDWriteTextLayout2 *iface, REFIID riid, void **obj)
1367 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1369 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1371 *obj = NULL;
1373 if (IsEqualIID(riid, &IID_IDWriteTextLayout2) ||
1374 IsEqualIID(riid, &IID_IDWriteTextLayout1) ||
1375 IsEqualIID(riid, &IID_IDWriteTextLayout) ||
1376 IsEqualIID(riid, &IID_IUnknown))
1378 *obj = iface;
1380 else if (IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
1381 IsEqualIID(riid, &IID_IDWriteTextFormat))
1382 *obj = &This->IDWriteTextFormat1_iface;
1384 if (*obj) {
1385 IDWriteTextLayout2_AddRef(iface);
1386 return S_OK;
1389 return E_NOINTERFACE;
1392 static ULONG WINAPI dwritetextlayout_AddRef(IDWriteTextLayout2 *iface)
1394 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1395 ULONG ref = InterlockedIncrement(&This->ref);
1396 TRACE("(%p)->(%d)\n", This, ref);
1397 return ref;
1400 static ULONG WINAPI dwritetextlayout_Release(IDWriteTextLayout2 *iface)
1402 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1403 ULONG ref = InterlockedDecrement(&This->ref);
1405 TRACE("(%p)->(%d)\n", This, ref);
1407 if (!ref) {
1408 free_layout_ranges_list(This);
1409 free_layout_eruns(This);
1410 free_layout_runs(This);
1411 release_format_data(&This->format);
1412 heap_free(This->nominal_breakpoints);
1413 heap_free(This->actual_breakpoints);
1414 heap_free(This->clustermetrics);
1415 heap_free(This->clusters);
1416 heap_free(This->lines);
1417 heap_free(This->str);
1418 heap_free(This);
1421 return ref;
1424 static HRESULT WINAPI dwritetextlayout_SetTextAlignment(IDWriteTextLayout2 *iface, DWRITE_TEXT_ALIGNMENT alignment)
1426 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1427 TRACE("(%p)->(%d)\n", This, alignment);
1428 return IDWriteTextFormat1_SetTextAlignment(&This->IDWriteTextFormat1_iface, alignment);
1431 static HRESULT WINAPI dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout2 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
1433 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1434 TRACE("(%p)->(%d)\n", This, alignment);
1435 return IDWriteTextFormat1_SetParagraphAlignment(&This->IDWriteTextFormat1_iface, alignment);
1438 static HRESULT WINAPI dwritetextlayout_SetWordWrapping(IDWriteTextLayout2 *iface, DWRITE_WORD_WRAPPING wrapping)
1440 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1441 TRACE("(%p)->(%d)\n", This, wrapping);
1442 return IDWriteTextFormat1_SetWordWrapping(&This->IDWriteTextFormat1_iface, wrapping);
1445 static HRESULT WINAPI dwritetextlayout_SetReadingDirection(IDWriteTextLayout2 *iface, DWRITE_READING_DIRECTION direction)
1447 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1448 TRACE("(%p)->(%d)\n", This, direction);
1449 return IDWriteTextFormat1_SetReadingDirection(&This->IDWriteTextFormat1_iface, direction);
1452 static HRESULT WINAPI dwritetextlayout_SetFlowDirection(IDWriteTextLayout2 *iface, DWRITE_FLOW_DIRECTION direction)
1454 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1455 TRACE("(%p)->(%d)\n", This, direction);
1456 return IDWriteTextFormat1_SetFlowDirection(&This->IDWriteTextFormat1_iface, direction);
1459 static HRESULT WINAPI dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout2 *iface, FLOAT tabstop)
1461 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1462 TRACE("(%p)->(%.2f)\n", This, tabstop);
1463 return IDWriteTextFormat1_SetIncrementalTabStop(&This->IDWriteTextFormat1_iface, tabstop);
1466 static HRESULT WINAPI dwritetextlayout_SetTrimming(IDWriteTextLayout2 *iface, DWRITE_TRIMMING const *trimming,
1467 IDWriteInlineObject *trimming_sign)
1469 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1470 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
1471 return IDWriteTextFormat1_SetTrimming(&This->IDWriteTextFormat1_iface, trimming, trimming_sign);
1474 static HRESULT WINAPI dwritetextlayout_SetLineSpacing(IDWriteTextLayout2 *iface, DWRITE_LINE_SPACING_METHOD spacing,
1475 FLOAT line_spacing, FLOAT baseline)
1477 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1478 TRACE("(%p)->(%d %.2f %.2f)\n", This, spacing, line_spacing, baseline);
1479 return IDWriteTextFormat1_SetLineSpacing(&This->IDWriteTextFormat1_iface, spacing, line_spacing, baseline);
1482 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextlayout_GetTextAlignment(IDWriteTextLayout2 *iface)
1484 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1485 TRACE("(%p)\n", This);
1486 return IDWriteTextFormat1_GetTextAlignment(&This->IDWriteTextFormat1_iface);
1489 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout2 *iface)
1491 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1492 TRACE("(%p)\n", This);
1493 return IDWriteTextFormat1_GetParagraphAlignment(&This->IDWriteTextFormat1_iface);
1496 static DWRITE_WORD_WRAPPING WINAPI dwritetextlayout_GetWordWrapping(IDWriteTextLayout2 *iface)
1498 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1499 TRACE("(%p)\n", This);
1500 return IDWriteTextFormat1_GetWordWrapping(&This->IDWriteTextFormat1_iface);
1503 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_GetReadingDirection(IDWriteTextLayout2 *iface)
1505 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1506 TRACE("(%p)\n", This);
1507 return IDWriteTextFormat1_GetReadingDirection(&This->IDWriteTextFormat1_iface);
1510 static DWRITE_FLOW_DIRECTION WINAPI dwritetextlayout_GetFlowDirection(IDWriteTextLayout2 *iface)
1512 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1513 TRACE("(%p)\n", This);
1514 return IDWriteTextFormat1_GetFlowDirection(&This->IDWriteTextFormat1_iface);
1517 static FLOAT WINAPI dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout2 *iface)
1519 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1520 TRACE("(%p)\n", This);
1521 return IDWriteTextFormat1_GetIncrementalTabStop(&This->IDWriteTextFormat1_iface);
1524 static HRESULT WINAPI dwritetextlayout_GetTrimming(IDWriteTextLayout2 *iface, DWRITE_TRIMMING *options,
1525 IDWriteInlineObject **trimming_sign)
1527 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1528 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
1529 return IDWriteTextFormat1_GetTrimming(&This->IDWriteTextFormat1_iface, options, trimming_sign);
1532 static HRESULT WINAPI dwritetextlayout_GetLineSpacing(IDWriteTextLayout2 *iface, DWRITE_LINE_SPACING_METHOD *method,
1533 FLOAT *spacing, FLOAT *baseline)
1535 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1536 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
1537 return IDWriteTextFormat1_GetLineSpacing(&This->IDWriteTextFormat1_iface, method, spacing, baseline);
1540 static HRESULT WINAPI dwritetextlayout_GetFontCollection(IDWriteTextLayout2 *iface, IDWriteFontCollection **collection)
1542 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1543 TRACE("(%p)->(%p)\n", This, collection);
1544 return IDWriteTextFormat1_GetFontCollection(&This->IDWriteTextFormat1_iface, collection);
1547 static UINT32 WINAPI dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout2 *iface)
1549 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1550 TRACE("(%p)\n", This);
1551 return IDWriteTextFormat1_GetFontFamilyNameLength(&This->IDWriteTextFormat1_iface);
1554 static HRESULT WINAPI dwritetextlayout_GetFontFamilyName(IDWriteTextLayout2 *iface, WCHAR *name, UINT32 size)
1556 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1557 TRACE("(%p)->(%p %u)\n", This, name, size);
1558 return IDWriteTextFormat1_GetFontFamilyName(&This->IDWriteTextFormat1_iface, name, size);
1561 static DWRITE_FONT_WEIGHT WINAPI dwritetextlayout_GetFontWeight(IDWriteTextLayout2 *iface)
1563 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1564 TRACE("(%p)\n", This);
1565 return IDWriteTextFormat1_GetFontWeight(&This->IDWriteTextFormat1_iface);
1568 static DWRITE_FONT_STYLE WINAPI dwritetextlayout_GetFontStyle(IDWriteTextLayout2 *iface)
1570 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1571 TRACE("(%p)\n", This);
1572 return IDWriteTextFormat1_GetFontStyle(&This->IDWriteTextFormat1_iface);
1575 static DWRITE_FONT_STRETCH WINAPI dwritetextlayout_GetFontStretch(IDWriteTextLayout2 *iface)
1577 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1578 TRACE("(%p)\n", This);
1579 return IDWriteTextFormat1_GetFontStretch(&This->IDWriteTextFormat1_iface);
1582 static FLOAT WINAPI dwritetextlayout_GetFontSize(IDWriteTextLayout2 *iface)
1584 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1585 TRACE("(%p)\n", This);
1586 return IDWriteTextFormat1_GetFontSize(&This->IDWriteTextFormat1_iface);
1589 static UINT32 WINAPI dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout2 *iface)
1591 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1592 TRACE("(%p)\n", This);
1593 return IDWriteTextFormat1_GetLocaleNameLength(&This->IDWriteTextFormat1_iface);
1596 static HRESULT WINAPI dwritetextlayout_GetLocaleName(IDWriteTextLayout2 *iface, WCHAR *name, UINT32 size)
1598 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1599 TRACE("(%p)->(%p %u)\n", This, name, size);
1600 return IDWriteTextFormat1_GetLocaleName(&This->IDWriteTextFormat1_iface, name, size);
1603 static HRESULT WINAPI dwritetextlayout_SetMaxWidth(IDWriteTextLayout2 *iface, FLOAT maxWidth)
1605 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1606 TRACE("(%p)->(%.1f)\n", This, maxWidth);
1608 if (maxWidth < 0.0)
1609 return E_INVALIDARG;
1611 This->maxwidth = maxWidth;
1612 return S_OK;
1615 static HRESULT WINAPI dwritetextlayout_SetMaxHeight(IDWriteTextLayout2 *iface, FLOAT maxHeight)
1617 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1618 TRACE("(%p)->(%.1f)\n", This, maxHeight);
1620 if (maxHeight < 0.0)
1621 return E_INVALIDARG;
1623 This->maxheight = maxHeight;
1624 return S_OK;
1627 static HRESULT WINAPI dwritetextlayout_SetFontCollection(IDWriteTextLayout2 *iface, IDWriteFontCollection* collection, DWRITE_TEXT_RANGE range)
1629 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1630 struct layout_range_attr_value value;
1632 TRACE("(%p)->(%p %s)\n", This, collection, debugstr_range(&range));
1634 value.range = range;
1635 value.u.collection = collection;
1636 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTCOLL, &value);
1639 static HRESULT WINAPI dwritetextlayout_SetFontFamilyName(IDWriteTextLayout2 *iface, WCHAR const *name, DWRITE_TEXT_RANGE range)
1641 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1642 struct layout_range_attr_value value;
1644 TRACE("(%p)->(%s %s)\n", This, debugstr_w(name), debugstr_range(&range));
1646 if (!name)
1647 return E_INVALIDARG;
1649 value.range = range;
1650 value.u.fontfamily = name;
1651 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTFAMILY, &value);
1654 static HRESULT WINAPI dwritetextlayout_SetFontWeight(IDWriteTextLayout2 *iface, DWRITE_FONT_WEIGHT weight, DWRITE_TEXT_RANGE range)
1656 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1657 struct layout_range_attr_value value;
1659 TRACE("(%p)->(%d %s)\n", This, weight, debugstr_range(&range));
1661 value.range = range;
1662 value.u.weight = weight;
1663 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_WEIGHT, &value);
1666 static HRESULT WINAPI dwritetextlayout_SetFontStyle(IDWriteTextLayout2 *iface, DWRITE_FONT_STYLE style, DWRITE_TEXT_RANGE range)
1668 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1669 struct layout_range_attr_value value;
1671 TRACE("(%p)->(%d %s)\n", This, style, debugstr_range(&range));
1673 value.range = range;
1674 value.u.style = style;
1675 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STYLE, &value);
1678 static HRESULT WINAPI dwritetextlayout_SetFontStretch(IDWriteTextLayout2 *iface, DWRITE_FONT_STRETCH stretch, DWRITE_TEXT_RANGE range)
1680 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1681 struct layout_range_attr_value value;
1683 TRACE("(%p)->(%d %s)\n", This, stretch, debugstr_range(&range));
1685 value.range = range;
1686 value.u.stretch = stretch;
1687 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRETCH, &value);
1690 static HRESULT WINAPI dwritetextlayout_SetFontSize(IDWriteTextLayout2 *iface, FLOAT size, DWRITE_TEXT_RANGE range)
1692 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1693 struct layout_range_attr_value value;
1695 TRACE("(%p)->(%.2f %s)\n", This, size, debugstr_range(&range));
1697 value.range = range;
1698 value.u.fontsize = size;
1699 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTSIZE, &value);
1702 static HRESULT WINAPI dwritetextlayout_SetUnderline(IDWriteTextLayout2 *iface, BOOL underline, DWRITE_TEXT_RANGE range)
1704 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1705 struct layout_range_attr_value value;
1707 TRACE("(%p)->(%d %s)\n", This, underline, debugstr_range(&range));
1709 value.range = range;
1710 value.u.underline = underline;
1711 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_UNDERLINE, &value);
1714 static HRESULT WINAPI dwritetextlayout_SetStrikethrough(IDWriteTextLayout2 *iface, BOOL strikethrough, DWRITE_TEXT_RANGE range)
1716 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1717 struct layout_range_attr_value value;
1719 TRACE("(%p)->(%d %s)\n", This, strikethrough, debugstr_range(&range));
1721 value.range = range;
1722 value.u.strikethrough = strikethrough;
1723 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRIKETHROUGH, &value);
1726 static HRESULT WINAPI dwritetextlayout_SetDrawingEffect(IDWriteTextLayout2 *iface, IUnknown* effect, DWRITE_TEXT_RANGE range)
1728 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1729 struct layout_range_attr_value value;
1731 TRACE("(%p)->(%p %s)\n", This, effect, debugstr_range(&range));
1733 value.range = range;
1734 value.u.effect = effect;
1735 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_EFFECT, &value);
1738 static HRESULT WINAPI dwritetextlayout_SetInlineObject(IDWriteTextLayout2 *iface, IDWriteInlineObject *object, DWRITE_TEXT_RANGE range)
1740 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1741 struct layout_range_attr_value value;
1743 TRACE("(%p)->(%p %s)\n", This, object, debugstr_range(&range));
1745 value.range = range;
1746 value.u.object = object;
1747 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_INLINE, &value);
1750 static HRESULT WINAPI dwritetextlayout_SetTypography(IDWriteTextLayout2 *iface, IDWriteTypography* typography, DWRITE_TEXT_RANGE range)
1752 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1753 FIXME("(%p)->(%p %s): stub\n", This, typography, debugstr_range(&range));
1754 return E_NOTIMPL;
1757 static HRESULT WINAPI dwritetextlayout_SetLocaleName(IDWriteTextLayout2 *iface, WCHAR const* locale, DWRITE_TEXT_RANGE range)
1759 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1760 struct layout_range_attr_value value;
1762 TRACE("(%p)->(%s %s)\n", This, debugstr_w(locale), debugstr_range(&range));
1764 if (!locale || strlenW(locale) > LOCALE_NAME_MAX_LENGTH-1)
1765 return E_INVALIDARG;
1767 value.range = range;
1768 value.u.locale = locale;
1769 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_LOCALE, &value);
1772 static FLOAT WINAPI dwritetextlayout_GetMaxWidth(IDWriteTextLayout2 *iface)
1774 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1775 TRACE("(%p)\n", This);
1776 return This->maxwidth;
1779 static FLOAT WINAPI dwritetextlayout_GetMaxHeight(IDWriteTextLayout2 *iface)
1781 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1782 TRACE("(%p)\n", This);
1783 return This->maxheight;
1786 static HRESULT WINAPI dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout2 *iface, UINT32 position,
1787 IDWriteFontCollection** collection, DWRITE_TEXT_RANGE *r)
1789 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1790 struct layout_range *range;
1792 TRACE("(%p)->(%u %p %p)\n", This, position, collection, r);
1794 range = get_layout_range_by_pos(This, position);
1795 *collection = range ? range->collection : NULL;
1796 if (*collection)
1797 IDWriteFontCollection_AddRef(*collection);
1799 return return_range(range, r);
1802 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout2 *iface,
1803 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
1805 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1806 TRACE("(%p)->(%d %p %p)\n", This, position, length, r);
1807 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, length, r);
1810 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout2 *iface,
1811 UINT32 position, WCHAR *name, UINT32 length, DWRITE_TEXT_RANGE *r)
1813 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1814 TRACE("(%p)->(%u %p %u %p)\n", This, position, name, length, r);
1815 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, name, length, r);
1818 static HRESULT WINAPI dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout2 *iface,
1819 UINT32 position, DWRITE_FONT_WEIGHT *weight, DWRITE_TEXT_RANGE *r)
1821 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1822 struct layout_range *range;
1824 TRACE("(%p)->(%u %p %p)\n", This, position, weight, r);
1826 if (position >= This->len)
1827 return S_OK;
1829 range = get_layout_range_by_pos(This, position);
1830 *weight = range->weight;
1832 return return_range(range, r);
1835 static HRESULT WINAPI dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout2 *iface,
1836 UINT32 position, DWRITE_FONT_STYLE *style, DWRITE_TEXT_RANGE *r)
1838 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1839 struct layout_range *range;
1841 TRACE("(%p)->(%u %p %p)\n", This, position, style, r);
1843 if (position >= This->len)
1844 return S_OK;
1846 range = get_layout_range_by_pos(This, position);
1847 *style = range->style;
1849 return return_range(range, r);
1852 static HRESULT WINAPI dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout2 *iface,
1853 UINT32 position, DWRITE_FONT_STRETCH *stretch, DWRITE_TEXT_RANGE *r)
1855 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1856 struct layout_range *range;
1858 TRACE("(%p)->(%u %p %p)\n", This, position, stretch, r);
1860 if (position >= This->len)
1861 return S_OK;
1863 range = get_layout_range_by_pos(This, position);
1864 *stretch = range->stretch;
1866 return return_range(range, r);
1869 static HRESULT WINAPI dwritetextlayout_layout_GetFontSize(IDWriteTextLayout2 *iface,
1870 UINT32 position, FLOAT *size, DWRITE_TEXT_RANGE *r)
1872 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1873 struct layout_range *range;
1875 TRACE("(%p)->(%u %p %p)\n", This, position, size, r);
1877 if (position >= This->len)
1878 return S_OK;
1880 range = get_layout_range_by_pos(This, position);
1881 *size = range->fontsize;
1883 return return_range(range, r);
1886 static HRESULT WINAPI dwritetextlayout_GetUnderline(IDWriteTextLayout2 *iface,
1887 UINT32 position, BOOL *underline, DWRITE_TEXT_RANGE *r)
1889 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1890 struct layout_range *range;
1892 TRACE("(%p)->(%u %p %p)\n", This, position, underline, r);
1894 if (position >= This->len)
1895 return S_OK;
1897 range = get_layout_range_by_pos(This, position);
1898 *underline = range->underline;
1900 return return_range(range, r);
1903 static HRESULT WINAPI dwritetextlayout_GetStrikethrough(IDWriteTextLayout2 *iface,
1904 UINT32 position, BOOL *strikethrough, DWRITE_TEXT_RANGE *r)
1906 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1907 struct layout_range *range;
1909 TRACE("(%p)->(%u %p %p)\n", This, position, strikethrough, r);
1911 if (position >= This->len)
1912 return S_OK;
1914 range = get_layout_range_by_pos(This, position);
1915 *strikethrough = range->strikethrough;
1917 return return_range(range, r);
1920 static HRESULT WINAPI dwritetextlayout_GetDrawingEffect(IDWriteTextLayout2 *iface,
1921 UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r)
1923 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1924 struct layout_range *range;
1926 TRACE("(%p)->(%u %p %p)\n", This, position, effect, r);
1928 if (position >= This->len)
1929 return S_OK;
1931 range = get_layout_range_by_pos(This, position);
1932 *effect = range->effect;
1933 if (*effect)
1934 IUnknown_AddRef(*effect);
1936 return return_range(range, r);
1939 static HRESULT WINAPI dwritetextlayout_GetInlineObject(IDWriteTextLayout2 *iface,
1940 UINT32 position, IDWriteInlineObject **object, DWRITE_TEXT_RANGE *r)
1942 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1943 struct layout_range *range;
1945 TRACE("(%p)->(%u %p %p)\n", This, position, object, r);
1947 range = get_layout_range_by_pos(This, position);
1948 *object = range ? range->object : NULL;
1949 if (*object)
1950 IDWriteInlineObject_AddRef(*object);
1952 return return_range(range, r);
1955 static HRESULT WINAPI dwritetextlayout_GetTypography(IDWriteTextLayout2 *iface,
1956 UINT32 position, IDWriteTypography** typography, DWRITE_TEXT_RANGE *range)
1958 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1959 FIXME("(%p)->(%u %p %p): stub\n", This, position, typography, range);
1960 return E_NOTIMPL;
1963 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout2 *iface,
1964 UINT32 position, UINT32* length, DWRITE_TEXT_RANGE *r)
1966 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1967 TRACE("(%p)->(%u %p %p)\n", This, position, length, r);
1968 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_LOCALE, position, length, r);
1971 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout2 *iface,
1972 UINT32 position, WCHAR* locale, UINT32 length, DWRITE_TEXT_RANGE *r)
1974 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1975 TRACE("(%p)->(%u %p %u %p)\n", This, position, locale, length, r);
1976 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_LOCALE, position, locale, length, r);
1979 static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface,
1980 void *context, IDWriteTextRenderer* renderer, FLOAT origin_x, FLOAT origin_y)
1982 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1983 struct layout_effective_run *run;
1984 HRESULT hr;
1986 TRACE("(%p)->(%p %p %.2f %.2f)\n", This, context, renderer, origin_x, origin_y);
1988 hr = layout_compute_effective_runs(This);
1989 if (FAILED(hr))
1990 return hr;
1992 /* 1. Regular runs */
1993 LIST_FOR_EACH_ENTRY(run, &This->eruns, struct layout_effective_run, entry) {
1994 const struct regular_layout_run *regular = &run->run->u.regular;
1995 UINT32 start_glyph = regular->clustermap[run->start];
1996 DWRITE_GLYPH_RUN_DESCRIPTION descr;
1997 DWRITE_GLYPH_RUN glyph_run;
1999 /* Everything but cluster map will be reused from nominal run, as we only need
2000 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
2001 it can't be reused because it has to start with 0 index for each reported run. */
2002 glyph_run = regular->run;
2003 glyph_run.glyphCount = run->glyphcount;
2005 /* fixup glyph data arrays */
2006 glyph_run.glyphIndices += start_glyph;
2007 glyph_run.glyphAdvances += start_glyph;
2008 glyph_run.glyphOffsets += start_glyph;
2010 /* description */
2011 descr = regular->descr;
2012 descr.stringLength = run->length;
2013 descr.string += run->start;
2014 descr.clusterMap = run->clustermap;
2015 descr.textPosition += run->start;
2017 /* return value is ignored */
2018 IDWriteTextRenderer_DrawGlyphRun(renderer,
2019 context,
2020 run->origin_x + origin_x,
2021 run->origin_y + origin_y,
2022 DWRITE_MEASURING_MODE_NATURAL,
2023 &glyph_run,
2024 &descr,
2025 NULL /* FIXME */);
2028 /* TODO: 2. Inline objects */
2029 /* TODO: 3. Underlines */
2030 /* TODO: 4. Strikethrough */
2032 return S_OK;
2035 static HRESULT WINAPI dwritetextlayout_GetLineMetrics(IDWriteTextLayout2 *iface,
2036 DWRITE_LINE_METRICS *metrics, UINT32 max_count, UINT32 *count)
2038 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2039 HRESULT hr;
2041 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
2043 hr = layout_compute_effective_runs(This);
2044 if (FAILED(hr))
2045 return hr;
2047 if (metrics)
2048 memcpy(metrics, This->lines, sizeof(DWRITE_LINE_METRICS)*min(max_count, This->line_count));
2050 *count = This->line_count;
2051 return max_count >= This->line_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
2054 static HRESULT WINAPI dwritetextlayout_GetMetrics(IDWriteTextLayout2 *iface, DWRITE_TEXT_METRICS *metrics)
2056 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2057 DWRITE_TEXT_METRICS1 metrics1;
2058 HRESULT hr;
2060 TRACE("(%p)->(%p)\n", This, metrics);
2062 hr = IDWriteTextLayout2_GetMetrics(iface, &metrics1);
2063 if (hr == S_OK)
2064 memcpy(metrics, &metrics1, sizeof(*metrics));
2066 return hr;
2069 static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout2 *iface, DWRITE_OVERHANG_METRICS *overhangs)
2071 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2072 FIXME("(%p)->(%p): stub\n", This, overhangs);
2073 return E_NOTIMPL;
2076 static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout2 *iface,
2077 DWRITE_CLUSTER_METRICS *metrics, UINT32 max_count, UINT32 *count)
2079 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2080 HRESULT hr;
2082 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
2084 hr = layout_compute(This);
2085 if (FAILED(hr))
2086 return hr;
2088 if (metrics)
2089 memcpy(metrics, This->clustermetrics, sizeof(DWRITE_CLUSTER_METRICS)*min(max_count, This->cluster_count));
2091 *count = This->cluster_count;
2092 return max_count >= This->cluster_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
2095 /* Only to be used with DetermineMinWidth() to find the longest cluster sequence that we don't want to try
2096 too hard to break. */
2097 static inline BOOL is_terminal_cluster(struct dwrite_textlayout *layout, UINT32 index)
2099 if (layout->clustermetrics[index].isWhitespace || layout->clustermetrics[index].isNewline ||
2100 (index == layout->cluster_count - 1))
2101 return TRUE;
2102 /* check next one */
2103 return (index < layout->cluster_count - 1) && layout->clustermetrics[index+1].isWhitespace;
2106 static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout2 *iface, FLOAT* min_width)
2108 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2109 FLOAT width;
2110 HRESULT hr;
2111 UINT32 i;
2113 TRACE("(%p)->(%p)\n", This, min_width);
2115 if (!min_width)
2116 return E_INVALIDARG;
2118 if (!(This->recompute & RECOMPUTE_MINIMAL_WIDTH))
2119 goto width_done;
2121 *min_width = 0.0;
2122 hr = layout_compute(This);
2123 if (FAILED(hr))
2124 return hr;
2126 for (i = 0; i < This->cluster_count;) {
2127 if (is_terminal_cluster(This, i)) {
2128 width = This->clustermetrics[i].width;
2129 i++;
2131 else {
2132 width = 0.0;
2133 while (!is_terminal_cluster(This, i)) {
2134 width += This->clustermetrics[i].width;
2135 i++;
2137 /* count last one too */
2138 width += This->clustermetrics[i].width;
2141 if (width > This->minwidth)
2142 This->minwidth = width;
2144 This->recompute &= ~RECOMPUTE_MINIMAL_WIDTH;
2146 width_done:
2147 *min_width = This->minwidth;
2148 return S_OK;
2151 static HRESULT WINAPI dwritetextlayout_HitTestPoint(IDWriteTextLayout2 *iface,
2152 FLOAT pointX, FLOAT pointY, BOOL* is_trailinghit, BOOL* is_inside, DWRITE_HIT_TEST_METRICS *metrics)
2154 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2155 FIXME("(%p)->(%f %f %p %p %p): stub\n", This, pointX, pointY, is_trailinghit, is_inside, metrics);
2156 return E_NOTIMPL;
2159 static HRESULT WINAPI dwritetextlayout_HitTestTextPosition(IDWriteTextLayout2 *iface,
2160 UINT32 textPosition, BOOL is_trailinghit, FLOAT* pointX, FLOAT* pointY, DWRITE_HIT_TEST_METRICS *metrics)
2162 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2163 FIXME("(%p)->(%u %d %p %p %p): stub\n", This, textPosition, is_trailinghit, pointX, pointY, metrics);
2164 return E_NOTIMPL;
2167 static HRESULT WINAPI dwritetextlayout_HitTestTextRange(IDWriteTextLayout2 *iface,
2168 UINT32 textPosition, UINT32 textLength, FLOAT originX, FLOAT originY,
2169 DWRITE_HIT_TEST_METRICS *metrics, UINT32 max_metricscount, UINT32* actual_metricscount)
2171 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2172 FIXME("(%p)->(%u %u %f %f %p %u %p): stub\n", This, textPosition, textLength, originX, originY, metrics,
2173 max_metricscount, actual_metricscount);
2174 return E_NOTIMPL;
2177 static HRESULT WINAPI dwritetextlayout1_SetPairKerning(IDWriteTextLayout2 *iface, BOOL is_pairkerning_enabled,
2178 DWRITE_TEXT_RANGE range)
2180 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2181 struct layout_range_attr_value value;
2183 TRACE("(%p)->(%d %s)\n", This, is_pairkerning_enabled, debugstr_range(&range));
2185 value.range = range;
2186 value.u.pair_kerning = !!is_pairkerning_enabled;
2187 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_PAIR_KERNING, &value);
2190 static HRESULT WINAPI dwritetextlayout1_GetPairKerning(IDWriteTextLayout2 *iface, UINT32 position, BOOL *is_pairkerning_enabled,
2191 DWRITE_TEXT_RANGE *r)
2193 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2194 struct layout_range *range;
2196 TRACE("(%p)->(%u %p %p)\n", This, position, is_pairkerning_enabled, r);
2198 if (position >= This->len)
2199 return S_OK;
2201 range = get_layout_range_by_pos(This, position);
2202 *is_pairkerning_enabled = range->pair_kerning;
2204 return return_range(range, r);
2207 static HRESULT WINAPI dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout2 *iface, FLOAT leading_spacing, FLOAT trailing_spacing,
2208 FLOAT minimum_advance_width, DWRITE_TEXT_RANGE range)
2210 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2211 FIXME("(%p)->(%f %f %f %s): stub\n", This, leading_spacing, trailing_spacing, minimum_advance_width, debugstr_range(&range));
2212 return E_NOTIMPL;
2215 static HRESULT WINAPI dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout2 *iface, UINT32 position, FLOAT* leading_spacing,
2216 FLOAT* trailing_spacing, FLOAT* minimum_advance_width, DWRITE_TEXT_RANGE *range)
2218 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2219 FIXME("(%p)->(%u %p %p %p %p): stub\n", This, position, leading_spacing, trailing_spacing, minimum_advance_width, range);
2220 return E_NOTIMPL;
2223 static HRESULT WINAPI dwritetextlayout2_GetMetrics(IDWriteTextLayout2 *iface, DWRITE_TEXT_METRICS1 *metrics)
2225 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2226 FIXME("(%p)->(%p): stub\n", This, metrics);
2227 return E_NOTIMPL;
2230 static HRESULT WINAPI dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout2 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
2232 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2234 TRACE("(%p)->(%d)\n", This, orientation);
2236 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
2237 return E_INVALIDARG;
2239 This->format.vertical_orientation = orientation;
2240 return S_OK;
2243 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout2 *iface)
2245 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2246 TRACE("(%p)\n", This);
2247 return This->format.vertical_orientation;
2250 static HRESULT WINAPI dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout2 *iface, BOOL lastline_wrapping_enabled)
2252 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2253 FIXME("(%p)->(%d): stub\n", This, lastline_wrapping_enabled);
2254 return E_NOTIMPL;
2257 static BOOL WINAPI dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout2 *iface)
2259 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2260 FIXME("(%p): stub\n", This);
2261 return FALSE;
2264 static HRESULT WINAPI dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout2 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
2266 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2267 FIXME("(%p)->(%d): stub\n", This, alignment);
2268 return E_NOTIMPL;
2271 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout2 *iface)
2273 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2274 FIXME("(%p): stub\n", This);
2275 return DWRITE_OPTICAL_ALIGNMENT_NONE;
2278 static HRESULT WINAPI dwritetextlayout2_SetFontFallback(IDWriteTextLayout2 *iface, IDWriteFontFallback *fallback)
2280 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2281 TRACE("(%p)->(%p)\n", This, fallback);
2282 return set_fontfallback_for_format(&This->format, fallback);
2285 static HRESULT WINAPI dwritetextlayout2_GetFontFallback(IDWriteTextLayout2 *iface, IDWriteFontFallback **fallback)
2287 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2288 TRACE("(%p)->(%p)\n", This, fallback);
2289 return get_fontfallback_from_format(&This->format, fallback);
2292 static const IDWriteTextLayout2Vtbl dwritetextlayoutvtbl = {
2293 dwritetextlayout_QueryInterface,
2294 dwritetextlayout_AddRef,
2295 dwritetextlayout_Release,
2296 dwritetextlayout_SetTextAlignment,
2297 dwritetextlayout_SetParagraphAlignment,
2298 dwritetextlayout_SetWordWrapping,
2299 dwritetextlayout_SetReadingDirection,
2300 dwritetextlayout_SetFlowDirection,
2301 dwritetextlayout_SetIncrementalTabStop,
2302 dwritetextlayout_SetTrimming,
2303 dwritetextlayout_SetLineSpacing,
2304 dwritetextlayout_GetTextAlignment,
2305 dwritetextlayout_GetParagraphAlignment,
2306 dwritetextlayout_GetWordWrapping,
2307 dwritetextlayout_GetReadingDirection,
2308 dwritetextlayout_GetFlowDirection,
2309 dwritetextlayout_GetIncrementalTabStop,
2310 dwritetextlayout_GetTrimming,
2311 dwritetextlayout_GetLineSpacing,
2312 dwritetextlayout_GetFontCollection,
2313 dwritetextlayout_GetFontFamilyNameLength,
2314 dwritetextlayout_GetFontFamilyName,
2315 dwritetextlayout_GetFontWeight,
2316 dwritetextlayout_GetFontStyle,
2317 dwritetextlayout_GetFontStretch,
2318 dwritetextlayout_GetFontSize,
2319 dwritetextlayout_GetLocaleNameLength,
2320 dwritetextlayout_GetLocaleName,
2321 dwritetextlayout_SetMaxWidth,
2322 dwritetextlayout_SetMaxHeight,
2323 dwritetextlayout_SetFontCollection,
2324 dwritetextlayout_SetFontFamilyName,
2325 dwritetextlayout_SetFontWeight,
2326 dwritetextlayout_SetFontStyle,
2327 dwritetextlayout_SetFontStretch,
2328 dwritetextlayout_SetFontSize,
2329 dwritetextlayout_SetUnderline,
2330 dwritetextlayout_SetStrikethrough,
2331 dwritetextlayout_SetDrawingEffect,
2332 dwritetextlayout_SetInlineObject,
2333 dwritetextlayout_SetTypography,
2334 dwritetextlayout_SetLocaleName,
2335 dwritetextlayout_GetMaxWidth,
2336 dwritetextlayout_GetMaxHeight,
2337 dwritetextlayout_layout_GetFontCollection,
2338 dwritetextlayout_layout_GetFontFamilyNameLength,
2339 dwritetextlayout_layout_GetFontFamilyName,
2340 dwritetextlayout_layout_GetFontWeight,
2341 dwritetextlayout_layout_GetFontStyle,
2342 dwritetextlayout_layout_GetFontStretch,
2343 dwritetextlayout_layout_GetFontSize,
2344 dwritetextlayout_GetUnderline,
2345 dwritetextlayout_GetStrikethrough,
2346 dwritetextlayout_GetDrawingEffect,
2347 dwritetextlayout_GetInlineObject,
2348 dwritetextlayout_GetTypography,
2349 dwritetextlayout_layout_GetLocaleNameLength,
2350 dwritetextlayout_layout_GetLocaleName,
2351 dwritetextlayout_Draw,
2352 dwritetextlayout_GetLineMetrics,
2353 dwritetextlayout_GetMetrics,
2354 dwritetextlayout_GetOverhangMetrics,
2355 dwritetextlayout_GetClusterMetrics,
2356 dwritetextlayout_DetermineMinWidth,
2357 dwritetextlayout_HitTestPoint,
2358 dwritetextlayout_HitTestTextPosition,
2359 dwritetextlayout_HitTestTextRange,
2360 dwritetextlayout1_SetPairKerning,
2361 dwritetextlayout1_GetPairKerning,
2362 dwritetextlayout1_SetCharacterSpacing,
2363 dwritetextlayout1_GetCharacterSpacing,
2364 dwritetextlayout2_GetMetrics,
2365 dwritetextlayout2_SetVerticalGlyphOrientation,
2366 dwritetextlayout2_GetVerticalGlyphOrientation,
2367 dwritetextlayout2_SetLastLineWrapping,
2368 dwritetextlayout2_GetLastLineWrapping,
2369 dwritetextlayout2_SetOpticalAlignment,
2370 dwritetextlayout2_GetOpticalAlignment,
2371 dwritetextlayout2_SetFontFallback,
2372 dwritetextlayout2_GetFontFallback
2375 static HRESULT WINAPI dwritetextformat1_layout_QueryInterface(IDWriteTextFormat1 *iface, REFIID riid, void **obj)
2377 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2378 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2379 return IDWriteTextLayout2_QueryInterface(&This->IDWriteTextLayout2_iface, riid, obj);
2382 static ULONG WINAPI dwritetextformat1_layout_AddRef(IDWriteTextFormat1 *iface)
2384 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2385 return IDWriteTextLayout2_AddRef(&This->IDWriteTextLayout2_iface);
2388 static ULONG WINAPI dwritetextformat1_layout_Release(IDWriteTextFormat1 *iface)
2390 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2391 return IDWriteTextLayout2_Release(&This->IDWriteTextLayout2_iface);
2394 static HRESULT WINAPI dwritetextformat1_layout_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
2396 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2397 FIXME("(%p)->(%d): stub\n", This, alignment);
2398 return E_NOTIMPL;
2401 static HRESULT WINAPI dwritetextformat1_layout_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
2403 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2404 FIXME("(%p)->(%d): stub\n", This, alignment);
2405 return E_NOTIMPL;
2408 static HRESULT WINAPI dwritetextformat1_layout_SetWordWrapping(IDWriteTextFormat1 *iface, DWRITE_WORD_WRAPPING wrapping)
2410 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2411 FIXME("(%p)->(%d): stub\n", This, wrapping);
2412 return E_NOTIMPL;
2415 static HRESULT WINAPI dwritetextformat1_layout_SetReadingDirection(IDWriteTextFormat1 *iface, DWRITE_READING_DIRECTION direction)
2417 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2418 FIXME("(%p)->(%d): stub\n", This, direction);
2419 return E_NOTIMPL;
2422 static HRESULT WINAPI dwritetextformat1_layout_SetFlowDirection(IDWriteTextFormat1 *iface, DWRITE_FLOW_DIRECTION direction)
2424 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2425 FIXME("(%p)->(%d): stub\n", This, direction);
2426 return E_NOTIMPL;
2429 static HRESULT WINAPI dwritetextformat1_layout_SetIncrementalTabStop(IDWriteTextFormat1 *iface, FLOAT tabstop)
2431 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2432 FIXME("(%p)->(%f): stub\n", This, tabstop);
2433 return E_NOTIMPL;
2436 static HRESULT WINAPI dwritetextformat1_layout_SetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING const *trimming,
2437 IDWriteInlineObject *trimming_sign)
2439 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2440 FIXME("(%p)->(%p %p): stub\n", This, trimming, trimming_sign);
2441 return E_NOTIMPL;
2444 static HRESULT WINAPI dwritetextformat1_layout_SetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD spacing,
2445 FLOAT line_spacing, FLOAT baseline)
2447 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2448 FIXME("(%p)->(%d %f %f): stub\n", This, spacing, line_spacing, baseline);
2449 return E_NOTIMPL;
2452 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat1_layout_GetTextAlignment(IDWriteTextFormat1 *iface)
2454 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2455 TRACE("(%p)\n", This);
2456 return This->format.textalignment;
2459 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat1_layout_GetParagraphAlignment(IDWriteTextFormat1 *iface)
2461 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2462 TRACE("(%p)\n", This);
2463 return This->format.paralign;
2466 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat1_layout_GetWordWrapping(IDWriteTextFormat1 *iface)
2468 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2469 FIXME("(%p): stub\n", This);
2470 return This->format.wrapping;
2473 static DWRITE_READING_DIRECTION WINAPI dwritetextformat1_layout_GetReadingDirection(IDWriteTextFormat1 *iface)
2475 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2476 TRACE("(%p)\n", This);
2477 return This->format.readingdir;
2480 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat1_layout_GetFlowDirection(IDWriteTextFormat1 *iface)
2482 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2483 TRACE("(%p)\n", This);
2484 return This->format.flow;
2487 static FLOAT WINAPI dwritetextformat1_layout_GetIncrementalTabStop(IDWriteTextFormat1 *iface)
2489 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2490 FIXME("(%p): stub\n", This);
2491 return 0.0;
2494 static HRESULT WINAPI dwritetextformat1_layout_GetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING *options,
2495 IDWriteInlineObject **trimming_sign)
2497 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2499 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
2501 *options = This->format.trimming;
2502 *trimming_sign = This->format.trimmingsign;
2503 if (*trimming_sign)
2504 IDWriteInlineObject_AddRef(*trimming_sign);
2505 return S_OK;
2508 static HRESULT WINAPI dwritetextformat1_layout_GetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD *method,
2509 FLOAT *spacing, FLOAT *baseline)
2511 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2513 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
2515 *method = This->format.spacingmethod;
2516 *spacing = This->format.spacing;
2517 *baseline = This->format.baseline;
2518 return S_OK;
2521 static HRESULT WINAPI dwritetextformat1_layout_GetFontCollection(IDWriteTextFormat1 *iface, IDWriteFontCollection **collection)
2523 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2525 TRACE("(%p)->(%p)\n", This, collection);
2527 *collection = This->format.collection;
2528 if (*collection)
2529 IDWriteFontCollection_AddRef(*collection);
2530 return S_OK;
2533 static UINT32 WINAPI dwritetextformat1_layout_GetFontFamilyNameLength(IDWriteTextFormat1 *iface)
2535 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2536 TRACE("(%p)\n", This);
2537 return This->format.family_len;
2540 static HRESULT WINAPI dwritetextformat1_layout_GetFontFamilyName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
2542 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2544 TRACE("(%p)->(%p %u)\n", This, name, size);
2546 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
2547 strcpyW(name, This->format.family_name);
2548 return S_OK;
2551 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat1_layout_GetFontWeight(IDWriteTextFormat1 *iface)
2553 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2554 TRACE("(%p)\n", This);
2555 return This->format.weight;
2558 static DWRITE_FONT_STYLE WINAPI dwritetextformat1_layout_GetFontStyle(IDWriteTextFormat1 *iface)
2560 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2561 TRACE("(%p)\n", This);
2562 return This->format.style;
2565 static DWRITE_FONT_STRETCH WINAPI dwritetextformat1_layout_GetFontStretch(IDWriteTextFormat1 *iface)
2567 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2568 TRACE("(%p)\n", This);
2569 return This->format.stretch;
2572 static FLOAT WINAPI dwritetextformat1_layout_GetFontSize(IDWriteTextFormat1 *iface)
2574 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2575 TRACE("(%p)\n", This);
2576 return This->format.fontsize;
2579 static UINT32 WINAPI dwritetextformat1_layout_GetLocaleNameLength(IDWriteTextFormat1 *iface)
2581 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2582 TRACE("(%p)\n", This);
2583 return This->format.locale_len;
2586 static HRESULT WINAPI dwritetextformat1_layout_GetLocaleName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
2588 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2590 TRACE("(%p)->(%p %u)\n", This, name, size);
2592 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
2593 strcpyW(name, This->format.locale);
2594 return S_OK;
2597 static HRESULT WINAPI dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat1 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
2599 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2600 FIXME("(%p)->(%d): stub\n", This, orientation);
2601 return E_NOTIMPL;
2604 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat1 *iface)
2606 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2607 FIXME("(%p): stub\n", This);
2608 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
2611 static HRESULT WINAPI dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat1 *iface, BOOL lastline_wrapping_enabled)
2613 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2614 FIXME("(%p)->(%d): stub\n", This, lastline_wrapping_enabled);
2615 return E_NOTIMPL;
2618 static BOOL WINAPI dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat1 *iface)
2620 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2621 FIXME("(%p): stub\n", This);
2622 return FALSE;
2625 static HRESULT WINAPI dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat1 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
2627 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2628 FIXME("(%p)->(%d): stub\n", This, alignment);
2629 return E_NOTIMPL;
2632 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat1 *iface)
2634 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2635 FIXME("(%p): stub\n", This);
2636 return DWRITE_OPTICAL_ALIGNMENT_NONE;
2639 static HRESULT WINAPI dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback *fallback)
2641 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2642 TRACE("(%p)->(%p)\n", This, fallback);
2643 return IDWriteTextLayout2_SetFontFallback(&This->IDWriteTextLayout2_iface, fallback);
2646 static HRESULT WINAPI dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback **fallback)
2648 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2649 TRACE("(%p)->(%p)\n", This, fallback);
2650 return IDWriteTextLayout2_GetFontFallback(&This->IDWriteTextLayout2_iface, fallback);
2653 static const IDWriteTextFormat1Vtbl dwritetextformat1_layout_vtbl = {
2654 dwritetextformat1_layout_QueryInterface,
2655 dwritetextformat1_layout_AddRef,
2656 dwritetextformat1_layout_Release,
2657 dwritetextformat1_layout_SetTextAlignment,
2658 dwritetextformat1_layout_SetParagraphAlignment,
2659 dwritetextformat1_layout_SetWordWrapping,
2660 dwritetextformat1_layout_SetReadingDirection,
2661 dwritetextformat1_layout_SetFlowDirection,
2662 dwritetextformat1_layout_SetIncrementalTabStop,
2663 dwritetextformat1_layout_SetTrimming,
2664 dwritetextformat1_layout_SetLineSpacing,
2665 dwritetextformat1_layout_GetTextAlignment,
2666 dwritetextformat1_layout_GetParagraphAlignment,
2667 dwritetextformat1_layout_GetWordWrapping,
2668 dwritetextformat1_layout_GetReadingDirection,
2669 dwritetextformat1_layout_GetFlowDirection,
2670 dwritetextformat1_layout_GetIncrementalTabStop,
2671 dwritetextformat1_layout_GetTrimming,
2672 dwritetextformat1_layout_GetLineSpacing,
2673 dwritetextformat1_layout_GetFontCollection,
2674 dwritetextformat1_layout_GetFontFamilyNameLength,
2675 dwritetextformat1_layout_GetFontFamilyName,
2676 dwritetextformat1_layout_GetFontWeight,
2677 dwritetextformat1_layout_GetFontStyle,
2678 dwritetextformat1_layout_GetFontStretch,
2679 dwritetextformat1_layout_GetFontSize,
2680 dwritetextformat1_layout_GetLocaleNameLength,
2681 dwritetextformat1_layout_GetLocaleName,
2682 dwritetextformat1_layout_SetVerticalGlyphOrientation,
2683 dwritetextformat1_layout_GetVerticalGlyphOrientation,
2684 dwritetextformat1_layout_SetLastLineWrapping,
2685 dwritetextformat1_layout_GetLastLineWrapping,
2686 dwritetextformat1_layout_SetOpticalAlignment,
2687 dwritetextformat1_layout_GetOpticalAlignment,
2688 dwritetextformat1_layout_SetFontFallback,
2689 dwritetextformat1_layout_GetFontFallback
2692 static HRESULT WINAPI dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink *iface,
2693 REFIID riid, void **obj)
2695 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) || IsEqualIID(riid, &IID_IUnknown)) {
2696 *obj = iface;
2697 IDWriteTextAnalysisSink_AddRef(iface);
2698 return S_OK;
2701 *obj = NULL;
2702 return E_NOINTERFACE;
2705 static ULONG WINAPI dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink *iface)
2707 return 2;
2710 static ULONG WINAPI dwritetextlayout_sink_Release(IDWriteTextAnalysisSink *iface)
2712 return 1;
2715 static HRESULT WINAPI dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink *iface,
2716 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
2718 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
2719 struct layout_run *run;
2721 TRACE("%u %u script=%d\n", position, length, sa->script);
2723 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
2724 if (!run)
2725 return E_OUTOFMEMORY;
2727 run->u.regular.descr.string = &layout->str[position];
2728 run->u.regular.descr.stringLength = length;
2729 run->u.regular.descr.textPosition = position;
2730 run->u.regular.sa = *sa;
2731 list_add_tail(&layout->runs, &run->entry);
2732 return S_OK;
2735 static HRESULT WINAPI dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink *iface,
2736 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
2738 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
2740 if (position + length > layout->len)
2741 return E_FAIL;
2743 memcpy(&layout->nominal_breakpoints[position], breakpoints, length*sizeof(DWRITE_LINE_BREAKPOINT));
2744 return S_OK;
2747 static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink *iface, UINT32 position,
2748 UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
2750 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
2751 struct layout_run *cur_run;
2753 LIST_FOR_EACH_ENTRY(cur_run, &layout->runs, struct layout_run, entry) {
2754 struct regular_layout_run *cur = &cur_run->u.regular;
2755 struct layout_run *run, *run2;
2757 if (cur_run->kind == LAYOUT_RUN_INLINE)
2758 continue;
2760 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
2761 if (position < cur->descr.textPosition || position > cur->descr.textPosition + cur->descr.stringLength)
2762 continue;
2764 /* full hit - just set run level */
2765 if (cur->descr.textPosition == position && cur->descr.stringLength == length) {
2766 cur->run.bidiLevel = resolvedLevel;
2767 break;
2770 /* current run is fully covered, move to next one */
2771 if (cur->descr.textPosition == position && cur->descr.stringLength < length) {
2772 cur->run.bidiLevel = resolvedLevel;
2773 position += cur->descr.stringLength;
2774 length -= cur->descr.stringLength;
2775 continue;
2778 /* now starting point is in a run, so it splits it */
2779 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
2780 if (!run)
2781 return E_OUTOFMEMORY;
2783 *run = *cur_run;
2784 run->u.regular.descr.textPosition = position;
2785 run->u.regular.descr.stringLength = cur->descr.stringLength - position + cur->descr.textPosition;
2786 run->u.regular.descr.string = &layout->str[position];
2787 run->u.regular.run.bidiLevel = resolvedLevel;
2788 cur->descr.stringLength -= position - cur->descr.textPosition;
2790 list_add_after(&cur_run->entry, &run->entry);
2792 if (position + length == run->u.regular.descr.textPosition + run->u.regular.descr.stringLength)
2793 break;
2795 /* split second time */
2796 run2 = alloc_layout_run(LAYOUT_RUN_REGULAR);
2797 if (!run2)
2798 return E_OUTOFMEMORY;
2800 *run2 = *cur_run;
2801 run2->u.regular.descr.textPosition = run->u.regular.descr.textPosition + run->u.regular.descr.stringLength;
2802 run2->u.regular.descr.stringLength = cur->descr.textPosition + cur->descr.stringLength - position - length;
2803 run2->u.regular.descr.string = &layout->str[run2->u.regular.descr.textPosition];
2804 run->u.regular.descr.stringLength -= run2->u.regular.descr.stringLength;
2806 list_add_after(&run->entry, &run2->entry);
2807 break;
2810 return S_OK;
2813 static HRESULT WINAPI dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink *iface,
2814 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
2816 return E_NOTIMPL;
2819 static const IDWriteTextAnalysisSinkVtbl dwritetextlayoutsinkvtbl = {
2820 dwritetextlayout_sink_QueryInterface,
2821 dwritetextlayout_sink_AddRef,
2822 dwritetextlayout_sink_Release,
2823 dwritetextlayout_sink_SetScriptAnalysis,
2824 dwritetextlayout_sink_SetLineBreakpoints,
2825 dwritetextlayout_sink_SetBidiLevel,
2826 dwritetextlayout_sink_SetNumberSubstitution
2829 static HRESULT WINAPI dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource *iface,
2830 REFIID riid, void **obj)
2832 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) ||
2833 IsEqualIID(riid, &IID_IUnknown))
2835 *obj = iface;
2836 IDWriteTextAnalysisSource_AddRef(iface);
2837 return S_OK;
2840 *obj = NULL;
2841 return E_NOINTERFACE;
2844 static ULONG WINAPI dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource *iface)
2846 return 2;
2849 static ULONG WINAPI dwritetextlayout_source_Release(IDWriteTextAnalysisSource *iface)
2851 return 1;
2854 static HRESULT WINAPI dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource *iface,
2855 UINT32 position, WCHAR const** text, UINT32* text_len)
2857 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource(iface);
2859 TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
2861 if (position < layout->len) {
2862 *text = &layout->str[position];
2863 *text_len = layout->len - position;
2865 else {
2866 *text = NULL;
2867 *text_len = 0;
2870 return S_OK;
2873 static HRESULT WINAPI dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource *iface,
2874 UINT32 position, WCHAR const** text, UINT32* text_len)
2876 FIXME("%u %p %p: stub\n", position, text, text_len);
2877 return E_NOTIMPL;
2880 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource *iface)
2882 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource(iface);
2883 return IDWriteTextLayout2_GetReadingDirection(&layout->IDWriteTextLayout2_iface);
2886 static HRESULT WINAPI dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource *iface,
2887 UINT32 position, UINT32* text_len, WCHAR const** locale)
2889 FIXME("%u %p %p: stub\n", position, text_len, locale);
2890 return E_NOTIMPL;
2893 static HRESULT WINAPI dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource *iface,
2894 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
2896 FIXME("%u %p %p: stub\n", position, text_len, substitution);
2897 return E_NOTIMPL;
2900 static const IDWriteTextAnalysisSourceVtbl dwritetextlayoutsourcevtbl = {
2901 dwritetextlayout_source_QueryInterface,
2902 dwritetextlayout_source_AddRef,
2903 dwritetextlayout_source_Release,
2904 dwritetextlayout_source_GetTextAtPosition,
2905 dwritetextlayout_source_GetTextBeforePosition,
2906 dwritetextlayout_source_GetParagraphReadingDirection,
2907 dwritetextlayout_source_GetLocaleName,
2908 dwritetextlayout_source_GetNumberSubstitution
2911 static HRESULT layout_format_from_textformat(struct dwrite_textlayout *layout, IDWriteTextFormat *format)
2913 IDWriteTextFormat1 *format1;
2914 UINT32 len;
2915 HRESULT hr;
2917 layout->format.weight = IDWriteTextFormat_GetFontWeight(format);
2918 layout->format.style = IDWriteTextFormat_GetFontStyle(format);
2919 layout->format.stretch = IDWriteTextFormat_GetFontStretch(format);
2920 layout->format.fontsize= IDWriteTextFormat_GetFontSize(format);
2921 layout->format.textalignment = IDWriteTextFormat_GetTextAlignment(format);
2922 layout->format.paralign = IDWriteTextFormat_GetParagraphAlignment(format);
2923 layout->format.wrapping = IDWriteTextFormat_GetWordWrapping(format);
2924 layout->format.readingdir = IDWriteTextFormat_GetReadingDirection(format);
2925 layout->format.flow = IDWriteTextFormat_GetFlowDirection(format);
2926 layout->format.fallback = NULL;
2927 hr = IDWriteTextFormat_GetLineSpacing(format, &layout->format.spacingmethod,
2928 &layout->format.spacing, &layout->format.baseline);
2929 if (FAILED(hr))
2930 return hr;
2932 hr = IDWriteTextFormat_GetTrimming(format, &layout->format.trimming, &layout->format.trimmingsign);
2933 if (FAILED(hr))
2934 return hr;
2936 /* locale name and length */
2937 len = IDWriteTextFormat_GetLocaleNameLength(format);
2938 layout->format.locale = heap_alloc((len+1)*sizeof(WCHAR));
2939 if (!layout->format.locale)
2940 return E_OUTOFMEMORY;
2942 hr = IDWriteTextFormat_GetLocaleName(format, layout->format.locale, len+1);
2943 if (FAILED(hr))
2944 return hr;
2945 layout->format.locale_len = len;
2947 /* font family name and length */
2948 len = IDWriteTextFormat_GetFontFamilyNameLength(format);
2949 layout->format.family_name = heap_alloc((len+1)*sizeof(WCHAR));
2950 if (!layout->format.family_name)
2951 return E_OUTOFMEMORY;
2953 hr = IDWriteTextFormat_GetFontFamilyName(format, layout->format.family_name, len+1);
2954 if (FAILED(hr))
2955 return hr;
2956 layout->format.family_len = len;
2958 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
2959 if (hr == S_OK) {
2960 layout->format.vertical_orientation = IDWriteTextFormat1_GetVerticalGlyphOrientation(format1);
2961 IDWriteTextFormat1_GetFontFallback(format1, &layout->format.fallback);
2962 IDWriteTextFormat1_Release(format1);
2964 else
2965 layout->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
2967 return IDWriteTextFormat_GetFontCollection(format, &layout->format.collection);
2970 static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, struct dwrite_textlayout *layout)
2972 DWRITE_TEXT_RANGE r = { 0, len };
2973 struct layout_range *range;
2974 HRESULT hr;
2976 layout->IDWriteTextLayout2_iface.lpVtbl = &dwritetextlayoutvtbl;
2977 layout->IDWriteTextFormat1_iface.lpVtbl = &dwritetextformat1_layout_vtbl;
2978 layout->IDWriteTextAnalysisSink_iface.lpVtbl = &dwritetextlayoutsinkvtbl;
2979 layout->IDWriteTextAnalysisSource_iface.lpVtbl = &dwritetextlayoutsourcevtbl;
2980 layout->ref = 1;
2981 layout->len = len;
2982 layout->maxwidth = maxwidth;
2983 layout->maxheight = maxheight;
2984 layout->recompute = RECOMPUTE_EVERYTHING;
2985 layout->nominal_breakpoints = NULL;
2986 layout->actual_breakpoints = NULL;
2987 layout->cluster_count = 0;
2988 layout->clustermetrics = NULL;
2989 layout->clusters = NULL;
2990 layout->lines = NULL;
2991 layout->line_count = 0;
2992 layout->line_alloc = 0;
2993 layout->minwidth = 0.0;
2994 list_init(&layout->eruns);
2995 list_init(&layout->runs);
2996 list_init(&layout->ranges);
2997 memset(&layout->format, 0, sizeof(layout->format));
2999 layout->gdicompatible = FALSE;
3000 layout->pixels_per_dip = 0.0;
3001 layout->use_gdi_natural = FALSE;
3002 memset(&layout->transform, 0, sizeof(layout->transform));
3004 layout->str = heap_strdupnW(str, len);
3005 if (len && !layout->str) {
3006 hr = E_OUTOFMEMORY;
3007 goto fail;
3010 hr = layout_format_from_textformat(layout, format);
3011 if (FAILED(hr))
3012 goto fail;
3014 range = alloc_layout_range(layout, &r);
3015 if (!range) {
3016 hr = E_OUTOFMEMORY;
3017 goto fail;
3020 list_add_head(&layout->ranges, &range->entry);
3021 return S_OK;
3023 fail:
3024 IDWriteTextLayout2_Release(&layout->IDWriteTextLayout2_iface);
3025 return hr;
3028 HRESULT create_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, IDWriteTextLayout **ret)
3030 struct dwrite_textlayout *layout;
3031 HRESULT hr;
3033 *ret = NULL;
3035 layout = heap_alloc(sizeof(struct dwrite_textlayout));
3036 if (!layout) return E_OUTOFMEMORY;
3038 hr = init_textlayout(str, len, format, maxwidth, maxheight, layout);
3039 if (hr == S_OK)
3040 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout2_iface;
3042 return hr;
3045 HRESULT create_gdicompat_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight,
3046 FLOAT pixels_per_dip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural, IDWriteTextLayout **ret)
3048 struct dwrite_textlayout *layout;
3049 HRESULT hr;
3051 *ret = NULL;
3053 layout = heap_alloc(sizeof(struct dwrite_textlayout));
3054 if (!layout) return E_OUTOFMEMORY;
3056 hr = init_textlayout(str, len, format, maxwidth, maxheight, layout);
3057 if (hr == S_OK) {
3058 /* set gdi-specific properties */
3059 layout->gdicompatible = TRUE;
3060 layout->pixels_per_dip = pixels_per_dip;
3061 layout->use_gdi_natural = use_gdi_natural;
3062 layout->transform = transform ? *transform : identity;
3064 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout2_iface;
3067 return hr;
3070 static HRESULT WINAPI dwritetrimmingsign_QueryInterface(IDWriteInlineObject *iface, REFIID riid, void **obj)
3072 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3074 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3076 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteInlineObject)) {
3077 *obj = iface;
3078 IDWriteInlineObject_AddRef(iface);
3079 return S_OK;
3082 *obj = NULL;
3083 return E_NOINTERFACE;
3087 static ULONG WINAPI dwritetrimmingsign_AddRef(IDWriteInlineObject *iface)
3089 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3090 ULONG ref = InterlockedIncrement(&This->ref);
3091 TRACE("(%p)->(%d)\n", This, ref);
3092 return ref;
3095 static ULONG WINAPI dwritetrimmingsign_Release(IDWriteInlineObject *iface)
3097 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3098 ULONG ref = InterlockedDecrement(&This->ref);
3100 TRACE("(%p)->(%d)\n", This, ref);
3102 if (!ref)
3103 heap_free(This);
3105 return ref;
3108 static HRESULT WINAPI dwritetrimmingsign_Draw(IDWriteInlineObject *iface, void *context, IDWriteTextRenderer *renderer,
3109 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *drawing_effect)
3111 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3112 FIXME("(%p)->(%p %p %f %f %d %d %p): stub\n", This, context, renderer, originX, originY, is_sideways, is_rtl, drawing_effect);
3113 return E_NOTIMPL;
3116 static HRESULT WINAPI dwritetrimmingsign_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *metrics)
3118 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3119 FIXME("(%p)->(%p): stub\n", This, metrics);
3120 memset(metrics, 0, sizeof(*metrics));
3121 return S_OK;
3124 static HRESULT WINAPI dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
3126 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3127 FIXME("(%p)->(%p): stub\n", This, overhangs);
3128 return E_NOTIMPL;
3131 static HRESULT WINAPI dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
3132 DWRITE_BREAK_CONDITION *after)
3134 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3136 TRACE("(%p)->(%p %p)\n", This, before, after);
3138 *before = *after = DWRITE_BREAK_CONDITION_NEUTRAL;
3139 return S_OK;
3142 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl = {
3143 dwritetrimmingsign_QueryInterface,
3144 dwritetrimmingsign_AddRef,
3145 dwritetrimmingsign_Release,
3146 dwritetrimmingsign_Draw,
3147 dwritetrimmingsign_GetMetrics,
3148 dwritetrimmingsign_GetOverhangMetrics,
3149 dwritetrimmingsign_GetBreakConditions
3152 HRESULT create_trimmingsign(IDWriteInlineObject **sign)
3154 struct dwrite_trimmingsign *This;
3156 *sign = NULL;
3158 This = heap_alloc(sizeof(struct dwrite_trimmingsign));
3159 if (!This) return E_OUTOFMEMORY;
3161 This->IDWriteInlineObject_iface.lpVtbl = &dwritetrimmingsignvtbl;
3162 This->ref = 1;
3164 *sign = &This->IDWriteInlineObject_iface;
3166 return S_OK;
3169 static HRESULT WINAPI dwritetextformat_QueryInterface(IDWriteTextFormat1 *iface, REFIID riid, void **obj)
3171 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3173 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3175 if (IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
3176 IsEqualIID(riid, &IID_IDWriteTextFormat) ||
3177 IsEqualIID(riid, &IID_IUnknown))
3179 *obj = iface;
3180 IDWriteTextFormat1_AddRef(iface);
3181 return S_OK;
3184 *obj = NULL;
3186 return E_NOINTERFACE;
3189 static ULONG WINAPI dwritetextformat_AddRef(IDWriteTextFormat1 *iface)
3191 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3192 ULONG ref = InterlockedIncrement(&This->ref);
3193 TRACE("(%p)->(%d)\n", This, ref);
3194 return ref;
3197 static ULONG WINAPI dwritetextformat_Release(IDWriteTextFormat1 *iface)
3199 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3200 ULONG ref = InterlockedDecrement(&This->ref);
3202 TRACE("(%p)->(%d)\n", This, ref);
3204 if (!ref)
3206 release_format_data(&This->format);
3207 heap_free(This);
3210 return ref;
3213 static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
3215 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3216 TRACE("(%p)->(%d)\n", This, alignment);
3217 This->format.textalignment = alignment;
3218 return S_OK;
3221 static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
3223 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3224 TRACE("(%p)->(%d)\n", This, alignment);
3225 This->format.paralign = alignment;
3226 return S_OK;
3229 static HRESULT WINAPI dwritetextformat_SetWordWrapping(IDWriteTextFormat1 *iface, DWRITE_WORD_WRAPPING wrapping)
3231 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3232 TRACE("(%p)->(%d)\n", This, wrapping);
3233 This->format.wrapping = wrapping;
3234 return S_OK;
3237 static HRESULT WINAPI dwritetextformat_SetReadingDirection(IDWriteTextFormat1 *iface, DWRITE_READING_DIRECTION direction)
3239 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3240 TRACE("(%p)->(%d)\n", This, direction);
3241 This->format.readingdir = direction;
3242 return S_OK;
3245 static HRESULT WINAPI dwritetextformat_SetFlowDirection(IDWriteTextFormat1 *iface, DWRITE_FLOW_DIRECTION direction)
3247 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3248 TRACE("(%p)->(%d)\n", This, direction);
3249 This->format.flow = direction;
3250 return S_OK;
3253 static HRESULT WINAPI dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat1 *iface, FLOAT tabstop)
3255 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3256 FIXME("(%p)->(%f): stub\n", This, tabstop);
3257 return E_NOTIMPL;
3260 static HRESULT WINAPI dwritetextformat_SetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING const *trimming,
3261 IDWriteInlineObject *trimming_sign)
3263 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3264 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
3266 This->format.trimming = *trimming;
3267 if (This->format.trimmingsign)
3268 IDWriteInlineObject_Release(This->format.trimmingsign);
3269 This->format.trimmingsign = trimming_sign;
3270 if (This->format.trimmingsign)
3271 IDWriteInlineObject_AddRef(This->format.trimmingsign);
3272 return S_OK;
3275 static HRESULT WINAPI dwritetextformat_SetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD method,
3276 FLOAT spacing, FLOAT baseline)
3278 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3279 TRACE("(%p)->(%d %f %f)\n", This, method, spacing, baseline);
3280 This->format.spacingmethod = method;
3281 This->format.spacing = spacing;
3282 This->format.baseline = baseline;
3283 return S_OK;
3286 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_GetTextAlignment(IDWriteTextFormat1 *iface)
3288 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3289 TRACE("(%p)\n", This);
3290 return This->format.textalignment;
3293 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_GetParagraphAlignment(IDWriteTextFormat1 *iface)
3295 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3296 TRACE("(%p)\n", This);
3297 return This->format.paralign;
3300 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_GetWordWrapping(IDWriteTextFormat1 *iface)
3302 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3303 TRACE("(%p)\n", This);
3304 return This->format.wrapping;
3307 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_GetReadingDirection(IDWriteTextFormat1 *iface)
3309 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3310 TRACE("(%p)\n", This);
3311 return This->format.readingdir;
3314 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_GetFlowDirection(IDWriteTextFormat1 *iface)
3316 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3317 TRACE("(%p)\n", This);
3318 return This->format.flow;
3321 static FLOAT WINAPI dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat1 *iface)
3323 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3324 FIXME("(%p): stub\n", This);
3325 return 0.0;
3328 static HRESULT WINAPI dwritetextformat_GetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING *options,
3329 IDWriteInlineObject **trimming_sign)
3331 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3332 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
3334 *options = This->format.trimming;
3335 if ((*trimming_sign = This->format.trimmingsign))
3336 IDWriteInlineObject_AddRef(*trimming_sign);
3338 return S_OK;
3341 static HRESULT WINAPI dwritetextformat_GetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD *method,
3342 FLOAT *spacing, FLOAT *baseline)
3344 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3345 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
3347 *method = This->format.spacingmethod;
3348 *spacing = This->format.spacing;
3349 *baseline = This->format.baseline;
3350 return S_OK;
3353 static HRESULT WINAPI dwritetextformat_GetFontCollection(IDWriteTextFormat1 *iface, IDWriteFontCollection **collection)
3355 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3357 TRACE("(%p)->(%p)\n", This, collection);
3359 *collection = This->format.collection;
3360 IDWriteFontCollection_AddRef(*collection);
3362 return S_OK;
3365 static UINT32 WINAPI dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat1 *iface)
3367 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3368 TRACE("(%p)\n", This);
3369 return This->format.family_len;
3372 static HRESULT WINAPI dwritetextformat_GetFontFamilyName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
3374 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3376 TRACE("(%p)->(%p %u)\n", This, name, size);
3378 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
3379 strcpyW(name, This->format.family_name);
3380 return S_OK;
3383 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_GetFontWeight(IDWriteTextFormat1 *iface)
3385 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3386 TRACE("(%p)\n", This);
3387 return This->format.weight;
3390 static DWRITE_FONT_STYLE WINAPI dwritetextformat_GetFontStyle(IDWriteTextFormat1 *iface)
3392 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3393 TRACE("(%p)\n", This);
3394 return This->format.style;
3397 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_GetFontStretch(IDWriteTextFormat1 *iface)
3399 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3400 TRACE("(%p)\n", This);
3401 return This->format.stretch;
3404 static FLOAT WINAPI dwritetextformat_GetFontSize(IDWriteTextFormat1 *iface)
3406 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3407 TRACE("(%p)\n", This);
3408 return This->format.fontsize;
3411 static UINT32 WINAPI dwritetextformat_GetLocaleNameLength(IDWriteTextFormat1 *iface)
3413 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3414 TRACE("(%p)\n", This);
3415 return This->format.locale_len;
3418 static HRESULT WINAPI dwritetextformat_GetLocaleName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
3420 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3422 TRACE("(%p)->(%p %u)\n", This, name, size);
3424 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
3425 strcpyW(name, This->format.locale);
3426 return S_OK;
3429 static HRESULT WINAPI dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat1 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
3431 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3433 TRACE("(%p)->(%d)\n", This, orientation);
3435 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
3436 return E_INVALIDARG;
3438 This->format.vertical_orientation = orientation;
3439 return S_OK;
3442 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat1 *iface)
3444 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3445 TRACE("(%p)\n", This);
3446 return This->format.vertical_orientation;
3449 static HRESULT WINAPI dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat1 *iface, BOOL lastline_wrapping_enabled)
3451 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3452 FIXME("(%p)->(%d): stub\n", This, lastline_wrapping_enabled);
3453 return E_NOTIMPL;
3456 static BOOL WINAPI dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat1 *iface)
3458 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3459 FIXME("(%p): stub\n", This);
3460 return FALSE;
3463 static HRESULT WINAPI dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat1 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
3465 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3466 FIXME("(%p)->(%d): stub\n", This, alignment);
3467 return E_NOTIMPL;
3470 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat1 *iface)
3472 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3473 FIXME("(%p): stub\n", This);
3474 return DWRITE_OPTICAL_ALIGNMENT_NONE;
3477 static HRESULT WINAPI dwritetextformat1_SetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback *fallback)
3479 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3480 TRACE("(%p)->(%p)\n", This, fallback);
3481 return set_fontfallback_for_format(&This->format, fallback);
3484 static HRESULT WINAPI dwritetextformat1_GetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback **fallback)
3486 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3487 TRACE("(%p)->(%p)\n", This, fallback);
3488 return get_fontfallback_from_format(&This->format, fallback);
3491 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl = {
3492 dwritetextformat_QueryInterface,
3493 dwritetextformat_AddRef,
3494 dwritetextformat_Release,
3495 dwritetextformat_SetTextAlignment,
3496 dwritetextformat_SetParagraphAlignment,
3497 dwritetextformat_SetWordWrapping,
3498 dwritetextformat_SetReadingDirection,
3499 dwritetextformat_SetFlowDirection,
3500 dwritetextformat_SetIncrementalTabStop,
3501 dwritetextformat_SetTrimming,
3502 dwritetextformat_SetLineSpacing,
3503 dwritetextformat_GetTextAlignment,
3504 dwritetextformat_GetParagraphAlignment,
3505 dwritetextformat_GetWordWrapping,
3506 dwritetextformat_GetReadingDirection,
3507 dwritetextformat_GetFlowDirection,
3508 dwritetextformat_GetIncrementalTabStop,
3509 dwritetextformat_GetTrimming,
3510 dwritetextformat_GetLineSpacing,
3511 dwritetextformat_GetFontCollection,
3512 dwritetextformat_GetFontFamilyNameLength,
3513 dwritetextformat_GetFontFamilyName,
3514 dwritetextformat_GetFontWeight,
3515 dwritetextformat_GetFontStyle,
3516 dwritetextformat_GetFontStretch,
3517 dwritetextformat_GetFontSize,
3518 dwritetextformat_GetLocaleNameLength,
3519 dwritetextformat_GetLocaleName,
3520 dwritetextformat1_SetVerticalGlyphOrientation,
3521 dwritetextformat1_GetVerticalGlyphOrientation,
3522 dwritetextformat1_SetLastLineWrapping,
3523 dwritetextformat1_GetLastLineWrapping,
3524 dwritetextformat1_SetOpticalAlignment,
3525 dwritetextformat1_GetOpticalAlignment,
3526 dwritetextformat1_SetFontFallback,
3527 dwritetextformat1_GetFontFallback
3530 HRESULT create_textformat(const WCHAR *family_name, IDWriteFontCollection *collection, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style,
3531 DWRITE_FONT_STRETCH stretch, FLOAT size, const WCHAR *locale, IDWriteTextFormat **format)
3533 struct dwrite_textformat *This;
3535 *format = NULL;
3537 This = heap_alloc(sizeof(struct dwrite_textformat));
3538 if (!This) return E_OUTOFMEMORY;
3540 This->IDWriteTextFormat1_iface.lpVtbl = &dwritetextformatvtbl;
3541 This->ref = 1;
3542 This->format.family_name = heap_strdupW(family_name);
3543 This->format.family_len = strlenW(family_name);
3544 This->format.locale = heap_strdupW(locale);
3545 This->format.locale_len = strlenW(locale);
3546 This->format.weight = weight;
3547 This->format.style = style;
3548 This->format.fontsize = size;
3549 This->format.stretch = stretch;
3550 This->format.textalignment = DWRITE_TEXT_ALIGNMENT_LEADING;
3551 This->format.paralign = DWRITE_PARAGRAPH_ALIGNMENT_NEAR;
3552 This->format.wrapping = DWRITE_WORD_WRAPPING_WRAP;
3553 This->format.readingdir = DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
3554 This->format.flow = DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM;
3555 This->format.spacingmethod = DWRITE_LINE_SPACING_METHOD_DEFAULT;
3556 This->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
3557 This->format.spacing = 0.0;
3558 This->format.baseline = 0.0;
3559 This->format.trimming.granularity = DWRITE_TRIMMING_GRANULARITY_NONE;
3560 This->format.trimming.delimiter = 0;
3561 This->format.trimming.delimiterCount = 0;
3562 This->format.trimmingsign = NULL;
3563 This->format.collection = collection;
3564 This->format.fallback = NULL;
3565 IDWriteFontCollection_AddRef(collection);
3567 *format = (IDWriteTextFormat*)&This->IDWriteTextFormat1_iface;
3569 return S_OK;
3572 static HRESULT WINAPI dwritetypography_QueryInterface(IDWriteTypography *iface, REFIID riid, void **obj)
3574 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
3576 TRACE("(%p)->(%s %p)\n", typography, debugstr_guid(riid), obj);
3578 if (IsEqualIID(riid, &IID_IDWriteTypography) || IsEqualIID(riid, &IID_IUnknown)) {
3579 *obj = iface;
3580 IDWriteTypography_AddRef(iface);
3581 return S_OK;
3584 *obj = NULL;
3586 return E_NOINTERFACE;
3589 static ULONG WINAPI dwritetypography_AddRef(IDWriteTypography *iface)
3591 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
3592 ULONG ref = InterlockedIncrement(&typography->ref);
3593 TRACE("(%p)->(%d)\n", typography, ref);
3594 return ref;
3597 static ULONG WINAPI dwritetypography_Release(IDWriteTypography *iface)
3599 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
3600 ULONG ref = InterlockedDecrement(&typography->ref);
3602 TRACE("(%p)->(%d)\n", typography, ref);
3604 if (!ref) {
3605 heap_free(typography->features);
3606 heap_free(typography);
3609 return ref;
3612 static HRESULT WINAPI dwritetypography_AddFontFeature(IDWriteTypography *iface, DWRITE_FONT_FEATURE feature)
3614 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
3616 TRACE("(%p)->(%x %u)\n", typography, feature.nameTag, feature.parameter);
3618 if (typography->count == typography->allocated) {
3619 DWRITE_FONT_FEATURE *ptr = heap_realloc(typography->features, 2*typography->allocated*sizeof(DWRITE_FONT_FEATURE));
3620 if (!ptr)
3621 return E_OUTOFMEMORY;
3623 typography->features = ptr;
3624 typography->allocated *= 2;
3627 typography->features[typography->count++] = feature;
3628 return S_OK;
3631 static UINT32 WINAPI dwritetypography_GetFontFeatureCount(IDWriteTypography *iface)
3633 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
3634 TRACE("(%p)\n", typography);
3635 return typography->count;
3638 static HRESULT WINAPI dwritetypography_GetFontFeature(IDWriteTypography *iface, UINT32 index, DWRITE_FONT_FEATURE *feature)
3640 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
3642 TRACE("(%p)->(%u %p)\n", typography, index, feature);
3644 if (index >= typography->count)
3645 return E_INVALIDARG;
3647 *feature = typography->features[index];
3648 return S_OK;
3651 static const IDWriteTypographyVtbl dwritetypographyvtbl = {
3652 dwritetypography_QueryInterface,
3653 dwritetypography_AddRef,
3654 dwritetypography_Release,
3655 dwritetypography_AddFontFeature,
3656 dwritetypography_GetFontFeatureCount,
3657 dwritetypography_GetFontFeature
3660 HRESULT create_typography(IDWriteTypography **ret)
3662 struct dwrite_typography *typography;
3664 *ret = NULL;
3666 typography = heap_alloc(sizeof(*typography));
3667 if (!typography)
3668 return E_OUTOFMEMORY;
3670 typography->IDWriteTypography_iface.lpVtbl = &dwritetypographyvtbl;
3671 typography->ref = 1;
3672 typography->allocated = 2;
3673 typography->count = 0;
3675 typography->features = heap_alloc(typography->allocated*sizeof(DWRITE_FONT_FEATURE));
3676 if (!typography->features) {
3677 heap_free(typography);
3678 return E_OUTOFMEMORY;
3681 *ret = &typography->IDWriteTypography_iface;
3682 return S_OK;