msvcirt: Add implementation of streambuf::sputbackc.
[wine.git] / dlls / dwrite / layout.c
blob611a1e6480a44f6a6d29191f4ff91bfcd417598c
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,
76 LAYOUT_RANGE_ATTR_SPACING
79 struct layout_range_attr_value {
80 DWRITE_TEXT_RANGE range;
81 union {
82 DWRITE_FONT_WEIGHT weight;
83 DWRITE_FONT_STYLE style;
84 DWRITE_FONT_STRETCH stretch;
85 FLOAT fontsize;
86 IDWriteInlineObject *object;
87 IUnknown *effect;
88 BOOL underline;
89 BOOL strikethrough;
90 BOOL pair_kerning;
91 IDWriteFontCollection *collection;
92 const WCHAR *locale;
93 const WCHAR *fontfamily;
94 FLOAT spacing[3]; /* in arguments order - leading, trailing, advance */
95 } u;
98 enum layout_range_kind {
99 LAYOUT_RANGE_REGULAR,
100 LAYOUT_RANGE_STRIKETHROUGH,
101 LAYOUT_RANGE_EFFECT,
102 LAYOUT_RANGE_SPACING
105 struct layout_range_header {
106 struct list entry;
107 enum layout_range_kind kind;
108 DWRITE_TEXT_RANGE range;
111 struct layout_range {
112 struct layout_range_header h;
113 DWRITE_FONT_WEIGHT weight;
114 DWRITE_FONT_STYLE style;
115 FLOAT fontsize;
116 DWRITE_FONT_STRETCH stretch;
117 IDWriteInlineObject *object;
118 BOOL underline;
119 BOOL pair_kerning;
120 IDWriteFontCollection *collection;
121 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
122 WCHAR *fontfamily;
125 struct layout_range_bool {
126 struct layout_range_header h;
127 BOOL value;
130 struct layout_range_effect {
131 struct layout_range_header h;
132 IUnknown *effect;
135 struct layout_range_spacing {
136 struct layout_range_header h;
137 FLOAT leading;
138 FLOAT trailing;
139 FLOAT min_advance;
142 enum layout_run_kind {
143 LAYOUT_RUN_REGULAR,
144 LAYOUT_RUN_INLINE
147 struct inline_object_run {
148 IDWriteInlineObject *object;
149 UINT16 length;
152 struct regular_layout_run {
153 DWRITE_GLYPH_RUN_DESCRIPTION descr;
154 DWRITE_GLYPH_RUN run;
155 DWRITE_SCRIPT_ANALYSIS sa;
156 UINT16 *glyphs;
157 UINT16 *clustermap;
158 FLOAT *advances;
159 DWRITE_GLYPH_OFFSET *offsets;
160 /* this is actual glyph count after shaping, it's not necessary the same as reported to Draw() */
161 UINT32 glyphcount;
164 struct layout_run {
165 struct list entry;
166 enum layout_run_kind kind;
167 union {
168 struct inline_object_run object;
169 struct regular_layout_run regular;
170 } u;
171 FLOAT baseline;
172 FLOAT height;
175 struct layout_effective_run {
176 struct list entry;
177 const struct layout_run *run; /* nominal run this one is based on */
178 UINT32 start; /* relative text position, 0 means first text position of a nominal run */
179 UINT32 length; /* length in codepoints that this run covers */
180 UINT32 glyphcount; /* total glyph count in this run */
181 FLOAT origin_x; /* baseline X position */
182 FLOAT origin_y; /* baseline Y position */
183 UINT16 *clustermap; /* effective clustermap, allocated separately, is not reused from nominal map */
184 UINT32 line;
187 struct layout_effective_inline {
188 struct list entry;
189 IDWriteInlineObject *object;
190 IUnknown *effect;
191 FLOAT origin_x;
192 FLOAT origin_y;
193 BOOL is_sideways;
194 BOOL is_rtl;
195 UINT32 line;
198 struct layout_strikethrough {
199 struct list entry;
200 const struct layout_effective_run *run;
201 DWRITE_STRIKETHROUGH s;
204 struct layout_cluster {
205 const struct layout_run *run; /* link to nominal run this cluster belongs to */
206 UINT32 position; /* relative to run, first cluster has 0 position */
209 enum layout_recompute_mask {
210 RECOMPUTE_NOMINAL_RUNS = 1 << 0,
211 RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
212 RECOMPUTE_EFFECTIVE_RUNS = 1 << 2,
213 RECOMPUTE_EVERYTHING = 0xffff
216 struct dwrite_textlayout {
217 IDWriteTextLayout2 IDWriteTextLayout2_iface;
218 IDWriteTextFormat1 IDWriteTextFormat1_iface;
219 IDWriteTextAnalysisSink IDWriteTextAnalysisSink_iface;
220 IDWriteTextAnalysisSource IDWriteTextAnalysisSource_iface;
221 LONG ref;
223 WCHAR *str;
224 UINT32 len;
225 struct dwrite_textformat_data format;
226 FLOAT maxwidth;
227 FLOAT maxheight;
228 struct list strike_ranges;
229 struct list effects;
230 struct list spacing;
231 struct list ranges;
232 struct list runs;
233 /* lists ready to use by Draw() */
234 struct list eruns;
235 struct list inlineobjects;
236 struct list strikethrough;
237 USHORT recompute;
239 DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
240 DWRITE_LINE_BREAKPOINT *actual_breakpoints;
242 struct layout_cluster *clusters;
243 DWRITE_CLUSTER_METRICS *clustermetrics;
244 UINT32 cluster_count;
245 FLOAT minwidth;
247 DWRITE_LINE_METRICS *lines;
248 UINT32 line_count;
249 UINT32 line_alloc;
251 /* gdi-compatible layout specifics */
252 BOOL gdicompatible;
253 FLOAT pixels_per_dip;
254 BOOL use_gdi_natural;
255 DWRITE_MATRIX transform;
258 struct dwrite_textformat {
259 IDWriteTextFormat1 IDWriteTextFormat1_iface;
260 LONG ref;
261 struct dwrite_textformat_data format;
264 struct dwrite_trimmingsign {
265 IDWriteInlineObject IDWriteInlineObject_iface;
266 LONG ref;
268 IDWriteTextLayout *layout;
271 struct dwrite_typography {
272 IDWriteTypography IDWriteTypography_iface;
273 LONG ref;
275 DWRITE_FONT_FEATURE *features;
276 UINT32 allocated;
277 UINT32 count;
280 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl;
282 static void release_format_data(struct dwrite_textformat_data *data)
284 if (data->collection) IDWriteFontCollection_Release(data->collection);
285 if (data->fallback) IDWriteFontFallback_Release(data->fallback);
286 if (data->trimmingsign) IDWriteInlineObject_Release(data->trimmingsign);
287 heap_free(data->family_name);
288 heap_free(data->locale);
291 static inline struct dwrite_textlayout *impl_from_IDWriteTextLayout2(IDWriteTextLayout2 *iface)
293 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextLayout2_iface);
296 static inline struct dwrite_textlayout *impl_layout_form_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
298 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextFormat1_iface);
301 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSink(IDWriteTextAnalysisSink *iface)
303 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSink_iface);
306 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSource(IDWriteTextAnalysisSource *iface)
308 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSource_iface);
311 static inline struct dwrite_textformat *impl_from_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
313 return CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat1_iface);
316 static inline struct dwrite_trimmingsign *impl_from_IDWriteInlineObject(IDWriteInlineObject *iface)
318 return CONTAINING_RECORD(iface, struct dwrite_trimmingsign, IDWriteInlineObject_iface);
321 static inline struct dwrite_typography *impl_from_IDWriteTypography(IDWriteTypography *iface)
323 return CONTAINING_RECORD(iface, struct dwrite_typography, IDWriteTypography_iface);
326 static inline const char *debugstr_run(const struct regular_layout_run *run)
328 return wine_dbg_sprintf("[%u,%u)", run->descr.textPosition, run->descr.textPosition +
329 run->descr.stringLength);
332 static HRESULT get_fontfallback_from_format(const struct dwrite_textformat_data *format, IDWriteFontFallback **fallback)
334 *fallback = format->fallback;
335 if (*fallback)
336 IDWriteFontFallback_AddRef(*fallback);
337 return S_OK;
340 static HRESULT set_fontfallback_for_format(struct dwrite_textformat_data *format, IDWriteFontFallback *fallback)
342 if (format->fallback)
343 IDWriteFontFallback_Release(format->fallback);
344 format->fallback = fallback;
345 if (fallback)
346 IDWriteFontFallback_AddRef(fallback);
347 return S_OK;
350 static struct layout_run *alloc_layout_run(enum layout_run_kind kind)
352 struct layout_run *ret;
354 ret = heap_alloc(sizeof(*ret));
355 if (!ret) return NULL;
357 memset(ret, 0, sizeof(*ret));
358 ret->kind = kind;
359 if (kind == LAYOUT_RUN_REGULAR) {
360 ret->u.regular.sa.script = Script_Unknown;
361 ret->u.regular.sa.shapes = DWRITE_SCRIPT_SHAPES_DEFAULT;
364 return ret;
367 static void free_layout_runs(struct dwrite_textlayout *layout)
369 struct layout_run *cur, *cur2;
370 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->runs, struct layout_run, entry) {
371 list_remove(&cur->entry);
372 if (cur->kind == LAYOUT_RUN_REGULAR) {
373 if (cur->u.regular.run.fontFace)
374 IDWriteFontFace_Release(cur->u.regular.run.fontFace);
375 heap_free(cur->u.regular.glyphs);
376 heap_free(cur->u.regular.clustermap);
377 heap_free(cur->u.regular.advances);
378 heap_free(cur->u.regular.offsets);
380 heap_free(cur);
384 static void free_layout_eruns(struct dwrite_textlayout *layout)
386 struct layout_effective_inline *in, *in2;
387 struct layout_effective_run *cur, *cur2;
388 struct layout_strikethrough *s, *s2;
390 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->eruns, struct layout_effective_run, entry) {
391 list_remove(&cur->entry);
392 heap_free(cur->clustermap);
393 heap_free(cur);
396 LIST_FOR_EACH_ENTRY_SAFE(in, in2, &layout->inlineobjects, struct layout_effective_inline, entry) {
397 list_remove(&in->entry);
398 heap_free(in);
401 LIST_FOR_EACH_ENTRY_SAFE(s, s2, &layout->strikethrough, struct layout_strikethrough, entry) {
402 list_remove(&s->entry);
403 heap_free(s);
407 /* Used to resolve break condition by forcing stronger condition over weaker. */
408 static inline DWRITE_BREAK_CONDITION override_break_condition(DWRITE_BREAK_CONDITION existingbreak, DWRITE_BREAK_CONDITION newbreak)
410 switch (existingbreak) {
411 case DWRITE_BREAK_CONDITION_NEUTRAL:
412 return newbreak;
413 case DWRITE_BREAK_CONDITION_CAN_BREAK:
414 return newbreak == DWRITE_BREAK_CONDITION_NEUTRAL ? existingbreak : newbreak;
415 /* let's keep stronger conditions as is */
416 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK:
417 case DWRITE_BREAK_CONDITION_MUST_BREAK:
418 break;
419 default:
420 ERR("unknown break condition %d\n", existingbreak);
423 return existingbreak;
426 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
427 static HRESULT layout_update_breakpoints_range(struct dwrite_textlayout *layout, const struct layout_range *cur)
429 DWRITE_BREAK_CONDITION before, after;
430 HRESULT hr;
431 UINT32 i;
433 /* ignore returned conditions if failed */
434 hr = IDWriteInlineObject_GetBreakConditions(cur->object, &before, &after);
435 if (FAILED(hr))
436 after = before = DWRITE_BREAK_CONDITION_NEUTRAL;
438 if (!layout->actual_breakpoints) {
439 layout->actual_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
440 if (!layout->actual_breakpoints)
441 return E_OUTOFMEMORY;
442 memcpy(layout->actual_breakpoints, layout->nominal_breakpoints, sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
445 for (i = cur->h.range.startPosition; i < cur->h.range.length + cur->h.range.startPosition; i++) {
446 /* for first codepoint check if there's anything before it and update accordingly */
447 if (i == cur->h.range.startPosition) {
448 if (i > 0)
449 layout->actual_breakpoints[i].breakConditionBefore = layout->actual_breakpoints[i-1].breakConditionAfter =
450 override_break_condition(layout->actual_breakpoints[i-1].breakConditionAfter, before);
451 else
452 layout->actual_breakpoints[i].breakConditionBefore = before;
453 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
455 /* similar check for last codepoint */
456 else if (i == cur->h.range.startPosition + cur->h.range.length - 1) {
457 if (i == layout->len - 1)
458 layout->actual_breakpoints[i].breakConditionAfter = after;
459 else
460 layout->actual_breakpoints[i].breakConditionAfter = layout->actual_breakpoints[i+1].breakConditionBefore =
461 override_break_condition(layout->actual_breakpoints[i+1].breakConditionBefore, after);
462 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
464 /* for all positions within a range disable breaks */
465 else {
466 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
467 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
470 layout->actual_breakpoints[i].isWhitespace = FALSE;
471 layout->actual_breakpoints[i].isSoftHyphen = FALSE;
474 return S_OK;
477 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos);
479 static inline DWRITE_LINE_BREAKPOINT get_effective_breakpoint(const struct dwrite_textlayout *layout, UINT32 pos)
481 if (layout->actual_breakpoints)
482 return layout->actual_breakpoints[pos];
483 return layout->nominal_breakpoints[pos];
486 static inline void init_cluster_metrics(const struct dwrite_textlayout *layout, const struct regular_layout_run *run,
487 UINT16 start_glyph, UINT16 stop_glyph, UINT32 stop_position, UINT16 length, DWRITE_CLUSTER_METRICS *metrics)
489 UINT8 breakcondition;
490 UINT32 position;
491 UINT16 j;
493 /* For clusters made of control chars we report zero glyphs, and we need zero cluster
494 width as well; advances are already computed at this point and are not necessary zero. */
495 metrics->width = 0.0;
496 if (run->run.glyphCount) {
497 for (j = start_glyph; j < stop_glyph; j++)
498 metrics->width += run->run.glyphAdvances[j];
500 metrics->length = length;
502 position = stop_position;
503 if (stop_glyph == run->glyphcount)
504 breakcondition = get_effective_breakpoint(layout, stop_position).breakConditionAfter;
505 else {
506 breakcondition = get_effective_breakpoint(layout, stop_position).breakConditionBefore;
507 if (stop_position) position = stop_position - 1;
510 metrics->canWrapLineAfter = breakcondition == DWRITE_BREAK_CONDITION_CAN_BREAK ||
511 breakcondition == DWRITE_BREAK_CONDITION_MUST_BREAK;
512 if (metrics->length == 1) {
513 WORD type = 0;
515 GetStringTypeW(CT_CTYPE1, &layout->str[position], 1, &type);
516 metrics->isWhitespace = !!(type & C1_SPACE);
517 metrics->isNewline = FALSE /* FIXME */;
518 metrics->isSoftHyphen = layout->str[position] == 0x00ad /* Unicode Soft Hyphen */;
520 else {
521 metrics->isWhitespace = FALSE;
522 metrics->isNewline = FALSE;
523 metrics->isSoftHyphen = FALSE;
525 metrics->isRightToLeft = run->run.bidiLevel & 1;
526 metrics->padding = 0;
531 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
532 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
533 Note that there's no need to reallocate anything at this point as we allocate one cluster per
534 codepoint initially.
537 static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 *cluster)
539 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[*cluster];
540 struct layout_cluster *c = &layout->clusters[*cluster];
541 const struct regular_layout_run *run = &r->u.regular;
542 UINT32 i, start = 0;
544 for (i = 0; i < run->descr.stringLength; i++) {
545 BOOL end = i == run->descr.stringLength - 1;
547 if (run->descr.clusterMap[start] != run->descr.clusterMap[i]) {
548 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->descr.clusterMap[i], i,
549 i - start, metrics);
550 c->position = start;
551 c->run = r;
553 *cluster += 1;
554 metrics++;
555 c++;
556 start = i;
559 if (end) {
560 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->glyphcount, i,
561 i - start + 1, metrics);
562 c->position = start;
563 c->run = r;
565 *cluster += 1;
566 return;
571 /* This helper should be used to get effective range length, in other words it returns number of text
572 positions from range starting point to the end of the range, limited by layout text length */
573 static inline UINT32 get_clipped_range_length(const struct dwrite_textlayout *layout, const struct layout_range *range)
575 if (range->h.range.startPosition + range->h.range.length <= layout->len)
576 return range->h.range.length;
577 return layout->len - range->h.range.startPosition;
580 static inline FLOAT get_scaled_font_metric(UINT32 metric, FLOAT emSize, const DWRITE_FONT_METRICS *metrics)
582 return (FLOAT)metric * emSize / (FLOAT)metrics->designUnitsPerEm;
585 static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
587 IDWriteTextAnalyzer *analyzer;
588 struct layout_range *range;
589 struct layout_run *r;
590 UINT32 cluster = 0;
591 HRESULT hr;
593 free_layout_eruns(layout);
594 free_layout_runs(layout);
596 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
597 if (!layout->clustermetrics) {
598 layout->clustermetrics = heap_alloc(layout->len*sizeof(*layout->clustermetrics));
599 layout->clusters = heap_alloc(layout->len*sizeof(*layout->clusters));
600 if (!layout->clustermetrics || !layout->clusters) {
601 heap_free(layout->clustermetrics);
602 heap_free(layout->clusters);
603 return E_OUTOFMEMORY;
606 layout->cluster_count = 0;
608 hr = get_textanalyzer(&analyzer);
609 if (FAILED(hr))
610 return hr;
612 LIST_FOR_EACH_ENTRY(range, &layout->ranges, struct layout_range, h.entry) {
613 /* we don't care about ranges that don't contain any text */
614 if (range->h.range.startPosition >= layout->len)
615 break;
617 /* inline objects override actual text in a range */
618 if (range->object) {
619 hr = layout_update_breakpoints_range(layout, range);
620 if (FAILED(hr))
621 return hr;
623 r = alloc_layout_run(LAYOUT_RUN_INLINE);
624 if (!r)
625 return E_OUTOFMEMORY;
627 r->u.object.object = range->object;
628 r->u.object.length = get_clipped_range_length(layout, range);
629 list_add_tail(&layout->runs, &r->entry);
630 continue;
633 /* initial splitting by script */
634 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, &layout->IDWriteTextAnalysisSource_iface,
635 range->h.range.startPosition, get_clipped_range_length(layout, range), &layout->IDWriteTextAnalysisSink_iface);
636 if (FAILED(hr))
637 break;
639 /* this splits it further */
640 hr = IDWriteTextAnalyzer_AnalyzeBidi(analyzer, &layout->IDWriteTextAnalysisSource_iface,
641 range->h.range.startPosition, get_clipped_range_length(layout, range), &layout->IDWriteTextAnalysisSink_iface);
642 if (FAILED(hr))
643 break;
646 /* fill run info */
647 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
648 DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props = NULL;
649 DWRITE_SHAPING_TEXT_PROPERTIES *text_props = NULL;
650 struct regular_layout_run *run = &r->u.regular;
651 DWRITE_FONT_METRICS fontmetrics = { 0 };
652 IDWriteFontFamily *family;
653 UINT32 index, max_count;
654 IDWriteFont *font;
655 BOOL exists = TRUE;
657 /* we need to do very little in case of inline objects */
658 if (r->kind == LAYOUT_RUN_INLINE) {
659 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[cluster];
660 struct layout_cluster *c = &layout->clusters[cluster];
661 DWRITE_INLINE_OBJECT_METRICS inlinemetrics;
663 metrics->width = 0.0;
664 metrics->length = r->u.object.length;
665 metrics->canWrapLineAfter = FALSE;
666 metrics->isWhitespace = FALSE;
667 metrics->isNewline = FALSE;
668 metrics->isSoftHyphen = FALSE;
669 metrics->isRightToLeft = FALSE;
670 metrics->padding = 0;
671 c->run = r;
672 c->position = 0; /* there's always one cluster per inline object, so 0 is valid value */
673 cluster++;
675 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
676 hr = IDWriteInlineObject_GetMetrics(r->u.object.object, &inlinemetrics);
677 if (FAILED(hr)) {
678 memset(&inlinemetrics, 0, sizeof(inlinemetrics));
679 hr = S_OK;
681 metrics->width = inlinemetrics.width;
682 r->baseline = inlinemetrics.baseline;
683 r->height = inlinemetrics.height;
685 /* FIXME: use resolved breakpoints in this case too */
687 continue;
690 range = get_layout_range_by_pos(layout, run->descr.textPosition);
692 hr = IDWriteFontCollection_FindFamilyName(range->collection, range->fontfamily, &index, &exists);
693 if (FAILED(hr) || !exists) {
694 WARN("%s: family %s not found in collection %p\n", debugstr_run(run), debugstr_w(range->fontfamily), range->collection);
695 continue;
698 hr = IDWriteFontCollection_GetFontFamily(range->collection, index, &family);
699 if (FAILED(hr))
700 continue;
702 hr = IDWriteFontFamily_GetFirstMatchingFont(family, range->weight, range->stretch, range->style, &font);
703 IDWriteFontFamily_Release(family);
704 if (FAILED(hr)) {
705 WARN("%s: failed to get a matching font\n", debugstr_run(run));
706 continue;
709 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
710 IDWriteFont_Release(font);
711 if (FAILED(hr))
712 continue;
714 run->run.fontEmSize = range->fontsize;
715 run->descr.localeName = range->locale;
716 run->clustermap = heap_alloc(run->descr.stringLength*sizeof(UINT16));
718 max_count = 3*run->descr.stringLength/2 + 16;
719 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
720 if (!run->clustermap || !run->glyphs)
721 goto memerr;
723 text_props = heap_alloc(run->descr.stringLength*sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
724 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
725 if (!text_props || !glyph_props)
726 goto memerr;
728 while (1) {
729 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, run->descr.string, run->descr.stringLength,
730 run->run.fontFace, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
731 NULL /* FIXME */, NULL, NULL, 0, max_count, run->clustermap, text_props, run->glyphs, glyph_props,
732 &run->glyphcount);
733 if (hr == E_NOT_SUFFICIENT_BUFFER) {
734 heap_free(run->glyphs);
735 heap_free(glyph_props);
737 max_count = run->glyphcount;
739 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
740 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
741 if (!run->glyphs || !glyph_props)
742 goto memerr;
744 continue;
747 break;
750 if (FAILED(hr)) {
751 heap_free(text_props);
752 heap_free(glyph_props);
753 WARN("%s: shaping failed 0x%08x\n", debugstr_run(run), hr);
754 continue;
757 run->run.glyphIndices = run->glyphs;
758 run->descr.clusterMap = run->clustermap;
760 run->advances = heap_alloc(run->glyphcount*sizeof(FLOAT));
761 run->offsets = heap_alloc(run->glyphcount*sizeof(DWRITE_GLYPH_OFFSET));
762 if (!run->advances || !run->offsets)
763 goto memerr;
765 /* now set advances and offsets */
766 if (layout->gdicompatible)
767 hr = IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap,
768 text_props, run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount,
769 run->run.fontFace, run->run.fontEmSize, layout->pixels_per_dip, &layout->transform, layout->use_gdi_natural,
770 run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL, NULL, 0,
771 run->advances, run->offsets);
772 else
773 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap, text_props,
774 run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount, run->run.fontFace,
775 run->run.fontEmSize, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
776 NULL, NULL, 0, run->advances, run->offsets);
778 heap_free(text_props);
779 heap_free(glyph_props);
780 if (FAILED(hr))
781 WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_run(run), hr);
783 run->run.glyphAdvances = run->advances;
784 run->run.glyphOffsets = run->offsets;
786 /* Special treatment of control script, shaping code adds normal glyphs for it,
787 with non-zero advances, and layout code exposes those as zero width clusters,
788 so we have to do it manually. */
789 if (run->sa.script == Script_Common)
790 run->run.glyphCount = 0;
791 else
792 run->run.glyphCount = run->glyphcount;
794 /* baseline derived from font metrics */
795 if (layout->gdicompatible) {
796 /* FIXME: check return value when it's actually implemented */
797 IDWriteFontFace_GetGdiCompatibleMetrics(run->run.fontFace,
798 run->run.fontEmSize,
799 layout->pixels_per_dip,
800 &layout->transform,
801 &fontmetrics);
803 else
804 IDWriteFontFace_GetMetrics(run->run.fontFace, &fontmetrics);
806 r->baseline = get_scaled_font_metric(fontmetrics.ascent, run->run.fontEmSize, &fontmetrics);
807 r->height = get_scaled_font_metric(fontmetrics.ascent + fontmetrics.descent, run->run.fontEmSize, &fontmetrics);
809 layout_set_cluster_metrics(layout, r, &cluster);
811 continue;
813 memerr:
814 heap_free(text_props);
815 heap_free(glyph_props);
816 heap_free(run->clustermap);
817 heap_free(run->glyphs);
818 heap_free(run->advances);
819 heap_free(run->offsets);
820 run->advances = NULL;
821 run->offsets = NULL;
822 run->clustermap = run->glyphs = NULL;
823 hr = E_OUTOFMEMORY;
824 break;
827 if (hr == S_OK)
828 layout->cluster_count = cluster;
830 IDWriteTextAnalyzer_Release(analyzer);
831 return hr;
834 static HRESULT layout_compute(struct dwrite_textlayout *layout)
836 HRESULT hr;
838 if (!(layout->recompute & RECOMPUTE_NOMINAL_RUNS))
839 return S_OK;
841 /* nominal breakpoints are evaluated only once, because string never changes */
842 if (!layout->nominal_breakpoints) {
843 IDWriteTextAnalyzer *analyzer;
844 HRESULT hr;
846 layout->nominal_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
847 if (!layout->nominal_breakpoints)
848 return E_OUTOFMEMORY;
850 hr = get_textanalyzer(&analyzer);
851 if (FAILED(hr))
852 return hr;
854 hr = IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer, &layout->IDWriteTextAnalysisSource_iface,
855 0, layout->len, &layout->IDWriteTextAnalysisSink_iface);
856 IDWriteTextAnalyzer_Release(analyzer);
858 if (layout->actual_breakpoints) {
859 heap_free(layout->actual_breakpoints);
860 layout->actual_breakpoints = NULL;
863 hr = layout_compute_runs(layout);
865 if (TRACE_ON(dwrite)) {
866 struct layout_run *cur;
868 LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
869 if (cur->kind == LAYOUT_RUN_INLINE)
870 TRACE("run inline object %p, len %u\n", cur->u.object.object, cur->u.object.length);
871 else
872 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur->u.regular.descr.textPosition, cur->u.regular.descr.textPosition +
873 cur->u.regular.descr.stringLength-1, cur->u.regular.descr.stringLength, cur->u.regular.run.bidiLevel);
877 layout->recompute &= ~RECOMPUTE_NOMINAL_RUNS;
878 return hr;
881 static inline FLOAT get_cluster_range_width(struct dwrite_textlayout *layout, UINT32 start, UINT32 end)
883 FLOAT width = 0.0;
884 for (; start < end; start++)
885 width += layout->clustermetrics[start].width;
886 return width;
889 static struct layout_range_header *get_layout_range_header_by_pos(struct list *ranges, UINT32 pos)
891 struct layout_range_header *cur;
893 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
894 DWRITE_TEXT_RANGE *r = &cur->range;
895 if (r->startPosition <= pos && pos < r->startPosition + r->length)
896 return cur;
899 return NULL;
902 static inline IUnknown *layout_get_effect_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
904 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->effects, pos);
905 return ((struct layout_range_effect*)h)->effect;
908 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
909 'cluster_count' indicates how many clusters to add, including first one. */
910 static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 first_cluster,
911 UINT32 cluster_count, UINT32 line, FLOAT origin_x, BOOL strikethrough)
913 UINT32 i, start, length, last_cluster;
914 struct layout_effective_run *run;
916 if (r->kind == LAYOUT_RUN_INLINE) {
917 struct layout_effective_inline *inlineobject;
919 inlineobject = heap_alloc(sizeof(*inlineobject));
920 if (!inlineobject)
921 return E_OUTOFMEMORY;
923 inlineobject->object = r->u.object.object;
924 inlineobject->origin_x = origin_x;
925 inlineobject->origin_y = 0.0; /* FIXME */
926 /* It's not clear how these two are set, possibly directionality
927 is derived from surrounding text (replaced text could have
928 different ranges which differ in reading direction). */
929 inlineobject->is_sideways = FALSE;
930 inlineobject->is_rtl = FALSE;
931 inlineobject->line = line;
933 /* effect assigned from start position and on is used for inline objects */
934 inlineobject->effect = layout_get_effect_from_pos(layout, layout->clusters[first_cluster].position);
936 list_add_tail(&layout->inlineobjects, &inlineobject->entry);
937 return S_OK;
940 run = heap_alloc(sizeof(*run));
941 if (!run)
942 return E_OUTOFMEMORY;
944 /* No need to iterate for that, use simple fact that:
945 <last cluster position> = first cluster position> + <sum of cluster lengths not including last one> */
946 last_cluster = first_cluster + cluster_count - 1;
947 length = layout->clusters[last_cluster].position - layout->clusters[first_cluster].position +
948 layout->clustermetrics[last_cluster].length;
950 run->clustermap = heap_alloc(sizeof(UINT16)*length);
951 if (!run->clustermap) {
952 heap_free(run);
953 return E_OUTOFMEMORY;
956 run->run = r;
957 run->start = start = layout->clusters[first_cluster].position;
958 run->length = length;
959 run->origin_x = origin_x;
960 run->origin_y = 0.0; /* set after line is built */
961 run->line = line;
963 if (r->u.regular.run.glyphCount) {
964 /* trim from the left */
965 run->glyphcount = r->u.regular.run.glyphCount - r->u.regular.clustermap[start];
966 /* trim from the right */
967 if (start + length < r->u.regular.descr.stringLength - 1)
968 run->glyphcount -= r->u.regular.run.glyphCount - r->u.regular.clustermap[start + length];
970 else
971 run->glyphcount = 0;
973 /* cluster map needs to be shifted */
974 for (i = 0; i < length; i++)
975 run->clustermap[i] = r->u.regular.clustermap[start + i] - r->u.regular.clustermap[start];
977 list_add_tail(&layout->eruns, &run->entry);
979 /* Strikethrough style is guaranteed to be consistent within effective run,
980 it's width equals to run width, thikness and offset are derived from
981 font metrics, rest of the values are from layout or run itself */
982 if (strikethrough) {
983 DWRITE_FONT_METRICS metrics = { 0 };
984 struct layout_strikethrough *s;
986 s = heap_alloc(sizeof(*s));
987 if (!s)
988 return E_OUTOFMEMORY;
990 if (layout->gdicompatible) {
991 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(
992 r->u.regular.run.fontFace,
993 r->u.regular.run.fontEmSize,
994 layout->pixels_per_dip,
995 &layout->transform,
996 &metrics);
997 if (FAILED(hr))
998 WARN("failed to get font metrics, 0x%08x\n", hr);
1000 else
1001 IDWriteFontFace_GetMetrics(r->u.regular.run.fontFace, &metrics);
1003 s->s.width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1004 s->s.thickness = metrics.strikethroughThickness;
1005 s->s.offset = metrics.strikethroughPosition;
1006 s->s.readingDirection = layout->format.readingdir;
1007 s->s.flowDirection = layout->format.flow;
1008 s->s.localeName = r->u.regular.descr.localeName;
1009 s->s.measuringMode = DWRITE_MEASURING_MODE_NATURAL; /* FIXME */
1010 s->run = run;
1012 list_add_tail(&layout->strikethrough, &s->entry);
1015 return S_OK;
1018 static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_LINE_METRICS *metrics, UINT32 *line)
1020 if (!layout->line_alloc) {
1021 layout->line_alloc = 5;
1022 layout->lines = heap_alloc(layout->line_alloc*sizeof(*layout->lines));
1023 if (!layout->lines)
1024 return E_OUTOFMEMORY;
1027 if (layout->line_count == layout->line_alloc) {
1028 DWRITE_LINE_METRICS *l = heap_realloc(layout->lines, layout->line_alloc*2*sizeof(*layout->lines));
1029 if (!l)
1030 return E_OUTOFMEMORY;
1031 layout->lines = l;
1032 layout->line_alloc *= 2;
1035 layout->lines[*line] = *metrics;
1036 *line += 1;
1037 return S_OK;
1040 static inline BOOL layout_get_strikethrough_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1042 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->strike_ranges, pos);
1043 return ((struct layout_range_bool*)h)->value;
1046 static inline struct layout_effective_run *layout_get_next_erun(struct dwrite_textlayout *layout,
1047 const struct layout_effective_run *cur)
1049 struct list *e;
1051 if (!cur)
1052 e = list_head(&layout->eruns);
1053 else
1054 e = list_next(&layout->eruns, &cur->entry);
1055 if (!e)
1056 return NULL;
1057 return LIST_ENTRY(e, struct layout_effective_run, entry);
1060 static inline struct layout_effective_inline *layout_get_next_inline_run(struct dwrite_textlayout *layout,
1061 const struct layout_effective_inline *cur)
1063 struct list *e;
1065 if (!cur)
1066 e = list_head(&layout->inlineobjects);
1067 else
1068 e = list_next(&layout->inlineobjects, &cur->entry);
1069 if (!e)
1070 return NULL;
1071 return LIST_ENTRY(e, struct layout_effective_inline, entry);
1074 static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
1076 struct layout_effective_inline *inrun;
1077 struct layout_effective_run *erun;
1078 const struct layout_run *run;
1079 DWRITE_LINE_METRICS metrics;
1080 FLOAT width, origin_x, origin_y;
1081 UINT32 i, start, line, textpos;
1082 HRESULT hr;
1083 BOOL s[2];
1085 if (!(layout->recompute & RECOMPUTE_EFFECTIVE_RUNS))
1086 return S_OK;
1088 hr = layout_compute(layout);
1089 if (FAILED(hr))
1090 return hr;
1092 layout->line_count = 0;
1093 origin_x = 0.0;
1094 line = 0;
1095 run = layout->clusters[0].run;
1096 memset(&metrics, 0, sizeof(metrics));
1097 s[0] = s[1] = layout_get_strikethrough_from_pos(layout, 0);
1099 for (i = 0, start = 0, textpos = 0, width = 0.0; i < layout->cluster_count; i++) {
1100 BOOL overflow;
1102 s[1] = layout_get_strikethrough_from_pos(layout, textpos);
1104 /* switched to next nominal run, at this point all previous pending clusters are already
1105 checked for layout line overflow, so new effective run will fit in current line */
1106 if (run != layout->clusters[i].run || s[0] != s[1]) {
1107 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, s[0]);
1108 if (FAILED(hr))
1109 return hr;
1110 origin_x += get_cluster_range_width(layout, start, i);
1111 run = layout->clusters[i].run;
1112 start = i;
1115 overflow = layout->clustermetrics[i].canWrapLineAfter &&
1116 (width + layout->clustermetrics[i].width > layout->maxwidth);
1117 /* check if we got new */
1118 if (overflow ||
1119 layout->clustermetrics[i].isNewline || /* always wrap on new line */
1120 i == layout->cluster_count - 1) /* end of the text */ {
1122 UINT32 strlength, last_cluster = i, index;
1123 FLOAT descent;
1125 if (!overflow) {
1126 metrics.length += layout->clustermetrics[i].length;
1127 last_cluster = i;
1129 else
1130 last_cluster = i ? i - 1 : i;
1132 if (i >= start) {
1133 hr = layout_add_effective_run(layout, run, start, i - start + 1, line, origin_x, s[0]);
1134 if (FAILED(hr))
1135 return hr;
1136 /* we don't need to update origin for next run as we're going to wrap */
1139 /* take a look at clusters we got for this line in reverse order to set
1140 trailing properties for current line */
1141 strlength = metrics.length;
1142 index = last_cluster;
1143 while (strlength) {
1144 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1146 if (!cluster->isNewline && !cluster->isWhitespace)
1147 break;
1149 if (cluster->isNewline) {
1150 metrics.trailingWhitespaceLength += cluster->length;
1151 metrics.newlineLength += cluster->length;
1154 if (cluster->isWhitespace)
1155 metrics.trailingWhitespaceLength += cluster->length;
1157 strlength -= cluster->length;
1158 index--;
1161 /* look for max baseline and descent for this line */
1162 strlength = metrics.length;
1163 index = last_cluster;
1164 metrics.baseline = 0.0;
1165 descent = 0.0;
1166 while (strlength) {
1167 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1168 const struct layout_run *cur = layout->clusters[index].run;
1169 FLOAT cur_descent = cur->height - cur->baseline;
1171 if (cur->baseline > metrics.baseline)
1172 metrics.baseline = cur->baseline;
1174 if (cur_descent > descent)
1175 descent = cur_descent;
1177 strlength -= cluster->length;
1178 index--;
1180 metrics.height = descent + metrics.baseline;
1182 metrics.isTrimmed = width > layout->maxwidth;
1183 hr = layout_set_line_metrics(layout, &metrics, &line);
1184 if (FAILED(hr))
1185 return hr;
1187 width = layout->clustermetrics[i].width;
1188 memset(&metrics, 0, sizeof(metrics));
1189 origin_x = 0.0;
1190 start = i;
1192 else {
1193 metrics.length += layout->clustermetrics[i].length;
1194 width += layout->clustermetrics[i].width;
1197 s[0] = s[1];
1198 textpos += layout->clustermetrics[i].length;
1201 layout->line_count = line;
1203 /* Now all line info is here, update effective runs positions in flow direction */
1204 erun = layout_get_next_erun(layout, NULL);
1205 inrun = layout_get_next_inline_run(layout, NULL);
1207 origin_y = 0.0;
1208 for (line = 0; line < layout->line_count; line++) {
1210 origin_y += layout->lines[line].baseline;
1212 /* For all runs on this line */
1213 while (erun && erun->line == line) {
1214 erun->origin_y = origin_y;
1215 erun = layout_get_next_erun(layout, erun);
1216 if (!erun)
1217 break;
1220 /* Same for inline runs */
1221 while (inrun && inrun->line == line) {
1222 inrun->origin_y = origin_y;
1223 inrun = layout_get_next_inline_run(layout, inrun);
1224 if (!inrun)
1225 break;
1229 layout->recompute &= ~RECOMPUTE_EFFECTIVE_RUNS;
1230 return hr;
1233 static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
1235 struct layout_range_spacing const *range_spacing = (struct layout_range_spacing*)h;
1236 struct layout_range_effect const *range_effect = (struct layout_range_effect*)h;
1237 struct layout_range_bool const *range_bool = (struct layout_range_bool*)h;
1238 struct layout_range const *range = (struct layout_range*)h;
1240 switch (attr) {
1241 case LAYOUT_RANGE_ATTR_WEIGHT:
1242 return range->weight == value->u.weight;
1243 case LAYOUT_RANGE_ATTR_STYLE:
1244 return range->style == value->u.style;
1245 case LAYOUT_RANGE_ATTR_STRETCH:
1246 return range->stretch == value->u.stretch;
1247 case LAYOUT_RANGE_ATTR_FONTSIZE:
1248 return range->fontsize == value->u.fontsize;
1249 case LAYOUT_RANGE_ATTR_INLINE:
1250 return range->object == value->u.object;
1251 case LAYOUT_RANGE_ATTR_EFFECT:
1252 return range_effect->effect == value->u.effect;
1253 case LAYOUT_RANGE_ATTR_UNDERLINE:
1254 return range->underline == value->u.underline;
1255 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
1256 return range_bool->value == value->u.strikethrough;
1257 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
1258 return range->pair_kerning == value->u.pair_kerning;
1259 case LAYOUT_RANGE_ATTR_FONTCOLL:
1260 return range->collection == value->u.collection;
1261 case LAYOUT_RANGE_ATTR_LOCALE:
1262 return strcmpW(range->locale, value->u.locale) == 0;
1263 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1264 return strcmpW(range->fontfamily, value->u.fontfamily) == 0;
1265 case LAYOUT_RANGE_ATTR_SPACING:
1266 return range_spacing->leading == value->u.spacing[0] &&
1267 range_spacing->trailing == value->u.spacing[1] &&
1268 range_spacing->min_advance == value->u.spacing[2];
1269 default:
1273 return FALSE;
1276 static inline BOOL is_same_layout_attributes(struct layout_range_header const *hleft, struct layout_range_header const *hright)
1278 switch (hleft->kind)
1280 case LAYOUT_RANGE_REGULAR:
1282 struct layout_range const *left = (struct layout_range const*)hleft;
1283 struct layout_range const *right = (struct layout_range const*)hright;
1284 return left->weight == right->weight &&
1285 left->style == right->style &&
1286 left->stretch == right->stretch &&
1287 left->fontsize == right->fontsize &&
1288 left->object == right->object &&
1289 left->underline == right->underline &&
1290 left->pair_kerning == right->pair_kerning &&
1291 left->collection == right->collection &&
1292 !strcmpW(left->locale, right->locale) &&
1293 !strcmpW(left->fontfamily, right->fontfamily);
1295 case LAYOUT_RANGE_STRIKETHROUGH:
1297 struct layout_range_bool const *left = (struct layout_range_bool const*)hleft;
1298 struct layout_range_bool const *right = (struct layout_range_bool const*)hright;
1299 return left->value == right->value;
1301 case LAYOUT_RANGE_EFFECT:
1303 struct layout_range_effect const *left = (struct layout_range_effect const*)hleft;
1304 struct layout_range_effect const *right = (struct layout_range_effect const*)hright;
1305 return left->effect == right->effect;
1307 case LAYOUT_RANGE_SPACING:
1309 struct layout_range_spacing const *left = (struct layout_range_spacing const*)hleft;
1310 struct layout_range_spacing const *right = (struct layout_range_spacing const*)hright;
1311 return left->leading == right->leading &&
1312 left->trailing == right->trailing &&
1313 left->min_advance == right->min_advance;
1315 default:
1316 FIXME("unknown range kind %d\n", hleft->kind);
1317 return FALSE;
1321 static inline BOOL is_same_text_range(const DWRITE_TEXT_RANGE *left, const DWRITE_TEXT_RANGE *right)
1323 return left->startPosition == right->startPosition && left->length == right->length;
1326 /* Allocates range and inits it with default values from text format. */
1327 static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout *layout, const DWRITE_TEXT_RANGE *r,
1328 enum layout_range_kind kind)
1330 struct layout_range_header *h;
1332 switch (kind)
1334 case LAYOUT_RANGE_REGULAR:
1336 struct layout_range *range;
1338 range = heap_alloc(sizeof(*range));
1339 if (!range) return NULL;
1341 range->weight = layout->format.weight;
1342 range->style = layout->format.style;
1343 range->stretch = layout->format.stretch;
1344 range->fontsize = layout->format.fontsize;
1345 range->object = NULL;
1346 range->underline = FALSE;
1347 range->pair_kerning = FALSE;
1349 range->fontfamily = heap_strdupW(layout->format.family_name);
1350 if (!range->fontfamily) {
1351 heap_free(range);
1352 return NULL;
1355 range->collection = layout->format.collection;
1356 if (range->collection)
1357 IDWriteFontCollection_AddRef(range->collection);
1358 strcpyW(range->locale, layout->format.locale);
1360 h = &range->h;
1361 break;
1363 case LAYOUT_RANGE_STRIKETHROUGH:
1365 struct layout_range_bool *range;
1367 range = heap_alloc(sizeof(*range));
1368 if (!range) return NULL;
1370 range->value = FALSE;
1371 h = &range->h;
1372 break;
1374 case LAYOUT_RANGE_EFFECT:
1376 struct layout_range_effect *range;
1378 range = heap_alloc(sizeof(*range));
1379 if (!range) return NULL;
1381 range->effect = NULL;
1382 h = &range->h;
1383 break;
1385 case LAYOUT_RANGE_SPACING:
1387 struct layout_range_spacing *range;
1389 range = heap_alloc(sizeof(*range));
1390 if (!range) return NULL;
1392 range->leading = 0.0;
1393 range->trailing = 0.0;
1394 range->min_advance = 0.0;
1395 h = &range->h;
1396 break;
1398 default:
1399 FIXME("unknown range kind %d\n", kind);
1400 return NULL;
1403 h->kind = kind;
1404 h->range = *r;
1405 return h;
1408 static struct layout_range_header *alloc_layout_range_from(struct layout_range_header *h, const DWRITE_TEXT_RANGE *r)
1410 struct layout_range_header *ret;
1412 switch (h->kind)
1414 case LAYOUT_RANGE_REGULAR:
1416 struct layout_range *from = (struct layout_range*)h;
1418 struct layout_range *range = heap_alloc(sizeof(*range));
1419 if (!range) return NULL;
1421 *range = *from;
1422 range->fontfamily = heap_strdupW(from->fontfamily);
1423 if (!range->fontfamily) {
1424 heap_free(range);
1425 return NULL;
1428 /* update refcounts */
1429 if (range->object)
1430 IDWriteInlineObject_AddRef(range->object);
1431 if (range->collection)
1432 IDWriteFontCollection_AddRef(range->collection);
1433 ret = &range->h;
1434 break;
1436 case LAYOUT_RANGE_STRIKETHROUGH:
1438 struct layout_range_bool *strike = heap_alloc(sizeof(*strike));
1439 if (!strike) return NULL;
1441 *strike = *(struct layout_range_bool*)h;
1442 ret = &strike->h;
1443 break;
1445 case LAYOUT_RANGE_EFFECT:
1447 struct layout_range_effect *effect = heap_alloc(sizeof(*effect));
1448 if (!effect) return NULL;
1450 *effect = *(struct layout_range_effect*)h;
1451 if (effect->effect)
1452 IUnknown_AddRef(effect->effect);
1453 ret = &effect->h;
1454 break;
1456 case LAYOUT_RANGE_SPACING:
1458 struct layout_range_spacing *spacing = heap_alloc(sizeof(*spacing));
1459 if (!spacing) return NULL;
1461 *spacing = *(struct layout_range_spacing*)h;
1462 ret = &spacing->h;
1463 break;
1465 default:
1466 FIXME("unknown range kind %d\n", h->kind);
1467 return NULL;
1470 ret->range = *r;
1471 return ret;
1474 static void free_layout_range(struct layout_range_header *h)
1476 if (!h)
1477 return;
1479 switch (h->kind)
1481 case LAYOUT_RANGE_REGULAR:
1483 struct layout_range *range = (struct layout_range*)h;
1485 if (range->object)
1486 IDWriteInlineObject_Release(range->object);
1487 if (range->collection)
1488 IDWriteFontCollection_Release(range->collection);
1489 heap_free(range->fontfamily);
1490 break;
1492 case LAYOUT_RANGE_EFFECT:
1494 struct layout_range_effect *effect = (struct layout_range_effect*)h;
1495 if (effect->effect)
1496 IUnknown_Release(effect->effect);
1497 break;
1499 default:
1503 heap_free(h);
1506 static void free_layout_ranges_list(struct dwrite_textlayout *layout)
1508 struct layout_range_header *cur, *cur2;
1510 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->ranges, struct layout_range_header, entry) {
1511 list_remove(&cur->entry);
1512 free_layout_range(cur);
1515 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->strike_ranges, struct layout_range_header, entry) {
1516 list_remove(&cur->entry);
1517 free_layout_range(cur);
1520 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->effects, struct layout_range_header, entry) {
1521 list_remove(&cur->entry);
1522 free_layout_range(cur);
1525 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->spacing, struct layout_range_header, entry) {
1526 list_remove(&cur->entry);
1527 free_layout_range(cur);
1531 static struct layout_range_header *find_outer_range(struct list *ranges, const DWRITE_TEXT_RANGE *range)
1533 struct layout_range_header *cur;
1535 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
1537 if (cur->range.startPosition > range->startPosition)
1538 return NULL;
1540 if ((cur->range.startPosition + cur->range.length < range->startPosition + range->length) &&
1541 (range->startPosition < cur->range.startPosition + cur->range.length))
1542 return NULL;
1543 if (cur->range.startPosition + cur->range.length >= range->startPosition + range->length)
1544 return cur;
1547 return NULL;
1550 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos)
1552 struct layout_range *cur;
1554 LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, h.entry) {
1555 DWRITE_TEXT_RANGE *r = &cur->h.range;
1556 if (r->startPosition <= pos && pos < r->startPosition + r->length)
1557 return cur;
1560 return NULL;
1563 static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
1565 if (*dest == value) return FALSE;
1567 if (*dest)
1568 IUnknown_Release(*dest);
1569 *dest = value;
1570 if (*dest)
1571 IUnknown_AddRef(*dest);
1573 return TRUE;
1576 static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
1578 struct layout_range_spacing *dest_spacing = (struct layout_range_spacing*)h;
1579 struct layout_range_effect *dest_effect = (struct layout_range_effect*)h;
1580 struct layout_range_bool *dest_bool = (struct layout_range_bool*)h;
1581 struct layout_range *dest = (struct layout_range*)h;
1583 BOOL changed = FALSE;
1585 switch (attr) {
1586 case LAYOUT_RANGE_ATTR_WEIGHT:
1587 changed = dest->weight != value->u.weight;
1588 dest->weight = value->u.weight;
1589 break;
1590 case LAYOUT_RANGE_ATTR_STYLE:
1591 changed = dest->style != value->u.style;
1592 dest->style = value->u.style;
1593 break;
1594 case LAYOUT_RANGE_ATTR_STRETCH:
1595 changed = dest->stretch != value->u.stretch;
1596 dest->stretch = value->u.stretch;
1597 break;
1598 case LAYOUT_RANGE_ATTR_FONTSIZE:
1599 changed = dest->fontsize != value->u.fontsize;
1600 dest->fontsize = value->u.fontsize;
1601 break;
1602 case LAYOUT_RANGE_ATTR_INLINE:
1603 changed = set_layout_range_iface_attr((IUnknown**)&dest->object, (IUnknown*)value->u.object);
1604 break;
1605 case LAYOUT_RANGE_ATTR_EFFECT:
1606 changed = set_layout_range_iface_attr((IUnknown**)&dest_effect->effect, (IUnknown*)value->u.effect);
1607 break;
1608 case LAYOUT_RANGE_ATTR_UNDERLINE:
1609 changed = dest->underline != value->u.underline;
1610 dest->underline = value->u.underline;
1611 break;
1612 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
1613 changed = dest_bool->value != value->u.strikethrough;
1614 dest_bool->value = value->u.strikethrough;
1615 break;
1616 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
1617 changed = dest->pair_kerning != value->u.pair_kerning;
1618 dest->pair_kerning = value->u.pair_kerning;
1619 break;
1620 case LAYOUT_RANGE_ATTR_FONTCOLL:
1621 changed = set_layout_range_iface_attr((IUnknown**)&dest->collection, (IUnknown*)value->u.collection);
1622 break;
1623 case LAYOUT_RANGE_ATTR_LOCALE:
1624 changed = strcmpW(dest->locale, value->u.locale) != 0;
1625 if (changed)
1626 strcpyW(dest->locale, value->u.locale);
1627 break;
1628 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1629 changed = strcmpW(dest->fontfamily, value->u.fontfamily) != 0;
1630 if (changed) {
1631 heap_free(dest->fontfamily);
1632 dest->fontfamily = heap_strdupW(value->u.fontfamily);
1634 break;
1635 case LAYOUT_RANGE_ATTR_SPACING:
1636 changed = dest_spacing->leading != value->u.spacing[0] ||
1637 dest_spacing->trailing != value->u.spacing[1] ||
1638 dest_spacing->min_advance != value->u.spacing[2];
1639 dest_spacing->leading = value->u.spacing[0];
1640 dest_spacing->trailing = value->u.spacing[1];
1641 dest_spacing->min_advance = value->u.spacing[2];
1642 break;
1643 default:
1647 return changed;
1650 static inline BOOL is_in_layout_range(const DWRITE_TEXT_RANGE *outer, const DWRITE_TEXT_RANGE *inner)
1652 return (inner->startPosition >= outer->startPosition) &&
1653 (inner->startPosition + inner->length <= outer->startPosition + outer->length);
1656 static inline HRESULT return_range(const struct layout_range_header *h, DWRITE_TEXT_RANGE *r)
1658 if (r) *r = h->range;
1659 return S_OK;
1662 /* Set attribute value for given range, does all needed splitting/merging of existing ranges. */
1663 static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
1665 struct layout_range_header *cur, *right, *left, *outer;
1666 BOOL changed = FALSE;
1667 struct list *ranges;
1668 DWRITE_TEXT_RANGE r;
1670 /* ignore zero length ranges */
1671 if (value->range.length == 0)
1672 return S_OK;
1674 /* select from ranges lists */
1675 switch (attr)
1677 case LAYOUT_RANGE_ATTR_WEIGHT:
1678 case LAYOUT_RANGE_ATTR_STYLE:
1679 case LAYOUT_RANGE_ATTR_STRETCH:
1680 case LAYOUT_RANGE_ATTR_FONTSIZE:
1681 case LAYOUT_RANGE_ATTR_INLINE:
1682 case LAYOUT_RANGE_ATTR_UNDERLINE:
1683 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
1684 case LAYOUT_RANGE_ATTR_FONTCOLL:
1685 case LAYOUT_RANGE_ATTR_LOCALE:
1686 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1687 ranges = &layout->ranges;
1688 break;
1689 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
1690 ranges = &layout->strike_ranges;
1691 break;
1692 case LAYOUT_RANGE_ATTR_EFFECT:
1693 ranges = &layout->effects;
1694 break;
1695 case LAYOUT_RANGE_ATTR_SPACING:
1696 ranges = &layout->spacing;
1697 break;
1698 default:
1699 FIXME("unknown attr kind %d\n", attr);
1700 return E_FAIL;
1703 /* If new range is completely within existing range, split existing range in two */
1704 if ((outer = find_outer_range(ranges, &value->range))) {
1706 /* no need to add same range */
1707 if (is_same_layout_attrvalue(outer, attr, value))
1708 return S_OK;
1710 /* for matching range bounds just replace data */
1711 if (is_same_text_range(&outer->range, &value->range)) {
1712 changed = set_layout_range_attrval(outer, attr, value);
1713 goto done;
1716 /* add new range to the left */
1717 if (value->range.startPosition == outer->range.startPosition) {
1718 left = alloc_layout_range_from(outer, &value->range);
1719 if (!left) return E_OUTOFMEMORY;
1721 changed = set_layout_range_attrval(left, attr, value);
1722 list_add_before(&outer->entry, &left->entry);
1723 outer->range.startPosition += value->range.length;
1724 outer->range.length -= value->range.length;
1725 goto done;
1728 /* add new range to the right */
1729 if (value->range.startPosition + value->range.length == outer->range.startPosition + outer->range.length) {
1730 right = alloc_layout_range_from(outer, &value->range);
1731 if (!right) return E_OUTOFMEMORY;
1733 changed = set_layout_range_attrval(right, attr, value);
1734 list_add_after(&outer->entry, &right->entry);
1735 outer->range.length -= value->range.length;
1736 goto done;
1739 r.startPosition = value->range.startPosition + value->range.length;
1740 r.length = outer->range.length + outer->range.startPosition - r.startPosition;
1742 /* right part */
1743 right = alloc_layout_range_from(outer, &r);
1744 /* new range in the middle */
1745 cur = alloc_layout_range_from(outer, &value->range);
1746 if (!right || !cur) {
1747 free_layout_range(right);
1748 free_layout_range(cur);
1749 return E_OUTOFMEMORY;
1752 /* reuse container range as a left part */
1753 outer->range.length = value->range.startPosition - outer->range.startPosition;
1755 /* new part */
1756 set_layout_range_attrval(cur, attr, value);
1758 list_add_after(&outer->entry, &cur->entry);
1759 list_add_after(&cur->entry, &right->entry);
1761 return S_OK;
1764 /* Now it's only possible that given range contains some existing ranges, fully or partially.
1765 Update all of them. */
1766 left = get_layout_range_header_by_pos(ranges, value->range.startPosition);
1767 if (left->range.startPosition == value->range.startPosition)
1768 changed = set_layout_range_attrval(left, attr, value);
1769 else /* need to split */ {
1770 r.startPosition = value->range.startPosition;
1771 r.length = left->range.length - value->range.startPosition + left->range.startPosition;
1772 left->range.length -= r.length;
1773 cur = alloc_layout_range_from(left, &r);
1774 changed = set_layout_range_attrval(cur, attr, value);
1775 list_add_after(&left->entry, &cur->entry);
1777 cur = LIST_ENTRY(list_next(ranges, &left->entry), struct layout_range_header, entry);
1779 /* for all existing ranges covered by new one update value */
1780 while (cur && is_in_layout_range(&value->range, &cur->range)) {
1781 changed = set_layout_range_attrval(cur, attr, value);
1782 cur = LIST_ENTRY(list_next(ranges, &cur->entry), struct layout_range_header, entry);
1785 /* it's possible rightmost range intersects */
1786 if (cur && (cur->range.startPosition < value->range.startPosition + value->range.length)) {
1787 r.startPosition = cur->range.startPosition;
1788 r.length = value->range.startPosition + value->range.length - cur->range.startPosition;
1789 left = alloc_layout_range_from(cur, &r);
1790 changed = set_layout_range_attrval(left, attr, value);
1791 cur->range.startPosition += left->range.length;
1792 cur->range.length -= left->range.length;
1793 list_add_before(&cur->entry, &left->entry);
1796 done:
1797 if (changed) {
1798 struct list *next, *i;
1800 layout->recompute = RECOMPUTE_EVERYTHING;
1801 i = list_head(ranges);
1802 while ((next = list_next(ranges, i))) {
1803 struct layout_range_header *next_range = LIST_ENTRY(next, struct layout_range_header, entry);
1805 cur = LIST_ENTRY(i, struct layout_range_header, entry);
1806 if (is_same_layout_attributes(cur, next_range)) {
1807 /* remove similar range */
1808 cur->range.length += next_range->range.length;
1809 list_remove(next);
1810 free_layout_range(next_range);
1812 else
1813 i = list_next(ranges, i);
1817 return S_OK;
1820 static inline const WCHAR *get_string_attribute_ptr(struct layout_range *range, enum layout_range_attr_kind kind)
1822 const WCHAR *str;
1824 switch (kind) {
1825 case LAYOUT_RANGE_ATTR_LOCALE:
1826 str = range->locale;
1827 break;
1828 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1829 str = range->fontfamily;
1830 break;
1831 default:
1832 str = NULL;
1835 return str;
1838 static HRESULT get_string_attribute_length(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
1839 UINT32 *length, DWRITE_TEXT_RANGE *r)
1841 struct layout_range *range;
1842 const WCHAR *str;
1844 range = get_layout_range_by_pos(layout, position);
1845 if (!range) {
1846 *length = 0;
1847 return S_OK;
1850 str = get_string_attribute_ptr(range, kind);
1851 *length = strlenW(str);
1852 return return_range(&range->h, r);
1855 static HRESULT get_string_attribute_value(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
1856 WCHAR *ret, UINT32 length, DWRITE_TEXT_RANGE *r)
1858 struct layout_range *range;
1859 const WCHAR *str;
1861 if (length == 0)
1862 return E_INVALIDARG;
1864 ret[0] = 0;
1865 range = get_layout_range_by_pos(layout, position);
1866 if (!range)
1867 return E_INVALIDARG;
1869 str = get_string_attribute_ptr(range, kind);
1870 if (length < strlenW(str) + 1)
1871 return E_NOT_SUFFICIENT_BUFFER;
1873 strcpyW(ret, str);
1874 return return_range(&range->h, r);
1877 static HRESULT WINAPI dwritetextlayout_QueryInterface(IDWriteTextLayout2 *iface, REFIID riid, void **obj)
1879 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1881 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1883 *obj = NULL;
1885 if (IsEqualIID(riid, &IID_IDWriteTextLayout2) ||
1886 IsEqualIID(riid, &IID_IDWriteTextLayout1) ||
1887 IsEqualIID(riid, &IID_IDWriteTextLayout) ||
1888 IsEqualIID(riid, &IID_IUnknown))
1890 *obj = iface;
1892 else if (IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
1893 IsEqualIID(riid, &IID_IDWriteTextFormat))
1894 *obj = &This->IDWriteTextFormat1_iface;
1896 if (*obj) {
1897 IDWriteTextLayout2_AddRef(iface);
1898 return S_OK;
1901 return E_NOINTERFACE;
1904 static ULONG WINAPI dwritetextlayout_AddRef(IDWriteTextLayout2 *iface)
1906 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1907 ULONG ref = InterlockedIncrement(&This->ref);
1908 TRACE("(%p)->(%d)\n", This, ref);
1909 return ref;
1912 static ULONG WINAPI dwritetextlayout_Release(IDWriteTextLayout2 *iface)
1914 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1915 ULONG ref = InterlockedDecrement(&This->ref);
1917 TRACE("(%p)->(%d)\n", This, ref);
1919 if (!ref) {
1920 free_layout_ranges_list(This);
1921 free_layout_eruns(This);
1922 free_layout_runs(This);
1923 release_format_data(&This->format);
1924 heap_free(This->nominal_breakpoints);
1925 heap_free(This->actual_breakpoints);
1926 heap_free(This->clustermetrics);
1927 heap_free(This->clusters);
1928 heap_free(This->lines);
1929 heap_free(This->str);
1930 heap_free(This);
1933 return ref;
1936 static HRESULT WINAPI dwritetextlayout_SetTextAlignment(IDWriteTextLayout2 *iface, DWRITE_TEXT_ALIGNMENT alignment)
1938 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1939 TRACE("(%p)->(%d)\n", This, alignment);
1940 return IDWriteTextFormat1_SetTextAlignment(&This->IDWriteTextFormat1_iface, alignment);
1943 static HRESULT WINAPI dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout2 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
1945 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1946 TRACE("(%p)->(%d)\n", This, alignment);
1947 return IDWriteTextFormat1_SetParagraphAlignment(&This->IDWriteTextFormat1_iface, alignment);
1950 static HRESULT WINAPI dwritetextlayout_SetWordWrapping(IDWriteTextLayout2 *iface, DWRITE_WORD_WRAPPING wrapping)
1952 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1953 TRACE("(%p)->(%d)\n", This, wrapping);
1954 return IDWriteTextFormat1_SetWordWrapping(&This->IDWriteTextFormat1_iface, wrapping);
1957 static HRESULT WINAPI dwritetextlayout_SetReadingDirection(IDWriteTextLayout2 *iface, DWRITE_READING_DIRECTION direction)
1959 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1960 TRACE("(%p)->(%d)\n", This, direction);
1961 return IDWriteTextFormat1_SetReadingDirection(&This->IDWriteTextFormat1_iface, direction);
1964 static HRESULT WINAPI dwritetextlayout_SetFlowDirection(IDWriteTextLayout2 *iface, DWRITE_FLOW_DIRECTION direction)
1966 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1967 TRACE("(%p)->(%d)\n", This, direction);
1968 return IDWriteTextFormat1_SetFlowDirection(&This->IDWriteTextFormat1_iface, direction);
1971 static HRESULT WINAPI dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout2 *iface, FLOAT tabstop)
1973 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1974 TRACE("(%p)->(%.2f)\n", This, tabstop);
1975 return IDWriteTextFormat1_SetIncrementalTabStop(&This->IDWriteTextFormat1_iface, tabstop);
1978 static HRESULT WINAPI dwritetextlayout_SetTrimming(IDWriteTextLayout2 *iface, DWRITE_TRIMMING const *trimming,
1979 IDWriteInlineObject *trimming_sign)
1981 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1982 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
1983 return IDWriteTextFormat1_SetTrimming(&This->IDWriteTextFormat1_iface, trimming, trimming_sign);
1986 static HRESULT WINAPI dwritetextlayout_SetLineSpacing(IDWriteTextLayout2 *iface, DWRITE_LINE_SPACING_METHOD spacing,
1987 FLOAT line_spacing, FLOAT baseline)
1989 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1990 TRACE("(%p)->(%d %.2f %.2f)\n", This, spacing, line_spacing, baseline);
1991 return IDWriteTextFormat1_SetLineSpacing(&This->IDWriteTextFormat1_iface, spacing, line_spacing, baseline);
1994 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextlayout_GetTextAlignment(IDWriteTextLayout2 *iface)
1996 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1997 TRACE("(%p)\n", This);
1998 return IDWriteTextFormat1_GetTextAlignment(&This->IDWriteTextFormat1_iface);
2001 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout2 *iface)
2003 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2004 TRACE("(%p)\n", This);
2005 return IDWriteTextFormat1_GetParagraphAlignment(&This->IDWriteTextFormat1_iface);
2008 static DWRITE_WORD_WRAPPING WINAPI dwritetextlayout_GetWordWrapping(IDWriteTextLayout2 *iface)
2010 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2011 TRACE("(%p)\n", This);
2012 return IDWriteTextFormat1_GetWordWrapping(&This->IDWriteTextFormat1_iface);
2015 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_GetReadingDirection(IDWriteTextLayout2 *iface)
2017 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2018 TRACE("(%p)\n", This);
2019 return IDWriteTextFormat1_GetReadingDirection(&This->IDWriteTextFormat1_iface);
2022 static DWRITE_FLOW_DIRECTION WINAPI dwritetextlayout_GetFlowDirection(IDWriteTextLayout2 *iface)
2024 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2025 TRACE("(%p)\n", This);
2026 return IDWriteTextFormat1_GetFlowDirection(&This->IDWriteTextFormat1_iface);
2029 static FLOAT WINAPI dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout2 *iface)
2031 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2032 TRACE("(%p)\n", This);
2033 return IDWriteTextFormat1_GetIncrementalTabStop(&This->IDWriteTextFormat1_iface);
2036 static HRESULT WINAPI dwritetextlayout_GetTrimming(IDWriteTextLayout2 *iface, DWRITE_TRIMMING *options,
2037 IDWriteInlineObject **trimming_sign)
2039 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2040 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
2041 return IDWriteTextFormat1_GetTrimming(&This->IDWriteTextFormat1_iface, options, trimming_sign);
2044 static HRESULT WINAPI dwritetextlayout_GetLineSpacing(IDWriteTextLayout2 *iface, DWRITE_LINE_SPACING_METHOD *method,
2045 FLOAT *spacing, FLOAT *baseline)
2047 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2048 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
2049 return IDWriteTextFormat1_GetLineSpacing(&This->IDWriteTextFormat1_iface, method, spacing, baseline);
2052 static HRESULT WINAPI dwritetextlayout_GetFontCollection(IDWriteTextLayout2 *iface, IDWriteFontCollection **collection)
2054 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2055 TRACE("(%p)->(%p)\n", This, collection);
2056 return IDWriteTextFormat1_GetFontCollection(&This->IDWriteTextFormat1_iface, collection);
2059 static UINT32 WINAPI dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout2 *iface)
2061 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2062 TRACE("(%p)\n", This);
2063 return IDWriteTextFormat1_GetFontFamilyNameLength(&This->IDWriteTextFormat1_iface);
2066 static HRESULT WINAPI dwritetextlayout_GetFontFamilyName(IDWriteTextLayout2 *iface, WCHAR *name, UINT32 size)
2068 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2069 TRACE("(%p)->(%p %u)\n", This, name, size);
2070 return IDWriteTextFormat1_GetFontFamilyName(&This->IDWriteTextFormat1_iface, name, size);
2073 static DWRITE_FONT_WEIGHT WINAPI dwritetextlayout_GetFontWeight(IDWriteTextLayout2 *iface)
2075 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2076 TRACE("(%p)\n", This);
2077 return IDWriteTextFormat1_GetFontWeight(&This->IDWriteTextFormat1_iface);
2080 static DWRITE_FONT_STYLE WINAPI dwritetextlayout_GetFontStyle(IDWriteTextLayout2 *iface)
2082 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2083 TRACE("(%p)\n", This);
2084 return IDWriteTextFormat1_GetFontStyle(&This->IDWriteTextFormat1_iface);
2087 static DWRITE_FONT_STRETCH WINAPI dwritetextlayout_GetFontStretch(IDWriteTextLayout2 *iface)
2089 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2090 TRACE("(%p)\n", This);
2091 return IDWriteTextFormat1_GetFontStretch(&This->IDWriteTextFormat1_iface);
2094 static FLOAT WINAPI dwritetextlayout_GetFontSize(IDWriteTextLayout2 *iface)
2096 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2097 TRACE("(%p)\n", This);
2098 return IDWriteTextFormat1_GetFontSize(&This->IDWriteTextFormat1_iface);
2101 static UINT32 WINAPI dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout2 *iface)
2103 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2104 TRACE("(%p)\n", This);
2105 return IDWriteTextFormat1_GetLocaleNameLength(&This->IDWriteTextFormat1_iface);
2108 static HRESULT WINAPI dwritetextlayout_GetLocaleName(IDWriteTextLayout2 *iface, WCHAR *name, UINT32 size)
2110 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2111 TRACE("(%p)->(%p %u)\n", This, name, size);
2112 return IDWriteTextFormat1_GetLocaleName(&This->IDWriteTextFormat1_iface, name, size);
2115 static HRESULT WINAPI dwritetextlayout_SetMaxWidth(IDWriteTextLayout2 *iface, FLOAT maxWidth)
2117 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2118 TRACE("(%p)->(%.1f)\n", This, maxWidth);
2120 if (maxWidth < 0.0)
2121 return E_INVALIDARG;
2123 This->maxwidth = maxWidth;
2124 return S_OK;
2127 static HRESULT WINAPI dwritetextlayout_SetMaxHeight(IDWriteTextLayout2 *iface, FLOAT maxHeight)
2129 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2130 TRACE("(%p)->(%.1f)\n", This, maxHeight);
2132 if (maxHeight < 0.0)
2133 return E_INVALIDARG;
2135 This->maxheight = maxHeight;
2136 return S_OK;
2139 static HRESULT WINAPI dwritetextlayout_SetFontCollection(IDWriteTextLayout2 *iface, IDWriteFontCollection* collection, DWRITE_TEXT_RANGE range)
2141 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2142 struct layout_range_attr_value value;
2144 TRACE("(%p)->(%p %s)\n", This, collection, debugstr_range(&range));
2146 value.range = range;
2147 value.u.collection = collection;
2148 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTCOLL, &value);
2151 static HRESULT WINAPI dwritetextlayout_SetFontFamilyName(IDWriteTextLayout2 *iface, WCHAR const *name, DWRITE_TEXT_RANGE range)
2153 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2154 struct layout_range_attr_value value;
2156 TRACE("(%p)->(%s %s)\n", This, debugstr_w(name), debugstr_range(&range));
2158 if (!name)
2159 return E_INVALIDARG;
2161 value.range = range;
2162 value.u.fontfamily = name;
2163 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTFAMILY, &value);
2166 static HRESULT WINAPI dwritetextlayout_SetFontWeight(IDWriteTextLayout2 *iface, DWRITE_FONT_WEIGHT weight, DWRITE_TEXT_RANGE range)
2168 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2169 struct layout_range_attr_value value;
2171 TRACE("(%p)->(%d %s)\n", This, weight, debugstr_range(&range));
2173 value.range = range;
2174 value.u.weight = weight;
2175 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_WEIGHT, &value);
2178 static HRESULT WINAPI dwritetextlayout_SetFontStyle(IDWriteTextLayout2 *iface, DWRITE_FONT_STYLE style, 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, style, debugstr_range(&range));
2185 if ((UINT32)style > DWRITE_FONT_STYLE_ITALIC)
2186 return E_INVALIDARG;
2188 value.range = range;
2189 value.u.style = style;
2190 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STYLE, &value);
2193 static HRESULT WINAPI dwritetextlayout_SetFontStretch(IDWriteTextLayout2 *iface, DWRITE_FONT_STRETCH stretch, DWRITE_TEXT_RANGE range)
2195 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2196 struct layout_range_attr_value value;
2198 TRACE("(%p)->(%d %s)\n", This, stretch, debugstr_range(&range));
2200 if (stretch == DWRITE_FONT_STRETCH_UNDEFINED || (UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
2201 return E_INVALIDARG;
2203 value.range = range;
2204 value.u.stretch = stretch;
2205 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRETCH, &value);
2208 static HRESULT WINAPI dwritetextlayout_SetFontSize(IDWriteTextLayout2 *iface, FLOAT size, DWRITE_TEXT_RANGE range)
2210 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2211 struct layout_range_attr_value value;
2213 TRACE("(%p)->(%.2f %s)\n", This, size, debugstr_range(&range));
2215 if (size <= 0.0)
2216 return E_INVALIDARG;
2218 value.range = range;
2219 value.u.fontsize = size;
2220 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTSIZE, &value);
2223 static HRESULT WINAPI dwritetextlayout_SetUnderline(IDWriteTextLayout2 *iface, BOOL underline, DWRITE_TEXT_RANGE range)
2225 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2226 struct layout_range_attr_value value;
2228 TRACE("(%p)->(%d %s)\n", This, underline, debugstr_range(&range));
2230 value.range = range;
2231 value.u.underline = underline;
2232 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_UNDERLINE, &value);
2235 static HRESULT WINAPI dwritetextlayout_SetStrikethrough(IDWriteTextLayout2 *iface, BOOL strikethrough, DWRITE_TEXT_RANGE range)
2237 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2238 struct layout_range_attr_value value;
2240 TRACE("(%p)->(%d %s)\n", This, strikethrough, debugstr_range(&range));
2242 value.range = range;
2243 value.u.strikethrough = strikethrough;
2244 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRIKETHROUGH, &value);
2247 static HRESULT WINAPI dwritetextlayout_SetDrawingEffect(IDWriteTextLayout2 *iface, IUnknown* effect, DWRITE_TEXT_RANGE range)
2249 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2250 struct layout_range_attr_value value;
2252 TRACE("(%p)->(%p %s)\n", This, effect, debugstr_range(&range));
2254 value.range = range;
2255 value.u.effect = effect;
2256 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_EFFECT, &value);
2259 static HRESULT WINAPI dwritetextlayout_SetInlineObject(IDWriteTextLayout2 *iface, IDWriteInlineObject *object, DWRITE_TEXT_RANGE range)
2261 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2262 struct layout_range_attr_value value;
2264 TRACE("(%p)->(%p %s)\n", This, object, debugstr_range(&range));
2266 value.range = range;
2267 value.u.object = object;
2268 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_INLINE, &value);
2271 static HRESULT WINAPI dwritetextlayout_SetTypography(IDWriteTextLayout2 *iface, IDWriteTypography* typography, DWRITE_TEXT_RANGE range)
2273 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2274 FIXME("(%p)->(%p %s): stub\n", This, typography, debugstr_range(&range));
2275 return E_NOTIMPL;
2278 static HRESULT WINAPI dwritetextlayout_SetLocaleName(IDWriteTextLayout2 *iface, WCHAR const* locale, DWRITE_TEXT_RANGE range)
2280 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2281 struct layout_range_attr_value value;
2283 TRACE("(%p)->(%s %s)\n", This, debugstr_w(locale), debugstr_range(&range));
2285 if (!locale || strlenW(locale) > LOCALE_NAME_MAX_LENGTH-1)
2286 return E_INVALIDARG;
2288 value.range = range;
2289 value.u.locale = locale;
2290 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_LOCALE, &value);
2293 static FLOAT WINAPI dwritetextlayout_GetMaxWidth(IDWriteTextLayout2 *iface)
2295 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2296 TRACE("(%p)\n", This);
2297 return This->maxwidth;
2300 static FLOAT WINAPI dwritetextlayout_GetMaxHeight(IDWriteTextLayout2 *iface)
2302 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2303 TRACE("(%p)\n", This);
2304 return This->maxheight;
2307 static HRESULT WINAPI dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout2 *iface, UINT32 position,
2308 IDWriteFontCollection** collection, DWRITE_TEXT_RANGE *r)
2310 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2311 struct layout_range *range;
2313 TRACE("(%p)->(%u %p %p)\n", This, position, collection, r);
2315 if (position >= This->len)
2316 return S_OK;
2318 range = get_layout_range_by_pos(This, position);
2319 *collection = range->collection;
2320 if (*collection)
2321 IDWriteFontCollection_AddRef(*collection);
2323 return return_range(&range->h, r);
2326 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout2 *iface,
2327 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
2329 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2330 TRACE("(%p)->(%d %p %p)\n", This, position, length, r);
2331 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, length, r);
2334 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout2 *iface,
2335 UINT32 position, WCHAR *name, UINT32 length, DWRITE_TEXT_RANGE *r)
2337 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2338 TRACE("(%p)->(%u %p %u %p)\n", This, position, name, length, r);
2339 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, name, length, r);
2342 static HRESULT WINAPI dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout2 *iface,
2343 UINT32 position, DWRITE_FONT_WEIGHT *weight, DWRITE_TEXT_RANGE *r)
2345 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2346 struct layout_range *range;
2348 TRACE("(%p)->(%u %p %p)\n", This, position, weight, r);
2350 if (position >= This->len)
2351 return S_OK;
2353 range = get_layout_range_by_pos(This, position);
2354 *weight = range->weight;
2356 return return_range(&range->h, r);
2359 static HRESULT WINAPI dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout2 *iface,
2360 UINT32 position, DWRITE_FONT_STYLE *style, DWRITE_TEXT_RANGE *r)
2362 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2363 struct layout_range *range;
2365 TRACE("(%p)->(%u %p %p)\n", This, position, style, r);
2367 range = get_layout_range_by_pos(This, position);
2368 *style = range->style;
2369 return return_range(&range->h, r);
2372 static HRESULT WINAPI dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout2 *iface,
2373 UINT32 position, DWRITE_FONT_STRETCH *stretch, DWRITE_TEXT_RANGE *r)
2375 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2376 struct layout_range *range;
2378 TRACE("(%p)->(%u %p %p)\n", This, position, stretch, r);
2380 range = get_layout_range_by_pos(This, position);
2381 *stretch = range->stretch;
2382 return return_range(&range->h, r);
2385 static HRESULT WINAPI dwritetextlayout_layout_GetFontSize(IDWriteTextLayout2 *iface,
2386 UINT32 position, FLOAT *size, DWRITE_TEXT_RANGE *r)
2388 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2389 struct layout_range *range;
2391 TRACE("(%p)->(%u %p %p)\n", This, position, size, r);
2393 range = get_layout_range_by_pos(This, position);
2394 *size = range->fontsize;
2395 return return_range(&range->h, r);
2398 static HRESULT WINAPI dwritetextlayout_GetUnderline(IDWriteTextLayout2 *iface,
2399 UINT32 position, BOOL *underline, DWRITE_TEXT_RANGE *r)
2401 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2402 struct layout_range *range;
2404 TRACE("(%p)->(%u %p %p)\n", This, position, underline, r);
2406 if (position >= This->len)
2407 return S_OK;
2409 range = get_layout_range_by_pos(This, position);
2410 *underline = range->underline;
2412 return return_range(&range->h, r);
2415 static HRESULT WINAPI dwritetextlayout_GetStrikethrough(IDWriteTextLayout2 *iface,
2416 UINT32 position, BOOL *strikethrough, DWRITE_TEXT_RANGE *r)
2418 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2419 struct layout_range_bool *range;
2421 TRACE("(%p)->(%u %p %p)\n", This, position, strikethrough, r);
2423 range = (struct layout_range_bool*)get_layout_range_header_by_pos(&This->strike_ranges, position);
2424 *strikethrough = range->value;
2426 return return_range(&range->h, r);
2429 static HRESULT WINAPI dwritetextlayout_GetDrawingEffect(IDWriteTextLayout2 *iface,
2430 UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r)
2432 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2433 struct layout_range_effect *range;
2435 TRACE("(%p)->(%u %p %p)\n", This, position, effect, r);
2437 range = (struct layout_range_effect*)get_layout_range_header_by_pos(&This->effects, position);
2438 *effect = range->effect;
2439 if (*effect)
2440 IUnknown_AddRef(*effect);
2442 return return_range(&range->h, r);
2445 static HRESULT WINAPI dwritetextlayout_GetInlineObject(IDWriteTextLayout2 *iface,
2446 UINT32 position, IDWriteInlineObject **object, DWRITE_TEXT_RANGE *r)
2448 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2449 struct layout_range *range;
2451 TRACE("(%p)->(%u %p %p)\n", This, position, object, r);
2453 if (position >= This->len)
2454 return S_OK;
2456 range = get_layout_range_by_pos(This, position);
2457 *object = range->object;
2458 if (*object)
2459 IDWriteInlineObject_AddRef(*object);
2461 return return_range(&range->h, r);
2464 static HRESULT WINAPI dwritetextlayout_GetTypography(IDWriteTextLayout2 *iface,
2465 UINT32 position, IDWriteTypography** typography, DWRITE_TEXT_RANGE *range)
2467 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2468 FIXME("(%p)->(%u %p %p): stub\n", This, position, typography, range);
2469 return E_NOTIMPL;
2472 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout2 *iface,
2473 UINT32 position, UINT32* length, DWRITE_TEXT_RANGE *r)
2475 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2476 TRACE("(%p)->(%u %p %p)\n", This, position, length, r);
2477 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_LOCALE, position, length, r);
2480 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout2 *iface,
2481 UINT32 position, WCHAR* locale, UINT32 length, DWRITE_TEXT_RANGE *r)
2483 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2484 TRACE("(%p)->(%u %p %u %p)\n", This, position, locale, length, r);
2485 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_LOCALE, position, locale, length, r);
2488 static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface,
2489 void *context, IDWriteTextRenderer* renderer, FLOAT origin_x, FLOAT origin_y)
2491 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2492 struct layout_effective_inline *inlineobject;
2493 struct layout_effective_run *run;
2494 struct layout_strikethrough *s;
2495 HRESULT hr;
2497 TRACE("(%p)->(%p %p %.2f %.2f)\n", This, context, renderer, origin_x, origin_y);
2499 hr = layout_compute_effective_runs(This);
2500 if (FAILED(hr))
2501 return hr;
2503 /* 1. Regular runs */
2504 LIST_FOR_EACH_ENTRY(run, &This->eruns, struct layout_effective_run, entry) {
2505 const struct regular_layout_run *regular = &run->run->u.regular;
2506 UINT32 start_glyph = regular->clustermap[run->start];
2507 DWRITE_GLYPH_RUN_DESCRIPTION descr;
2508 DWRITE_GLYPH_RUN glyph_run;
2510 /* Everything but cluster map will be reused from nominal run, as we only need
2511 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
2512 it can't be reused because it has to start with 0 index for each reported run. */
2513 glyph_run = regular->run;
2514 glyph_run.glyphCount = run->glyphcount;
2516 /* fixup glyph data arrays */
2517 glyph_run.glyphIndices += start_glyph;
2518 glyph_run.glyphAdvances += start_glyph;
2519 glyph_run.glyphOffsets += start_glyph;
2521 /* description */
2522 descr = regular->descr;
2523 descr.stringLength = run->length;
2524 descr.string += run->start;
2525 descr.clusterMap = run->clustermap;
2526 descr.textPosition += run->start;
2528 /* return value is ignored */
2529 IDWriteTextRenderer_DrawGlyphRun(renderer,
2530 context,
2531 run->origin_x + origin_x,
2532 run->origin_y + origin_y,
2533 DWRITE_MEASURING_MODE_NATURAL,
2534 &glyph_run,
2535 &descr,
2536 NULL);
2539 /* 2. Inline objects */
2540 LIST_FOR_EACH_ENTRY(inlineobject, &This->inlineobjects, struct layout_effective_inline, entry) {
2541 IDWriteTextRenderer_DrawInlineObject(renderer,
2542 context,
2543 inlineobject->origin_x,
2544 inlineobject->origin_y,
2545 inlineobject->object,
2546 inlineobject->is_sideways,
2547 inlineobject->is_rtl,
2548 inlineobject->effect);
2551 /* TODO: 3. Underlines */
2553 /* 4. Strikethrough */
2554 LIST_FOR_EACH_ENTRY(s, &This->strikethrough, struct layout_strikethrough, entry) {
2555 IDWriteTextRenderer_DrawStrikethrough(renderer,
2556 context,
2557 s->run->origin_x,
2558 s->run->origin_y,
2559 &s->s,
2560 NULL);
2563 return S_OK;
2566 static HRESULT WINAPI dwritetextlayout_GetLineMetrics(IDWriteTextLayout2 *iface,
2567 DWRITE_LINE_METRICS *metrics, UINT32 max_count, UINT32 *count)
2569 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2570 HRESULT hr;
2572 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
2574 hr = layout_compute_effective_runs(This);
2575 if (FAILED(hr))
2576 return hr;
2578 if (metrics)
2579 memcpy(metrics, This->lines, sizeof(DWRITE_LINE_METRICS)*min(max_count, This->line_count));
2581 *count = This->line_count;
2582 return max_count >= This->line_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
2585 static HRESULT WINAPI dwritetextlayout_GetMetrics(IDWriteTextLayout2 *iface, DWRITE_TEXT_METRICS *metrics)
2587 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2588 DWRITE_TEXT_METRICS1 metrics1;
2589 HRESULT hr;
2591 TRACE("(%p)->(%p)\n", This, metrics);
2593 hr = IDWriteTextLayout2_GetMetrics(iface, &metrics1);
2594 if (hr == S_OK)
2595 memcpy(metrics, &metrics1, sizeof(*metrics));
2597 return hr;
2600 static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout2 *iface, DWRITE_OVERHANG_METRICS *overhangs)
2602 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2603 FIXME("(%p)->(%p): stub\n", This, overhangs);
2604 return E_NOTIMPL;
2607 static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout2 *iface,
2608 DWRITE_CLUSTER_METRICS *metrics, UINT32 max_count, UINT32 *count)
2610 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2611 HRESULT hr;
2613 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
2615 hr = layout_compute(This);
2616 if (FAILED(hr))
2617 return hr;
2619 if (metrics)
2620 memcpy(metrics, This->clustermetrics, sizeof(DWRITE_CLUSTER_METRICS)*min(max_count, This->cluster_count));
2622 *count = This->cluster_count;
2623 return max_count >= This->cluster_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
2626 /* Only to be used with DetermineMinWidth() to find the longest cluster sequence that we don't want to try
2627 too hard to break. */
2628 static inline BOOL is_terminal_cluster(struct dwrite_textlayout *layout, UINT32 index)
2630 if (layout->clustermetrics[index].isWhitespace || layout->clustermetrics[index].isNewline ||
2631 (index == layout->cluster_count - 1))
2632 return TRUE;
2633 /* check next one */
2634 return (index < layout->cluster_count - 1) && layout->clustermetrics[index+1].isWhitespace;
2637 static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout2 *iface, FLOAT* min_width)
2639 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2640 FLOAT width;
2641 HRESULT hr;
2642 UINT32 i;
2644 TRACE("(%p)->(%p)\n", This, min_width);
2646 if (!min_width)
2647 return E_INVALIDARG;
2649 if (!(This->recompute & RECOMPUTE_MINIMAL_WIDTH))
2650 goto width_done;
2652 *min_width = 0.0;
2653 hr = layout_compute(This);
2654 if (FAILED(hr))
2655 return hr;
2657 for (i = 0; i < This->cluster_count;) {
2658 if (is_terminal_cluster(This, i)) {
2659 width = This->clustermetrics[i].width;
2660 i++;
2662 else {
2663 width = 0.0;
2664 while (!is_terminal_cluster(This, i)) {
2665 width += This->clustermetrics[i].width;
2666 i++;
2668 /* count last one too */
2669 width += This->clustermetrics[i].width;
2672 if (width > This->minwidth)
2673 This->minwidth = width;
2675 This->recompute &= ~RECOMPUTE_MINIMAL_WIDTH;
2677 width_done:
2678 *min_width = This->minwidth;
2679 return S_OK;
2682 static HRESULT WINAPI dwritetextlayout_HitTestPoint(IDWriteTextLayout2 *iface,
2683 FLOAT pointX, FLOAT pointY, BOOL* is_trailinghit, BOOL* is_inside, DWRITE_HIT_TEST_METRICS *metrics)
2685 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2686 FIXME("(%p)->(%f %f %p %p %p): stub\n", This, pointX, pointY, is_trailinghit, is_inside, metrics);
2687 return E_NOTIMPL;
2690 static HRESULT WINAPI dwritetextlayout_HitTestTextPosition(IDWriteTextLayout2 *iface,
2691 UINT32 textPosition, BOOL is_trailinghit, FLOAT* pointX, FLOAT* pointY, DWRITE_HIT_TEST_METRICS *metrics)
2693 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2694 FIXME("(%p)->(%u %d %p %p %p): stub\n", This, textPosition, is_trailinghit, pointX, pointY, metrics);
2695 return E_NOTIMPL;
2698 static HRESULT WINAPI dwritetextlayout_HitTestTextRange(IDWriteTextLayout2 *iface,
2699 UINT32 textPosition, UINT32 textLength, FLOAT originX, FLOAT originY,
2700 DWRITE_HIT_TEST_METRICS *metrics, UINT32 max_metricscount, UINT32* actual_metricscount)
2702 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2703 FIXME("(%p)->(%u %u %f %f %p %u %p): stub\n", This, textPosition, textLength, originX, originY, metrics,
2704 max_metricscount, actual_metricscount);
2705 return E_NOTIMPL;
2708 static HRESULT WINAPI dwritetextlayout1_SetPairKerning(IDWriteTextLayout2 *iface, BOOL is_pairkerning_enabled,
2709 DWRITE_TEXT_RANGE range)
2711 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2712 struct layout_range_attr_value value;
2714 TRACE("(%p)->(%d %s)\n", This, is_pairkerning_enabled, debugstr_range(&range));
2716 value.range = range;
2717 value.u.pair_kerning = !!is_pairkerning_enabled;
2718 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_PAIR_KERNING, &value);
2721 static HRESULT WINAPI dwritetextlayout1_GetPairKerning(IDWriteTextLayout2 *iface, UINT32 position, BOOL *is_pairkerning_enabled,
2722 DWRITE_TEXT_RANGE *r)
2724 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2725 struct layout_range *range;
2727 TRACE("(%p)->(%u %p %p)\n", This, position, is_pairkerning_enabled, r);
2729 if (position >= This->len)
2730 return S_OK;
2732 range = get_layout_range_by_pos(This, position);
2733 *is_pairkerning_enabled = range->pair_kerning;
2735 return return_range(&range->h, r);
2738 static HRESULT WINAPI dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout2 *iface, FLOAT leading, FLOAT trailing,
2739 FLOAT min_advance, DWRITE_TEXT_RANGE range)
2741 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2742 struct layout_range_attr_value value;
2744 TRACE("(%p)->(%.2f %.2f %.2f %s)\n", This, leading, trailing, min_advance, debugstr_range(&range));
2746 if (min_advance < 0.0)
2747 return E_INVALIDARG;
2749 value.range = range;
2750 value.u.spacing[0] = leading;
2751 value.u.spacing[1] = trailing;
2752 value.u.spacing[2] = min_advance;
2753 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_SPACING, &value);
2756 static HRESULT WINAPI dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout2 *iface, UINT32 position, FLOAT *leading,
2757 FLOAT *trailing, FLOAT *min_advance, DWRITE_TEXT_RANGE *r)
2759 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2760 struct layout_range_spacing *range;
2762 TRACE("(%p)->(%u %p %p %p %p)\n", This, position, leading, trailing, min_advance, r);
2764 range = (struct layout_range_spacing*)get_layout_range_header_by_pos(&This->spacing, position);
2765 *leading = range->leading;
2766 *trailing = range->trailing;
2767 *min_advance = range->min_advance;
2769 return return_range(&range->h, r);
2772 static HRESULT WINAPI dwritetextlayout2_GetMetrics(IDWriteTextLayout2 *iface, DWRITE_TEXT_METRICS1 *metrics)
2774 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2775 FIXME("(%p)->(%p): stub\n", This, metrics);
2776 return E_NOTIMPL;
2779 static HRESULT WINAPI dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout2 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
2781 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2783 TRACE("(%p)->(%d)\n", This, orientation);
2785 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
2786 return E_INVALIDARG;
2788 This->format.vertical_orientation = orientation;
2789 return S_OK;
2792 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout2 *iface)
2794 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2795 TRACE("(%p)\n", This);
2796 return This->format.vertical_orientation;
2799 static HRESULT WINAPI dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout2 *iface, BOOL lastline_wrapping_enabled)
2801 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2802 FIXME("(%p)->(%d): stub\n", This, lastline_wrapping_enabled);
2803 return E_NOTIMPL;
2806 static BOOL WINAPI dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout2 *iface)
2808 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2809 FIXME("(%p): stub\n", This);
2810 return FALSE;
2813 static HRESULT WINAPI dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout2 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
2815 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2816 FIXME("(%p)->(%d): stub\n", This, alignment);
2817 return E_NOTIMPL;
2820 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout2 *iface)
2822 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2823 FIXME("(%p): stub\n", This);
2824 return DWRITE_OPTICAL_ALIGNMENT_NONE;
2827 static HRESULT WINAPI dwritetextlayout2_SetFontFallback(IDWriteTextLayout2 *iface, IDWriteFontFallback *fallback)
2829 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2830 TRACE("(%p)->(%p)\n", This, fallback);
2831 return set_fontfallback_for_format(&This->format, fallback);
2834 static HRESULT WINAPI dwritetextlayout2_GetFontFallback(IDWriteTextLayout2 *iface, IDWriteFontFallback **fallback)
2836 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2837 TRACE("(%p)->(%p)\n", This, fallback);
2838 return get_fontfallback_from_format(&This->format, fallback);
2841 static const IDWriteTextLayout2Vtbl dwritetextlayoutvtbl = {
2842 dwritetextlayout_QueryInterface,
2843 dwritetextlayout_AddRef,
2844 dwritetextlayout_Release,
2845 dwritetextlayout_SetTextAlignment,
2846 dwritetextlayout_SetParagraphAlignment,
2847 dwritetextlayout_SetWordWrapping,
2848 dwritetextlayout_SetReadingDirection,
2849 dwritetextlayout_SetFlowDirection,
2850 dwritetextlayout_SetIncrementalTabStop,
2851 dwritetextlayout_SetTrimming,
2852 dwritetextlayout_SetLineSpacing,
2853 dwritetextlayout_GetTextAlignment,
2854 dwritetextlayout_GetParagraphAlignment,
2855 dwritetextlayout_GetWordWrapping,
2856 dwritetextlayout_GetReadingDirection,
2857 dwritetextlayout_GetFlowDirection,
2858 dwritetextlayout_GetIncrementalTabStop,
2859 dwritetextlayout_GetTrimming,
2860 dwritetextlayout_GetLineSpacing,
2861 dwritetextlayout_GetFontCollection,
2862 dwritetextlayout_GetFontFamilyNameLength,
2863 dwritetextlayout_GetFontFamilyName,
2864 dwritetextlayout_GetFontWeight,
2865 dwritetextlayout_GetFontStyle,
2866 dwritetextlayout_GetFontStretch,
2867 dwritetextlayout_GetFontSize,
2868 dwritetextlayout_GetLocaleNameLength,
2869 dwritetextlayout_GetLocaleName,
2870 dwritetextlayout_SetMaxWidth,
2871 dwritetextlayout_SetMaxHeight,
2872 dwritetextlayout_SetFontCollection,
2873 dwritetextlayout_SetFontFamilyName,
2874 dwritetextlayout_SetFontWeight,
2875 dwritetextlayout_SetFontStyle,
2876 dwritetextlayout_SetFontStretch,
2877 dwritetextlayout_SetFontSize,
2878 dwritetextlayout_SetUnderline,
2879 dwritetextlayout_SetStrikethrough,
2880 dwritetextlayout_SetDrawingEffect,
2881 dwritetextlayout_SetInlineObject,
2882 dwritetextlayout_SetTypography,
2883 dwritetextlayout_SetLocaleName,
2884 dwritetextlayout_GetMaxWidth,
2885 dwritetextlayout_GetMaxHeight,
2886 dwritetextlayout_layout_GetFontCollection,
2887 dwritetextlayout_layout_GetFontFamilyNameLength,
2888 dwritetextlayout_layout_GetFontFamilyName,
2889 dwritetextlayout_layout_GetFontWeight,
2890 dwritetextlayout_layout_GetFontStyle,
2891 dwritetextlayout_layout_GetFontStretch,
2892 dwritetextlayout_layout_GetFontSize,
2893 dwritetextlayout_GetUnderline,
2894 dwritetextlayout_GetStrikethrough,
2895 dwritetextlayout_GetDrawingEffect,
2896 dwritetextlayout_GetInlineObject,
2897 dwritetextlayout_GetTypography,
2898 dwritetextlayout_layout_GetLocaleNameLength,
2899 dwritetextlayout_layout_GetLocaleName,
2900 dwritetextlayout_Draw,
2901 dwritetextlayout_GetLineMetrics,
2902 dwritetextlayout_GetMetrics,
2903 dwritetextlayout_GetOverhangMetrics,
2904 dwritetextlayout_GetClusterMetrics,
2905 dwritetextlayout_DetermineMinWidth,
2906 dwritetextlayout_HitTestPoint,
2907 dwritetextlayout_HitTestTextPosition,
2908 dwritetextlayout_HitTestTextRange,
2909 dwritetextlayout1_SetPairKerning,
2910 dwritetextlayout1_GetPairKerning,
2911 dwritetextlayout1_SetCharacterSpacing,
2912 dwritetextlayout1_GetCharacterSpacing,
2913 dwritetextlayout2_GetMetrics,
2914 dwritetextlayout2_SetVerticalGlyphOrientation,
2915 dwritetextlayout2_GetVerticalGlyphOrientation,
2916 dwritetextlayout2_SetLastLineWrapping,
2917 dwritetextlayout2_GetLastLineWrapping,
2918 dwritetextlayout2_SetOpticalAlignment,
2919 dwritetextlayout2_GetOpticalAlignment,
2920 dwritetextlayout2_SetFontFallback,
2921 dwritetextlayout2_GetFontFallback
2924 static HRESULT WINAPI dwritetextformat1_layout_QueryInterface(IDWriteTextFormat1 *iface, REFIID riid, void **obj)
2926 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2927 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2928 return IDWriteTextLayout2_QueryInterface(&This->IDWriteTextLayout2_iface, riid, obj);
2931 static ULONG WINAPI dwritetextformat1_layout_AddRef(IDWriteTextFormat1 *iface)
2933 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2934 return IDWriteTextLayout2_AddRef(&This->IDWriteTextLayout2_iface);
2937 static ULONG WINAPI dwritetextformat1_layout_Release(IDWriteTextFormat1 *iface)
2939 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2940 return IDWriteTextLayout2_Release(&This->IDWriteTextLayout2_iface);
2943 static HRESULT WINAPI dwritetextformat1_layout_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
2945 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2946 FIXME("(%p)->(%d): stub\n", This, alignment);
2947 return E_NOTIMPL;
2950 static HRESULT WINAPI dwritetextformat1_layout_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
2952 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2953 FIXME("(%p)->(%d): stub\n", This, alignment);
2954 return E_NOTIMPL;
2957 static HRESULT WINAPI dwritetextformat1_layout_SetWordWrapping(IDWriteTextFormat1 *iface, DWRITE_WORD_WRAPPING wrapping)
2959 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2960 FIXME("(%p)->(%d): stub\n", This, wrapping);
2961 return E_NOTIMPL;
2964 static HRESULT WINAPI dwritetextformat1_layout_SetReadingDirection(IDWriteTextFormat1 *iface, DWRITE_READING_DIRECTION direction)
2966 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2967 FIXME("(%p)->(%d): stub\n", This, direction);
2968 return E_NOTIMPL;
2971 static HRESULT WINAPI dwritetextformat1_layout_SetFlowDirection(IDWriteTextFormat1 *iface, DWRITE_FLOW_DIRECTION direction)
2973 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2974 FIXME("(%p)->(%d): stub\n", This, direction);
2975 return E_NOTIMPL;
2978 static HRESULT WINAPI dwritetextformat1_layout_SetIncrementalTabStop(IDWriteTextFormat1 *iface, FLOAT tabstop)
2980 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2981 FIXME("(%p)->(%f): stub\n", This, tabstop);
2982 return E_NOTIMPL;
2985 static HRESULT WINAPI dwritetextformat1_layout_SetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING const *trimming,
2986 IDWriteInlineObject *trimming_sign)
2988 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2989 FIXME("(%p)->(%p %p): stub\n", This, trimming, trimming_sign);
2990 return E_NOTIMPL;
2993 static HRESULT WINAPI dwritetextformat1_layout_SetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD spacing,
2994 FLOAT line_spacing, FLOAT baseline)
2996 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
2997 FIXME("(%p)->(%d %f %f): stub\n", This, spacing, line_spacing, baseline);
2998 return E_NOTIMPL;
3001 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat1_layout_GetTextAlignment(IDWriteTextFormat1 *iface)
3003 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3004 TRACE("(%p)\n", This);
3005 return This->format.textalignment;
3008 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat1_layout_GetParagraphAlignment(IDWriteTextFormat1 *iface)
3010 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3011 TRACE("(%p)\n", This);
3012 return This->format.paralign;
3015 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat1_layout_GetWordWrapping(IDWriteTextFormat1 *iface)
3017 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3018 FIXME("(%p): stub\n", This);
3019 return This->format.wrapping;
3022 static DWRITE_READING_DIRECTION WINAPI dwritetextformat1_layout_GetReadingDirection(IDWriteTextFormat1 *iface)
3024 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3025 TRACE("(%p)\n", This);
3026 return This->format.readingdir;
3029 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat1_layout_GetFlowDirection(IDWriteTextFormat1 *iface)
3031 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3032 TRACE("(%p)\n", This);
3033 return This->format.flow;
3036 static FLOAT WINAPI dwritetextformat1_layout_GetIncrementalTabStop(IDWriteTextFormat1 *iface)
3038 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3039 FIXME("(%p): stub\n", This);
3040 return 0.0;
3043 static HRESULT WINAPI dwritetextformat1_layout_GetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING *options,
3044 IDWriteInlineObject **trimming_sign)
3046 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3048 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
3050 *options = This->format.trimming;
3051 *trimming_sign = This->format.trimmingsign;
3052 if (*trimming_sign)
3053 IDWriteInlineObject_AddRef(*trimming_sign);
3054 return S_OK;
3057 static HRESULT WINAPI dwritetextformat1_layout_GetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD *method,
3058 FLOAT *spacing, FLOAT *baseline)
3060 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3062 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
3064 *method = This->format.spacingmethod;
3065 *spacing = This->format.spacing;
3066 *baseline = This->format.baseline;
3067 return S_OK;
3070 static HRESULT WINAPI dwritetextformat1_layout_GetFontCollection(IDWriteTextFormat1 *iface, IDWriteFontCollection **collection)
3072 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3074 TRACE("(%p)->(%p)\n", This, collection);
3076 *collection = This->format.collection;
3077 if (*collection)
3078 IDWriteFontCollection_AddRef(*collection);
3079 return S_OK;
3082 static UINT32 WINAPI dwritetextformat1_layout_GetFontFamilyNameLength(IDWriteTextFormat1 *iface)
3084 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3085 TRACE("(%p)\n", This);
3086 return This->format.family_len;
3089 static HRESULT WINAPI dwritetextformat1_layout_GetFontFamilyName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
3091 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3093 TRACE("(%p)->(%p %u)\n", This, name, size);
3095 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
3096 strcpyW(name, This->format.family_name);
3097 return S_OK;
3100 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat1_layout_GetFontWeight(IDWriteTextFormat1 *iface)
3102 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3103 TRACE("(%p)\n", This);
3104 return This->format.weight;
3107 static DWRITE_FONT_STYLE WINAPI dwritetextformat1_layout_GetFontStyle(IDWriteTextFormat1 *iface)
3109 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3110 TRACE("(%p)\n", This);
3111 return This->format.style;
3114 static DWRITE_FONT_STRETCH WINAPI dwritetextformat1_layout_GetFontStretch(IDWriteTextFormat1 *iface)
3116 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3117 TRACE("(%p)\n", This);
3118 return This->format.stretch;
3121 static FLOAT WINAPI dwritetextformat1_layout_GetFontSize(IDWriteTextFormat1 *iface)
3123 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3124 TRACE("(%p)\n", This);
3125 return This->format.fontsize;
3128 static UINT32 WINAPI dwritetextformat1_layout_GetLocaleNameLength(IDWriteTextFormat1 *iface)
3130 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3131 TRACE("(%p)\n", This);
3132 return This->format.locale_len;
3135 static HRESULT WINAPI dwritetextformat1_layout_GetLocaleName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
3137 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3139 TRACE("(%p)->(%p %u)\n", This, name, size);
3141 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
3142 strcpyW(name, This->format.locale);
3143 return S_OK;
3146 static HRESULT WINAPI dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat1 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
3148 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3149 FIXME("(%p)->(%d): stub\n", This, orientation);
3150 return E_NOTIMPL;
3153 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat1 *iface)
3155 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3156 FIXME("(%p): stub\n", This);
3157 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
3160 static HRESULT WINAPI dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat1 *iface, BOOL lastline_wrapping_enabled)
3162 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3163 FIXME("(%p)->(%d): stub\n", This, lastline_wrapping_enabled);
3164 return E_NOTIMPL;
3167 static BOOL WINAPI dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat1 *iface)
3169 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3170 FIXME("(%p): stub\n", This);
3171 return FALSE;
3174 static HRESULT WINAPI dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat1 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
3176 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3177 FIXME("(%p)->(%d): stub\n", This, alignment);
3178 return E_NOTIMPL;
3181 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat1 *iface)
3183 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3184 FIXME("(%p): stub\n", This);
3185 return DWRITE_OPTICAL_ALIGNMENT_NONE;
3188 static HRESULT WINAPI dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback *fallback)
3190 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3191 TRACE("(%p)->(%p)\n", This, fallback);
3192 return IDWriteTextLayout2_SetFontFallback(&This->IDWriteTextLayout2_iface, fallback);
3195 static HRESULT WINAPI dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback **fallback)
3197 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3198 TRACE("(%p)->(%p)\n", This, fallback);
3199 return IDWriteTextLayout2_GetFontFallback(&This->IDWriteTextLayout2_iface, fallback);
3202 static const IDWriteTextFormat1Vtbl dwritetextformat1_layout_vtbl = {
3203 dwritetextformat1_layout_QueryInterface,
3204 dwritetextformat1_layout_AddRef,
3205 dwritetextformat1_layout_Release,
3206 dwritetextformat1_layout_SetTextAlignment,
3207 dwritetextformat1_layout_SetParagraphAlignment,
3208 dwritetextformat1_layout_SetWordWrapping,
3209 dwritetextformat1_layout_SetReadingDirection,
3210 dwritetextformat1_layout_SetFlowDirection,
3211 dwritetextformat1_layout_SetIncrementalTabStop,
3212 dwritetextformat1_layout_SetTrimming,
3213 dwritetextformat1_layout_SetLineSpacing,
3214 dwritetextformat1_layout_GetTextAlignment,
3215 dwritetextformat1_layout_GetParagraphAlignment,
3216 dwritetextformat1_layout_GetWordWrapping,
3217 dwritetextformat1_layout_GetReadingDirection,
3218 dwritetextformat1_layout_GetFlowDirection,
3219 dwritetextformat1_layout_GetIncrementalTabStop,
3220 dwritetextformat1_layout_GetTrimming,
3221 dwritetextformat1_layout_GetLineSpacing,
3222 dwritetextformat1_layout_GetFontCollection,
3223 dwritetextformat1_layout_GetFontFamilyNameLength,
3224 dwritetextformat1_layout_GetFontFamilyName,
3225 dwritetextformat1_layout_GetFontWeight,
3226 dwritetextformat1_layout_GetFontStyle,
3227 dwritetextformat1_layout_GetFontStretch,
3228 dwritetextformat1_layout_GetFontSize,
3229 dwritetextformat1_layout_GetLocaleNameLength,
3230 dwritetextformat1_layout_GetLocaleName,
3231 dwritetextformat1_layout_SetVerticalGlyphOrientation,
3232 dwritetextformat1_layout_GetVerticalGlyphOrientation,
3233 dwritetextformat1_layout_SetLastLineWrapping,
3234 dwritetextformat1_layout_GetLastLineWrapping,
3235 dwritetextformat1_layout_SetOpticalAlignment,
3236 dwritetextformat1_layout_GetOpticalAlignment,
3237 dwritetextformat1_layout_SetFontFallback,
3238 dwritetextformat1_layout_GetFontFallback
3241 static HRESULT WINAPI dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink *iface,
3242 REFIID riid, void **obj)
3244 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) || IsEqualIID(riid, &IID_IUnknown)) {
3245 *obj = iface;
3246 IDWriteTextAnalysisSink_AddRef(iface);
3247 return S_OK;
3250 *obj = NULL;
3251 return E_NOINTERFACE;
3254 static ULONG WINAPI dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink *iface)
3256 return 2;
3259 static ULONG WINAPI dwritetextlayout_sink_Release(IDWriteTextAnalysisSink *iface)
3261 return 1;
3264 static HRESULT WINAPI dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink *iface,
3265 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
3267 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
3268 struct layout_run *run;
3270 TRACE("%u %u script=%d\n", position, length, sa->script);
3272 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
3273 if (!run)
3274 return E_OUTOFMEMORY;
3276 run->u.regular.descr.string = &layout->str[position];
3277 run->u.regular.descr.stringLength = length;
3278 run->u.regular.descr.textPosition = position;
3279 run->u.regular.sa = *sa;
3280 list_add_tail(&layout->runs, &run->entry);
3281 return S_OK;
3284 static HRESULT WINAPI dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink *iface,
3285 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
3287 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
3289 if (position + length > layout->len)
3290 return E_FAIL;
3292 memcpy(&layout->nominal_breakpoints[position], breakpoints, length*sizeof(DWRITE_LINE_BREAKPOINT));
3293 return S_OK;
3296 static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink *iface, UINT32 position,
3297 UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
3299 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
3300 struct layout_run *cur_run;
3302 TRACE("%u %u %u %u\n", position, length, explicitLevel, resolvedLevel);
3304 LIST_FOR_EACH_ENTRY(cur_run, &layout->runs, struct layout_run, entry) {
3305 struct regular_layout_run *cur = &cur_run->u.regular;
3306 struct layout_run *run;
3308 if (cur_run->kind == LAYOUT_RUN_INLINE)
3309 continue;
3311 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
3312 if (position < cur->descr.textPosition || position >= cur->descr.textPosition + cur->descr.stringLength)
3313 continue;
3315 /* full hit - just set run level */
3316 if (cur->descr.textPosition == position && cur->descr.stringLength == length) {
3317 cur->run.bidiLevel = resolvedLevel;
3318 break;
3321 /* current run is fully covered, move to next one */
3322 if (cur->descr.textPosition == position && cur->descr.stringLength < length) {
3323 cur->run.bidiLevel = resolvedLevel;
3324 position += cur->descr.stringLength;
3325 length -= cur->descr.stringLength;
3326 continue;
3329 /* all fully covered runs are processed at this point, reuse existing run for remaining
3330 reported bidi range and add another run for the rest of original one */
3332 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
3333 if (!run)
3334 return E_OUTOFMEMORY;
3336 *run = *cur_run;
3337 run->u.regular.descr.textPosition = position + length;
3338 run->u.regular.descr.stringLength = cur->descr.stringLength - length;
3339 run->u.regular.descr.string = &layout->str[position + length];
3341 /* reduce existing run */
3342 cur->run.bidiLevel = resolvedLevel;
3343 cur->descr.stringLength = length;
3345 list_add_after(&cur_run->entry, &run->entry);
3346 break;
3349 return S_OK;
3352 static HRESULT WINAPI dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink *iface,
3353 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
3355 return E_NOTIMPL;
3358 static const IDWriteTextAnalysisSinkVtbl dwritetextlayoutsinkvtbl = {
3359 dwritetextlayout_sink_QueryInterface,
3360 dwritetextlayout_sink_AddRef,
3361 dwritetextlayout_sink_Release,
3362 dwritetextlayout_sink_SetScriptAnalysis,
3363 dwritetextlayout_sink_SetLineBreakpoints,
3364 dwritetextlayout_sink_SetBidiLevel,
3365 dwritetextlayout_sink_SetNumberSubstitution
3368 static HRESULT WINAPI dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource *iface,
3369 REFIID riid, void **obj)
3371 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) ||
3372 IsEqualIID(riid, &IID_IUnknown))
3374 *obj = iface;
3375 IDWriteTextAnalysisSource_AddRef(iface);
3376 return S_OK;
3379 *obj = NULL;
3380 return E_NOINTERFACE;
3383 static ULONG WINAPI dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource *iface)
3385 return 2;
3388 static ULONG WINAPI dwritetextlayout_source_Release(IDWriteTextAnalysisSource *iface)
3390 return 1;
3393 static HRESULT WINAPI dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource *iface,
3394 UINT32 position, WCHAR const** text, UINT32* text_len)
3396 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource(iface);
3398 TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
3400 if (position < layout->len) {
3401 *text = &layout->str[position];
3402 *text_len = layout->len - position;
3404 else {
3405 *text = NULL;
3406 *text_len = 0;
3409 return S_OK;
3412 static HRESULT WINAPI dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource *iface,
3413 UINT32 position, WCHAR const** text, UINT32* text_len)
3415 FIXME("%u %p %p: stub\n", position, text, text_len);
3416 return E_NOTIMPL;
3419 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource *iface)
3421 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource(iface);
3422 return IDWriteTextLayout2_GetReadingDirection(&layout->IDWriteTextLayout2_iface);
3425 static HRESULT WINAPI dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource *iface,
3426 UINT32 position, UINT32* text_len, WCHAR const** locale)
3428 FIXME("%u %p %p: stub\n", position, text_len, locale);
3429 return E_NOTIMPL;
3432 static HRESULT WINAPI dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource *iface,
3433 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
3435 FIXME("%u %p %p: stub\n", position, text_len, substitution);
3436 return E_NOTIMPL;
3439 static const IDWriteTextAnalysisSourceVtbl dwritetextlayoutsourcevtbl = {
3440 dwritetextlayout_source_QueryInterface,
3441 dwritetextlayout_source_AddRef,
3442 dwritetextlayout_source_Release,
3443 dwritetextlayout_source_GetTextAtPosition,
3444 dwritetextlayout_source_GetTextBeforePosition,
3445 dwritetextlayout_source_GetParagraphReadingDirection,
3446 dwritetextlayout_source_GetLocaleName,
3447 dwritetextlayout_source_GetNumberSubstitution
3450 static HRESULT layout_format_from_textformat(struct dwrite_textlayout *layout, IDWriteTextFormat *format)
3452 IDWriteTextFormat1 *format1;
3453 UINT32 len;
3454 HRESULT hr;
3456 layout->format.weight = IDWriteTextFormat_GetFontWeight(format);
3457 layout->format.style = IDWriteTextFormat_GetFontStyle(format);
3458 layout->format.stretch = IDWriteTextFormat_GetFontStretch(format);
3459 layout->format.fontsize= IDWriteTextFormat_GetFontSize(format);
3460 layout->format.textalignment = IDWriteTextFormat_GetTextAlignment(format);
3461 layout->format.paralign = IDWriteTextFormat_GetParagraphAlignment(format);
3462 layout->format.wrapping = IDWriteTextFormat_GetWordWrapping(format);
3463 layout->format.readingdir = IDWriteTextFormat_GetReadingDirection(format);
3464 layout->format.flow = IDWriteTextFormat_GetFlowDirection(format);
3465 layout->format.fallback = NULL;
3466 hr = IDWriteTextFormat_GetLineSpacing(format, &layout->format.spacingmethod,
3467 &layout->format.spacing, &layout->format.baseline);
3468 if (FAILED(hr))
3469 return hr;
3471 hr = IDWriteTextFormat_GetTrimming(format, &layout->format.trimming, &layout->format.trimmingsign);
3472 if (FAILED(hr))
3473 return hr;
3475 /* locale name and length */
3476 len = IDWriteTextFormat_GetLocaleNameLength(format);
3477 layout->format.locale = heap_alloc((len+1)*sizeof(WCHAR));
3478 if (!layout->format.locale)
3479 return E_OUTOFMEMORY;
3481 hr = IDWriteTextFormat_GetLocaleName(format, layout->format.locale, len+1);
3482 if (FAILED(hr))
3483 return hr;
3484 layout->format.locale_len = len;
3486 /* font family name and length */
3487 len = IDWriteTextFormat_GetFontFamilyNameLength(format);
3488 layout->format.family_name = heap_alloc((len+1)*sizeof(WCHAR));
3489 if (!layout->format.family_name)
3490 return E_OUTOFMEMORY;
3492 hr = IDWriteTextFormat_GetFontFamilyName(format, layout->format.family_name, len+1);
3493 if (FAILED(hr))
3494 return hr;
3495 layout->format.family_len = len;
3497 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
3498 if (hr == S_OK) {
3499 layout->format.vertical_orientation = IDWriteTextFormat1_GetVerticalGlyphOrientation(format1);
3500 IDWriteTextFormat1_GetFontFallback(format1, &layout->format.fallback);
3501 IDWriteTextFormat1_Release(format1);
3503 else
3504 layout->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
3506 return IDWriteTextFormat_GetFontCollection(format, &layout->format.collection);
3509 static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, struct dwrite_textlayout *layout)
3511 struct layout_range_header *range, *strike, *effect, *spacing;
3512 DWRITE_TEXT_RANGE r = { 0, ~0u };
3513 HRESULT hr;
3515 layout->IDWriteTextLayout2_iface.lpVtbl = &dwritetextlayoutvtbl;
3516 layout->IDWriteTextFormat1_iface.lpVtbl = &dwritetextformat1_layout_vtbl;
3517 layout->IDWriteTextAnalysisSink_iface.lpVtbl = &dwritetextlayoutsinkvtbl;
3518 layout->IDWriteTextAnalysisSource_iface.lpVtbl = &dwritetextlayoutsourcevtbl;
3519 layout->ref = 1;
3520 layout->len = len;
3521 layout->maxwidth = maxwidth;
3522 layout->maxheight = maxheight;
3523 layout->recompute = RECOMPUTE_EVERYTHING;
3524 layout->nominal_breakpoints = NULL;
3525 layout->actual_breakpoints = NULL;
3526 layout->cluster_count = 0;
3527 layout->clustermetrics = NULL;
3528 layout->clusters = NULL;
3529 layout->lines = NULL;
3530 layout->line_count = 0;
3531 layout->line_alloc = 0;
3532 layout->minwidth = 0.0;
3533 list_init(&layout->eruns);
3534 list_init(&layout->inlineobjects);
3535 list_init(&layout->strikethrough);
3536 list_init(&layout->runs);
3537 list_init(&layout->ranges);
3538 list_init(&layout->strike_ranges);
3539 list_init(&layout->effects);
3540 list_init(&layout->spacing);
3541 memset(&layout->format, 0, sizeof(layout->format));
3543 layout->gdicompatible = FALSE;
3544 layout->pixels_per_dip = 0.0;
3545 layout->use_gdi_natural = FALSE;
3546 memset(&layout->transform, 0, sizeof(layout->transform));
3548 layout->str = heap_strdupnW(str, len);
3549 if (len && !layout->str) {
3550 hr = E_OUTOFMEMORY;
3551 goto fail;
3554 hr = layout_format_from_textformat(layout, format);
3555 if (FAILED(hr))
3556 goto fail;
3558 range = alloc_layout_range(layout, &r, LAYOUT_RANGE_REGULAR);
3559 strike = alloc_layout_range(layout, &r, LAYOUT_RANGE_STRIKETHROUGH);
3560 effect = alloc_layout_range(layout, &r, LAYOUT_RANGE_EFFECT);
3561 spacing = alloc_layout_range(layout, &r, LAYOUT_RANGE_SPACING);
3562 if (!range || !strike || !effect || !spacing) {
3563 free_layout_range(range);
3564 free_layout_range(strike);
3565 free_layout_range(effect);
3566 free_layout_range(spacing);
3567 hr = E_OUTOFMEMORY;
3568 goto fail;
3571 list_add_head(&layout->ranges, &range->entry);
3572 list_add_head(&layout->strike_ranges, &strike->entry);
3573 list_add_head(&layout->effects, &effect->entry);
3574 list_add_head(&layout->spacing, &spacing->entry);
3575 return S_OK;
3577 fail:
3578 IDWriteTextLayout2_Release(&layout->IDWriteTextLayout2_iface);
3579 return hr;
3582 HRESULT create_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, IDWriteTextLayout **ret)
3584 struct dwrite_textlayout *layout;
3585 HRESULT hr;
3587 *ret = NULL;
3589 layout = heap_alloc(sizeof(struct dwrite_textlayout));
3590 if (!layout) return E_OUTOFMEMORY;
3592 hr = init_textlayout(str, len, format, maxwidth, maxheight, layout);
3593 if (hr == S_OK)
3594 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout2_iface;
3596 return hr;
3599 HRESULT create_gdicompat_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight,
3600 FLOAT pixels_per_dip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural, IDWriteTextLayout **ret)
3602 struct dwrite_textlayout *layout;
3603 HRESULT hr;
3605 *ret = NULL;
3607 layout = heap_alloc(sizeof(struct dwrite_textlayout));
3608 if (!layout) return E_OUTOFMEMORY;
3610 hr = init_textlayout(str, len, format, maxwidth, maxheight, layout);
3611 if (hr == S_OK) {
3612 /* set gdi-specific properties */
3613 layout->gdicompatible = TRUE;
3614 layout->pixels_per_dip = pixels_per_dip;
3615 layout->use_gdi_natural = use_gdi_natural;
3616 layout->transform = transform ? *transform : identity;
3618 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout2_iface;
3621 return hr;
3624 static HRESULT WINAPI dwritetrimmingsign_QueryInterface(IDWriteInlineObject *iface, REFIID riid, void **obj)
3626 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3628 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3630 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteInlineObject)) {
3631 *obj = iface;
3632 IDWriteInlineObject_AddRef(iface);
3633 return S_OK;
3636 *obj = NULL;
3637 return E_NOINTERFACE;
3640 static ULONG WINAPI dwritetrimmingsign_AddRef(IDWriteInlineObject *iface)
3642 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3643 ULONG ref = InterlockedIncrement(&This->ref);
3644 TRACE("(%p)->(%d)\n", This, ref);
3645 return ref;
3648 static ULONG WINAPI dwritetrimmingsign_Release(IDWriteInlineObject *iface)
3650 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3651 ULONG ref = InterlockedDecrement(&This->ref);
3653 TRACE("(%p)->(%d)\n", This, ref);
3655 if (!ref) {
3656 IDWriteTextLayout_Release(This->layout);
3657 heap_free(This);
3660 return ref;
3663 static HRESULT WINAPI dwritetrimmingsign_Draw(IDWriteInlineObject *iface, void *context, IDWriteTextRenderer *renderer,
3664 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *effect)
3666 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3667 DWRITE_TEXT_RANGE range = { 0, ~0u };
3669 TRACE("(%p)->(%p %p %.2f %.2f %d %d %p)\n", This, context, renderer, originX, originY, is_sideways, is_rtl, effect);
3671 IDWriteTextLayout_SetDrawingEffect(This->layout, effect, range);
3672 return IDWriteTextLayout_Draw(This->layout, context, renderer, originX, originY);
3675 static HRESULT WINAPI dwritetrimmingsign_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *metrics)
3677 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3678 FIXME("(%p)->(%p): stub\n", This, metrics);
3679 memset(metrics, 0, sizeof(*metrics));
3680 return S_OK;
3683 static HRESULT WINAPI dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
3685 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3686 FIXME("(%p)->(%p): stub\n", This, overhangs);
3687 return E_NOTIMPL;
3690 static HRESULT WINAPI dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
3691 DWRITE_BREAK_CONDITION *after)
3693 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
3695 TRACE("(%p)->(%p %p)\n", This, before, after);
3697 *before = *after = DWRITE_BREAK_CONDITION_NEUTRAL;
3698 return S_OK;
3701 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl = {
3702 dwritetrimmingsign_QueryInterface,
3703 dwritetrimmingsign_AddRef,
3704 dwritetrimmingsign_Release,
3705 dwritetrimmingsign_Draw,
3706 dwritetrimmingsign_GetMetrics,
3707 dwritetrimmingsign_GetOverhangMetrics,
3708 dwritetrimmingsign_GetBreakConditions
3711 static inline BOOL is_reading_direction_horz(DWRITE_READING_DIRECTION direction)
3713 return (direction == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT) ||
3714 (direction == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
3717 static inline BOOL is_reading_direction_vert(DWRITE_READING_DIRECTION direction)
3719 return (direction == DWRITE_READING_DIRECTION_TOP_TO_BOTTOM) ||
3720 (direction == DWRITE_READING_DIRECTION_BOTTOM_TO_TOP);
3723 static inline BOOL is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction)
3725 return (direction == DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT) ||
3726 (direction == DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT);
3729 static inline BOOL is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction)
3731 return (direction == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM) ||
3732 (direction == DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP);
3735 HRESULT create_trimmingsign(IDWriteFactory2 *factory, IDWriteTextFormat *format, IDWriteInlineObject **sign)
3737 static const WCHAR ellipsisW = 0x2026;
3738 struct dwrite_trimmingsign *This;
3739 DWRITE_READING_DIRECTION reading;
3740 DWRITE_FLOW_DIRECTION flow;
3741 HRESULT hr;
3743 *sign = NULL;
3745 /* Validate reading/flow direction here, layout creation won't complain about
3746 invalid combinations. */
3747 reading = IDWriteTextFormat_GetReadingDirection(format);
3748 flow = IDWriteTextFormat_GetFlowDirection(format);
3750 if ((is_reading_direction_horz(reading) && is_flow_direction_horz(flow)) ||
3751 (is_reading_direction_vert(reading) && is_flow_direction_vert(flow)))
3752 return DWRITE_E_FLOWDIRECTIONCONFLICTS;
3754 This = heap_alloc(sizeof(*This));
3755 if (!This)
3756 return E_OUTOFMEMORY;
3758 This->IDWriteInlineObject_iface.lpVtbl = &dwritetrimmingsignvtbl;
3759 This->ref = 1;
3761 hr = IDWriteFactory2_CreateTextLayout(factory, &ellipsisW, 1, format, 0.0, 0.0, &This->layout);
3762 if (FAILED(hr)) {
3763 heap_free(This);
3764 return hr;
3767 IDWriteTextLayout_SetWordWrapping(This->layout, DWRITE_WORD_WRAPPING_NO_WRAP);
3768 *sign = &This->IDWriteInlineObject_iface;
3770 return S_OK;
3773 static HRESULT WINAPI dwritetextformat_QueryInterface(IDWriteTextFormat1 *iface, REFIID riid, void **obj)
3775 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3777 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3779 if (IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
3780 IsEqualIID(riid, &IID_IDWriteTextFormat) ||
3781 IsEqualIID(riid, &IID_IUnknown))
3783 *obj = iface;
3784 IDWriteTextFormat1_AddRef(iface);
3785 return S_OK;
3788 *obj = NULL;
3790 return E_NOINTERFACE;
3793 static ULONG WINAPI dwritetextformat_AddRef(IDWriteTextFormat1 *iface)
3795 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3796 ULONG ref = InterlockedIncrement(&This->ref);
3797 TRACE("(%p)->(%d)\n", This, ref);
3798 return ref;
3801 static ULONG WINAPI dwritetextformat_Release(IDWriteTextFormat1 *iface)
3803 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3804 ULONG ref = InterlockedDecrement(&This->ref);
3806 TRACE("(%p)->(%d)\n", This, ref);
3808 if (!ref)
3810 release_format_data(&This->format);
3811 heap_free(This);
3814 return ref;
3817 static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
3819 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3821 TRACE("(%p)->(%d)\n", This, alignment);
3823 if ((UINT32)alignment > DWRITE_TEXT_ALIGNMENT_JUSTIFIED)
3824 return E_INVALIDARG;
3826 This->format.textalignment = alignment;
3827 return S_OK;
3830 static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
3832 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3834 TRACE("(%p)->(%d)\n", This, alignment);
3836 if ((UINT32)alignment > DWRITE_PARAGRAPH_ALIGNMENT_CENTER)
3837 return E_INVALIDARG;
3839 This->format.paralign = alignment;
3840 return S_OK;
3843 static HRESULT WINAPI dwritetextformat_SetWordWrapping(IDWriteTextFormat1 *iface, DWRITE_WORD_WRAPPING wrapping)
3845 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3847 TRACE("(%p)->(%d)\n", This, wrapping);
3849 if ((UINT32)wrapping > DWRITE_WORD_WRAPPING_CHARACTER)
3850 return E_INVALIDARG;
3852 This->format.wrapping = wrapping;
3853 return S_OK;
3856 static HRESULT WINAPI dwritetextformat_SetReadingDirection(IDWriteTextFormat1 *iface, DWRITE_READING_DIRECTION direction)
3858 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3860 TRACE("(%p)->(%d)\n", This, direction);
3862 if ((UINT32)direction > DWRITE_READING_DIRECTION_BOTTOM_TO_TOP)
3863 return E_INVALIDARG;
3865 This->format.readingdir = direction;
3866 return S_OK;
3869 static HRESULT WINAPI dwritetextformat_SetFlowDirection(IDWriteTextFormat1 *iface, DWRITE_FLOW_DIRECTION direction)
3871 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3873 TRACE("(%p)->(%d)\n", This, direction);
3875 if ((UINT32)direction > DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT)
3876 return E_INVALIDARG;
3878 This->format.flow = direction;
3879 return S_OK;
3882 static HRESULT WINAPI dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat1 *iface, FLOAT tabstop)
3884 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3885 FIXME("(%p)->(%f): stub\n", This, tabstop);
3886 return E_NOTIMPL;
3889 static HRESULT WINAPI dwritetextformat_SetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING const *trimming,
3890 IDWriteInlineObject *trimming_sign)
3892 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3893 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
3895 This->format.trimming = *trimming;
3896 if (This->format.trimmingsign)
3897 IDWriteInlineObject_Release(This->format.trimmingsign);
3898 This->format.trimmingsign = trimming_sign;
3899 if (This->format.trimmingsign)
3900 IDWriteInlineObject_AddRef(This->format.trimmingsign);
3901 return S_OK;
3904 static HRESULT WINAPI dwritetextformat_SetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD method,
3905 FLOAT spacing, FLOAT baseline)
3907 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3909 TRACE("(%p)->(%d %f %f)\n", This, method, spacing, baseline);
3911 if (spacing < 0.0 || (UINT32)method > DWRITE_LINE_SPACING_METHOD_UNIFORM)
3912 return E_INVALIDARG;
3914 This->format.spacingmethod = method;
3915 This->format.spacing = spacing;
3916 This->format.baseline = baseline;
3917 return S_OK;
3920 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_GetTextAlignment(IDWriteTextFormat1 *iface)
3922 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3923 TRACE("(%p)\n", This);
3924 return This->format.textalignment;
3927 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_GetParagraphAlignment(IDWriteTextFormat1 *iface)
3929 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3930 TRACE("(%p)\n", This);
3931 return This->format.paralign;
3934 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_GetWordWrapping(IDWriteTextFormat1 *iface)
3936 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3937 TRACE("(%p)\n", This);
3938 return This->format.wrapping;
3941 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_GetReadingDirection(IDWriteTextFormat1 *iface)
3943 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3944 TRACE("(%p)\n", This);
3945 return This->format.readingdir;
3948 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_GetFlowDirection(IDWriteTextFormat1 *iface)
3950 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3951 TRACE("(%p)\n", This);
3952 return This->format.flow;
3955 static FLOAT WINAPI dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat1 *iface)
3957 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3958 FIXME("(%p): stub\n", This);
3959 return 0.0;
3962 static HRESULT WINAPI dwritetextformat_GetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING *options,
3963 IDWriteInlineObject **trimming_sign)
3965 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3966 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
3968 *options = This->format.trimming;
3969 if ((*trimming_sign = This->format.trimmingsign))
3970 IDWriteInlineObject_AddRef(*trimming_sign);
3972 return S_OK;
3975 static HRESULT WINAPI dwritetextformat_GetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD *method,
3976 FLOAT *spacing, FLOAT *baseline)
3978 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3979 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
3981 *method = This->format.spacingmethod;
3982 *spacing = This->format.spacing;
3983 *baseline = This->format.baseline;
3984 return S_OK;
3987 static HRESULT WINAPI dwritetextformat_GetFontCollection(IDWriteTextFormat1 *iface, IDWriteFontCollection **collection)
3989 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
3991 TRACE("(%p)->(%p)\n", This, collection);
3993 *collection = This->format.collection;
3994 IDWriteFontCollection_AddRef(*collection);
3996 return S_OK;
3999 static UINT32 WINAPI dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat1 *iface)
4001 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4002 TRACE("(%p)\n", This);
4003 return This->format.family_len;
4006 static HRESULT WINAPI dwritetextformat_GetFontFamilyName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
4008 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4010 TRACE("(%p)->(%p %u)\n", This, name, size);
4012 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
4013 strcpyW(name, This->format.family_name);
4014 return S_OK;
4017 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_GetFontWeight(IDWriteTextFormat1 *iface)
4019 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4020 TRACE("(%p)\n", This);
4021 return This->format.weight;
4024 static DWRITE_FONT_STYLE WINAPI dwritetextformat_GetFontStyle(IDWriteTextFormat1 *iface)
4026 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4027 TRACE("(%p)\n", This);
4028 return This->format.style;
4031 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_GetFontStretch(IDWriteTextFormat1 *iface)
4033 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4034 TRACE("(%p)\n", This);
4035 return This->format.stretch;
4038 static FLOAT WINAPI dwritetextformat_GetFontSize(IDWriteTextFormat1 *iface)
4040 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4041 TRACE("(%p)\n", This);
4042 return This->format.fontsize;
4045 static UINT32 WINAPI dwritetextformat_GetLocaleNameLength(IDWriteTextFormat1 *iface)
4047 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4048 TRACE("(%p)\n", This);
4049 return This->format.locale_len;
4052 static HRESULT WINAPI dwritetextformat_GetLocaleName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
4054 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4056 TRACE("(%p)->(%p %u)\n", This, name, size);
4058 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
4059 strcpyW(name, This->format.locale);
4060 return S_OK;
4063 static HRESULT WINAPI dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat1 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4065 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4067 TRACE("(%p)->(%d)\n", This, orientation);
4069 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
4070 return E_INVALIDARG;
4072 This->format.vertical_orientation = orientation;
4073 return S_OK;
4076 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat1 *iface)
4078 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4079 TRACE("(%p)\n", This);
4080 return This->format.vertical_orientation;
4083 static HRESULT WINAPI dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat1 *iface, BOOL lastline_wrapping_enabled)
4085 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4086 FIXME("(%p)->(%d): stub\n", This, lastline_wrapping_enabled);
4087 return E_NOTIMPL;
4090 static BOOL WINAPI dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat1 *iface)
4092 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4093 FIXME("(%p): stub\n", This);
4094 return FALSE;
4097 static HRESULT WINAPI dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat1 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
4099 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4100 FIXME("(%p)->(%d): stub\n", This, alignment);
4101 return E_NOTIMPL;
4104 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat1 *iface)
4106 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4107 FIXME("(%p): stub\n", This);
4108 return DWRITE_OPTICAL_ALIGNMENT_NONE;
4111 static HRESULT WINAPI dwritetextformat1_SetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback *fallback)
4113 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4114 TRACE("(%p)->(%p)\n", This, fallback);
4115 return set_fontfallback_for_format(&This->format, fallback);
4118 static HRESULT WINAPI dwritetextformat1_GetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback **fallback)
4120 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4121 TRACE("(%p)->(%p)\n", This, fallback);
4122 return get_fontfallback_from_format(&This->format, fallback);
4125 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl = {
4126 dwritetextformat_QueryInterface,
4127 dwritetextformat_AddRef,
4128 dwritetextformat_Release,
4129 dwritetextformat_SetTextAlignment,
4130 dwritetextformat_SetParagraphAlignment,
4131 dwritetextformat_SetWordWrapping,
4132 dwritetextformat_SetReadingDirection,
4133 dwritetextformat_SetFlowDirection,
4134 dwritetextformat_SetIncrementalTabStop,
4135 dwritetextformat_SetTrimming,
4136 dwritetextformat_SetLineSpacing,
4137 dwritetextformat_GetTextAlignment,
4138 dwritetextformat_GetParagraphAlignment,
4139 dwritetextformat_GetWordWrapping,
4140 dwritetextformat_GetReadingDirection,
4141 dwritetextformat_GetFlowDirection,
4142 dwritetextformat_GetIncrementalTabStop,
4143 dwritetextformat_GetTrimming,
4144 dwritetextformat_GetLineSpacing,
4145 dwritetextformat_GetFontCollection,
4146 dwritetextformat_GetFontFamilyNameLength,
4147 dwritetextformat_GetFontFamilyName,
4148 dwritetextformat_GetFontWeight,
4149 dwritetextformat_GetFontStyle,
4150 dwritetextformat_GetFontStretch,
4151 dwritetextformat_GetFontSize,
4152 dwritetextformat_GetLocaleNameLength,
4153 dwritetextformat_GetLocaleName,
4154 dwritetextformat1_SetVerticalGlyphOrientation,
4155 dwritetextformat1_GetVerticalGlyphOrientation,
4156 dwritetextformat1_SetLastLineWrapping,
4157 dwritetextformat1_GetLastLineWrapping,
4158 dwritetextformat1_SetOpticalAlignment,
4159 dwritetextformat1_GetOpticalAlignment,
4160 dwritetextformat1_SetFontFallback,
4161 dwritetextformat1_GetFontFallback
4164 HRESULT create_textformat(const WCHAR *family_name, IDWriteFontCollection *collection, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style,
4165 DWRITE_FONT_STRETCH stretch, FLOAT size, const WCHAR *locale, IDWriteTextFormat **format)
4167 struct dwrite_textformat *This;
4169 *format = NULL;
4171 This = heap_alloc(sizeof(struct dwrite_textformat));
4172 if (!This) return E_OUTOFMEMORY;
4174 This->IDWriteTextFormat1_iface.lpVtbl = &dwritetextformatvtbl;
4175 This->ref = 1;
4176 This->format.family_name = heap_strdupW(family_name);
4177 This->format.family_len = strlenW(family_name);
4178 This->format.locale = heap_strdupW(locale);
4179 This->format.locale_len = strlenW(locale);
4180 This->format.weight = weight;
4181 This->format.style = style;
4182 This->format.fontsize = size;
4183 This->format.stretch = stretch;
4184 This->format.textalignment = DWRITE_TEXT_ALIGNMENT_LEADING;
4185 This->format.paralign = DWRITE_PARAGRAPH_ALIGNMENT_NEAR;
4186 This->format.wrapping = DWRITE_WORD_WRAPPING_WRAP;
4187 This->format.readingdir = DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
4188 This->format.flow = DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM;
4189 This->format.spacingmethod = DWRITE_LINE_SPACING_METHOD_DEFAULT;
4190 This->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
4191 This->format.spacing = 0.0;
4192 This->format.baseline = 0.0;
4193 This->format.trimming.granularity = DWRITE_TRIMMING_GRANULARITY_NONE;
4194 This->format.trimming.delimiter = 0;
4195 This->format.trimming.delimiterCount = 0;
4196 This->format.trimmingsign = NULL;
4197 This->format.collection = collection;
4198 This->format.fallback = NULL;
4199 IDWriteFontCollection_AddRef(collection);
4201 *format = (IDWriteTextFormat*)&This->IDWriteTextFormat1_iface;
4203 return S_OK;
4206 static HRESULT WINAPI dwritetypography_QueryInterface(IDWriteTypography *iface, REFIID riid, void **obj)
4208 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4210 TRACE("(%p)->(%s %p)\n", typography, debugstr_guid(riid), obj);
4212 if (IsEqualIID(riid, &IID_IDWriteTypography) || IsEqualIID(riid, &IID_IUnknown)) {
4213 *obj = iface;
4214 IDWriteTypography_AddRef(iface);
4215 return S_OK;
4218 *obj = NULL;
4220 return E_NOINTERFACE;
4223 static ULONG WINAPI dwritetypography_AddRef(IDWriteTypography *iface)
4225 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4226 ULONG ref = InterlockedIncrement(&typography->ref);
4227 TRACE("(%p)->(%d)\n", typography, ref);
4228 return ref;
4231 static ULONG WINAPI dwritetypography_Release(IDWriteTypography *iface)
4233 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4234 ULONG ref = InterlockedDecrement(&typography->ref);
4236 TRACE("(%p)->(%d)\n", typography, ref);
4238 if (!ref) {
4239 heap_free(typography->features);
4240 heap_free(typography);
4243 return ref;
4246 static HRESULT WINAPI dwritetypography_AddFontFeature(IDWriteTypography *iface, DWRITE_FONT_FEATURE feature)
4248 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4250 TRACE("(%p)->(%x %u)\n", typography, feature.nameTag, feature.parameter);
4252 if (typography->count == typography->allocated) {
4253 DWRITE_FONT_FEATURE *ptr = heap_realloc(typography->features, 2*typography->allocated*sizeof(DWRITE_FONT_FEATURE));
4254 if (!ptr)
4255 return E_OUTOFMEMORY;
4257 typography->features = ptr;
4258 typography->allocated *= 2;
4261 typography->features[typography->count++] = feature;
4262 return S_OK;
4265 static UINT32 WINAPI dwritetypography_GetFontFeatureCount(IDWriteTypography *iface)
4267 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4268 TRACE("(%p)\n", typography);
4269 return typography->count;
4272 static HRESULT WINAPI dwritetypography_GetFontFeature(IDWriteTypography *iface, UINT32 index, DWRITE_FONT_FEATURE *feature)
4274 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4276 TRACE("(%p)->(%u %p)\n", typography, index, feature);
4278 if (index >= typography->count)
4279 return E_INVALIDARG;
4281 *feature = typography->features[index];
4282 return S_OK;
4285 static const IDWriteTypographyVtbl dwritetypographyvtbl = {
4286 dwritetypography_QueryInterface,
4287 dwritetypography_AddRef,
4288 dwritetypography_Release,
4289 dwritetypography_AddFontFeature,
4290 dwritetypography_GetFontFeatureCount,
4291 dwritetypography_GetFontFeature
4294 HRESULT create_typography(IDWriteTypography **ret)
4296 struct dwrite_typography *typography;
4298 *ret = NULL;
4300 typography = heap_alloc(sizeof(*typography));
4301 if (!typography)
4302 return E_OUTOFMEMORY;
4304 typography->IDWriteTypography_iface.lpVtbl = &dwritetypographyvtbl;
4305 typography->ref = 1;
4306 typography->allocated = 2;
4307 typography->count = 0;
4309 typography->features = heap_alloc(typography->allocated*sizeof(DWRITE_FONT_FEATURE));
4310 if (!typography->features) {
4311 heap_free(typography);
4312 return E_OUTOFMEMORY;
4315 *ret = &typography->IDWriteTypography_iface;
4316 return S_OK;