server: Store the attributes in the object_attributes structure.
[wine.git] / dlls / dwrite / layout.c
blob57c8ddc473e7de7aa20929138c0b434c9e259f16
1 /*
2 * Text format and layout
4 * Copyright 2012, 2014-2016 Nikolay Sivov for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include <stdarg.h>
24 #include <math.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "dwrite_private.h"
30 #include "scripts.h"
31 #include "wine/list.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
35 struct dwrite_textformat_data {
36 WCHAR *family_name;
37 UINT32 family_len;
38 WCHAR *locale;
39 UINT32 locale_len;
41 DWRITE_FONT_WEIGHT weight;
42 DWRITE_FONT_STYLE style;
43 DWRITE_FONT_STRETCH stretch;
45 DWRITE_PARAGRAPH_ALIGNMENT paralign;
46 DWRITE_READING_DIRECTION readingdir;
47 DWRITE_WORD_WRAPPING wrapping;
48 BOOL last_line_wrapping;
49 DWRITE_TEXT_ALIGNMENT textalignment;
50 DWRITE_FLOW_DIRECTION flow;
51 DWRITE_LINE_SPACING_METHOD spacingmethod;
52 DWRITE_VERTICAL_GLYPH_ORIENTATION vertical_orientation;
53 DWRITE_OPTICAL_ALIGNMENT optical_alignment;
55 FLOAT spacing;
56 FLOAT baseline;
57 FLOAT fontsize;
59 DWRITE_TRIMMING trimming;
60 IDWriteInlineObject *trimmingsign;
62 IDWriteFontCollection *collection;
63 IDWriteFontFallback *fallback;
66 enum layout_range_attr_kind {
67 LAYOUT_RANGE_ATTR_WEIGHT,
68 LAYOUT_RANGE_ATTR_STYLE,
69 LAYOUT_RANGE_ATTR_STRETCH,
70 LAYOUT_RANGE_ATTR_FONTSIZE,
71 LAYOUT_RANGE_ATTR_EFFECT,
72 LAYOUT_RANGE_ATTR_INLINE,
73 LAYOUT_RANGE_ATTR_UNDERLINE,
74 LAYOUT_RANGE_ATTR_STRIKETHROUGH,
75 LAYOUT_RANGE_ATTR_PAIR_KERNING,
76 LAYOUT_RANGE_ATTR_FONTCOLL,
77 LAYOUT_RANGE_ATTR_LOCALE,
78 LAYOUT_RANGE_ATTR_FONTFAMILY,
79 LAYOUT_RANGE_ATTR_SPACING,
80 LAYOUT_RANGE_ATTR_TYPOGRAPHY
83 struct layout_range_attr_value {
84 DWRITE_TEXT_RANGE range;
85 union {
86 DWRITE_FONT_WEIGHT weight;
87 DWRITE_FONT_STYLE style;
88 DWRITE_FONT_STRETCH stretch;
89 FLOAT fontsize;
90 IDWriteInlineObject *object;
91 IUnknown *effect;
92 BOOL underline;
93 BOOL strikethrough;
94 BOOL pair_kerning;
95 IDWriteFontCollection *collection;
96 const WCHAR *locale;
97 const WCHAR *fontfamily;
98 FLOAT spacing[3]; /* in arguments order - leading, trailing, advance */
99 IDWriteTypography *typography;
100 } u;
103 enum layout_range_kind {
104 LAYOUT_RANGE_REGULAR,
105 LAYOUT_RANGE_UNDERLINE,
106 LAYOUT_RANGE_STRIKETHROUGH,
107 LAYOUT_RANGE_EFFECT,
108 LAYOUT_RANGE_SPACING,
109 LAYOUT_RANGE_TYPOGRAPHY
112 struct layout_range_header {
113 struct list entry;
114 enum layout_range_kind kind;
115 DWRITE_TEXT_RANGE range;
118 struct layout_range {
119 struct layout_range_header h;
120 DWRITE_FONT_WEIGHT weight;
121 DWRITE_FONT_STYLE style;
122 FLOAT fontsize;
123 DWRITE_FONT_STRETCH stretch;
124 IDWriteInlineObject *object;
125 BOOL pair_kerning;
126 IDWriteFontCollection *collection;
127 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
128 WCHAR *fontfamily;
131 struct layout_range_bool {
132 struct layout_range_header h;
133 BOOL value;
136 struct layout_range_iface {
137 struct layout_range_header h;
138 IUnknown *iface;
141 struct layout_range_spacing {
142 struct layout_range_header h;
143 FLOAT leading;
144 FLOAT trailing;
145 FLOAT min_advance;
148 enum layout_run_kind {
149 LAYOUT_RUN_REGULAR,
150 LAYOUT_RUN_INLINE
153 struct inline_object_run {
154 IDWriteInlineObject *object;
155 UINT16 length;
158 struct regular_layout_run {
159 DWRITE_GLYPH_RUN_DESCRIPTION descr;
160 DWRITE_GLYPH_RUN run;
161 DWRITE_SCRIPT_ANALYSIS sa;
162 UINT16 *glyphs;
163 UINT16 *clustermap;
164 FLOAT *advances;
165 DWRITE_GLYPH_OFFSET *offsets;
166 /* this is actual glyph count after shaping, it's not necessary the same as reported to Draw() */
167 UINT32 glyphcount;
170 struct layout_run {
171 struct list entry;
172 enum layout_run_kind kind;
173 union {
174 struct inline_object_run object;
175 struct regular_layout_run regular;
176 } u;
177 FLOAT baseline;
178 FLOAT height;
181 struct layout_effective_run {
182 struct list entry;
183 const struct layout_run *run; /* nominal run this one is based on */
184 UINT32 start; /* relative text position, 0 means first text position of a nominal run */
185 UINT32 length; /* length in codepoints that this run covers */
186 UINT32 glyphcount; /* total glyph count in this run */
187 IUnknown *effect; /* original reference is kept only at range level */
188 FLOAT origin_x; /* baseline X position */
189 FLOAT origin_y; /* baseline Y position */
190 FLOAT align_dx; /* adjustment from text alignment */
191 FLOAT width; /* run width */
192 UINT16 *clustermap; /* effective clustermap, allocated separately, is not reused from nominal map */
193 UINT32 line; /* 0-based line index in line metrics array */
194 BOOL underlined; /* set if this run is underlined */
197 struct layout_effective_inline {
198 struct list entry;
199 IDWriteInlineObject *object;
200 IUnknown *effect;
201 FLOAT origin_x;
202 FLOAT origin_y;
203 FLOAT align_dx;
204 FLOAT width;
205 BOOL is_sideways;
206 BOOL is_rtl;
207 UINT32 line;
210 struct layout_underline {
211 struct list entry;
212 const struct layout_effective_run *run;
213 DWRITE_UNDERLINE u;
216 struct layout_strikethrough {
217 struct list entry;
218 const struct layout_effective_run *run;
219 DWRITE_STRIKETHROUGH s;
222 struct layout_cluster {
223 const struct layout_run *run; /* link to nominal run this cluster belongs to */
224 UINT32 position; /* relative to run, first cluster has 0 position */
227 enum layout_recompute_mask {
228 RECOMPUTE_NOMINAL_RUNS = 1 << 0,
229 RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
230 RECOMPUTE_EFFECTIVE_RUNS = 1 << 2,
231 RECOMPUTE_EVERYTHING = 0xffff
234 struct dwrite_textlayout {
235 IDWriteTextLayout2 IDWriteTextLayout2_iface;
236 IDWriteTextFormat1 IDWriteTextFormat1_iface;
237 IDWriteTextAnalysisSink IDWriteTextAnalysisSink_iface;
238 IDWriteTextAnalysisSource IDWriteTextAnalysisSource_iface;
239 LONG ref;
241 WCHAR *str;
242 UINT32 len;
243 struct dwrite_textformat_data format;
244 struct list strike_ranges;
245 struct list underline_ranges;
246 struct list typographies;
247 struct list effects;
248 struct list spacing;
249 struct list ranges;
250 struct list runs;
251 /* lists ready to use by Draw() */
252 struct list eruns;
253 struct list inlineobjects;
254 struct list underlines;
255 struct list strikethrough;
256 USHORT recompute;
258 DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
259 DWRITE_LINE_BREAKPOINT *actual_breakpoints;
261 struct layout_cluster *clusters;
262 DWRITE_CLUSTER_METRICS *clustermetrics;
263 UINT32 cluster_count;
264 FLOAT minwidth;
266 DWRITE_LINE_METRICS *lines;
267 UINT32 line_alloc;
269 DWRITE_TEXT_METRICS1 metrics;
271 DWRITE_MEASURING_MODE measuringmode;
273 /* gdi-compatible layout specifics */
274 FLOAT ppdip;
275 DWRITE_MATRIX transform;
278 struct dwrite_textformat {
279 IDWriteTextFormat1 IDWriteTextFormat1_iface;
280 LONG ref;
281 struct dwrite_textformat_data format;
284 struct dwrite_trimmingsign {
285 IDWriteInlineObject IDWriteInlineObject_iface;
286 LONG ref;
288 IDWriteTextLayout *layout;
291 struct dwrite_typography {
292 IDWriteTypography IDWriteTypography_iface;
293 LONG ref;
295 DWRITE_FONT_FEATURE *features;
296 UINT32 allocated;
297 UINT32 count;
300 struct dwrite_vec {
301 FLOAT x;
302 FLOAT y;
305 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl;
307 static void release_format_data(struct dwrite_textformat_data *data)
309 if (data->collection) IDWriteFontCollection_Release(data->collection);
310 if (data->fallback) IDWriteFontFallback_Release(data->fallback);
311 if (data->trimmingsign) IDWriteInlineObject_Release(data->trimmingsign);
312 heap_free(data->family_name);
313 heap_free(data->locale);
316 static inline struct dwrite_textlayout *impl_from_IDWriteTextLayout2(IDWriteTextLayout2 *iface)
318 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextLayout2_iface);
321 static inline struct dwrite_textlayout *impl_layout_form_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
323 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextFormat1_iface);
326 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSink(IDWriteTextAnalysisSink *iface)
328 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSink_iface);
331 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSource(IDWriteTextAnalysisSource *iface)
333 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSource_iface);
336 static inline struct dwrite_textformat *impl_from_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
338 return CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat1_iface);
341 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat*);
343 static inline struct dwrite_trimmingsign *impl_from_IDWriteInlineObject(IDWriteInlineObject *iface)
345 return CONTAINING_RECORD(iface, struct dwrite_trimmingsign, IDWriteInlineObject_iface);
348 static inline struct dwrite_typography *impl_from_IDWriteTypography(IDWriteTypography *iface)
350 return CONTAINING_RECORD(iface, struct dwrite_typography, IDWriteTypography_iface);
353 static inline const char *debugstr_run(const struct regular_layout_run *run)
355 return wine_dbg_sprintf("[%u,%u)", run->descr.textPosition, run->descr.textPosition +
356 run->descr.stringLength);
359 static inline BOOL is_layout_gdi_compatible(struct dwrite_textlayout *layout)
361 return layout->measuringmode != DWRITE_MEASURING_MODE_NATURAL;
364 static inline HRESULT format_set_textalignment(struct dwrite_textformat_data *format, DWRITE_TEXT_ALIGNMENT alignment,
365 BOOL *changed)
367 if ((UINT32)alignment > DWRITE_TEXT_ALIGNMENT_JUSTIFIED)
368 return E_INVALIDARG;
369 if (changed) *changed = format->textalignment != alignment;
370 format->textalignment = alignment;
371 return S_OK;
374 static inline HRESULT format_set_paralignment(struct dwrite_textformat_data *format,
375 DWRITE_PARAGRAPH_ALIGNMENT alignment, BOOL *changed)
377 if ((UINT32)alignment > DWRITE_PARAGRAPH_ALIGNMENT_CENTER)
378 return E_INVALIDARG;
379 if (changed) *changed = format->paralign != alignment;
380 format->paralign = alignment;
381 return S_OK;
384 static inline HRESULT format_set_readingdirection(struct dwrite_textformat_data *format,
385 DWRITE_READING_DIRECTION direction, BOOL *changed)
387 if ((UINT32)direction > DWRITE_READING_DIRECTION_BOTTOM_TO_TOP)
388 return E_INVALIDARG;
389 if (changed) *changed = format->readingdir != direction;
390 format->readingdir = direction;
391 return S_OK;
394 static inline HRESULT format_set_wordwrapping(struct dwrite_textformat_data *format,
395 DWRITE_WORD_WRAPPING wrapping, BOOL *changed)
397 if ((UINT32)wrapping > DWRITE_WORD_WRAPPING_CHARACTER)
398 return E_INVALIDARG;
399 if (changed) *changed = format->wrapping != wrapping;
400 format->wrapping = wrapping;
401 return S_OK;
404 static HRESULT get_fontfallback_from_format(const struct dwrite_textformat_data *format, IDWriteFontFallback **fallback)
406 *fallback = format->fallback;
407 if (*fallback)
408 IDWriteFontFallback_AddRef(*fallback);
409 return S_OK;
412 static HRESULT set_fontfallback_for_format(struct dwrite_textformat_data *format, IDWriteFontFallback *fallback)
414 if (format->fallback)
415 IDWriteFontFallback_Release(format->fallback);
416 format->fallback = fallback;
417 if (fallback)
418 IDWriteFontFallback_AddRef(fallback);
419 return S_OK;
422 static HRESULT format_set_optical_alignment(struct dwrite_textformat_data *format,
423 DWRITE_OPTICAL_ALIGNMENT alignment)
425 if ((UINT32)alignment > DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS)
426 return E_INVALIDARG;
427 format->optical_alignment = alignment;
428 return S_OK;
431 static struct layout_run *alloc_layout_run(enum layout_run_kind kind)
433 struct layout_run *ret;
435 ret = heap_alloc(sizeof(*ret));
436 if (!ret) return NULL;
438 memset(ret, 0, sizeof(*ret));
439 ret->kind = kind;
440 if (kind == LAYOUT_RUN_REGULAR) {
441 ret->u.regular.sa.script = Script_Unknown;
442 ret->u.regular.sa.shapes = DWRITE_SCRIPT_SHAPES_DEFAULT;
445 return ret;
448 static void free_layout_runs(struct dwrite_textlayout *layout)
450 struct layout_run *cur, *cur2;
451 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->runs, struct layout_run, entry) {
452 list_remove(&cur->entry);
453 if (cur->kind == LAYOUT_RUN_REGULAR) {
454 if (cur->u.regular.run.fontFace)
455 IDWriteFontFace_Release(cur->u.regular.run.fontFace);
456 heap_free(cur->u.regular.glyphs);
457 heap_free(cur->u.regular.clustermap);
458 heap_free(cur->u.regular.advances);
459 heap_free(cur->u.regular.offsets);
461 heap_free(cur);
465 static void free_layout_eruns(struct dwrite_textlayout *layout)
467 struct layout_effective_inline *in, *in2;
468 struct layout_effective_run *cur, *cur2;
469 struct layout_strikethrough *s, *s2;
470 struct layout_underline *u, *u2;
472 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->eruns, struct layout_effective_run, entry) {
473 list_remove(&cur->entry);
474 heap_free(cur->clustermap);
475 heap_free(cur);
478 LIST_FOR_EACH_ENTRY_SAFE(in, in2, &layout->inlineobjects, struct layout_effective_inline, entry) {
479 list_remove(&in->entry);
480 heap_free(in);
483 LIST_FOR_EACH_ENTRY_SAFE(u, u2, &layout->underlines, struct layout_underline, entry) {
484 list_remove(&u->entry);
485 heap_free(u);
488 LIST_FOR_EACH_ENTRY_SAFE(s, s2, &layout->strikethrough, struct layout_strikethrough, entry) {
489 list_remove(&s->entry);
490 heap_free(s);
494 /* Used to resolve break condition by forcing stronger condition over weaker. */
495 static inline DWRITE_BREAK_CONDITION override_break_condition(DWRITE_BREAK_CONDITION existingbreak, DWRITE_BREAK_CONDITION newbreak)
497 switch (existingbreak) {
498 case DWRITE_BREAK_CONDITION_NEUTRAL:
499 return newbreak;
500 case DWRITE_BREAK_CONDITION_CAN_BREAK:
501 return newbreak == DWRITE_BREAK_CONDITION_NEUTRAL ? existingbreak : newbreak;
502 /* let's keep stronger conditions as is */
503 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK:
504 case DWRITE_BREAK_CONDITION_MUST_BREAK:
505 break;
506 default:
507 ERR("unknown break condition %d\n", existingbreak);
510 return existingbreak;
513 /* This helper should be used to get effective range length, in other words it returns number of text
514 positions from range starting point to the end of the range, limited by layout text length */
515 static inline UINT32 get_clipped_range_length(const struct dwrite_textlayout *layout, const struct layout_range *range)
517 if (range->h.range.startPosition + range->h.range.length <= layout->len)
518 return range->h.range.length;
519 return layout->len - range->h.range.startPosition;
522 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
523 static HRESULT layout_update_breakpoints_range(struct dwrite_textlayout *layout, const struct layout_range *cur)
525 DWRITE_BREAK_CONDITION before, after;
526 UINT32 i, length;
527 HRESULT hr;
529 /* ignore returned conditions if failed */
530 hr = IDWriteInlineObject_GetBreakConditions(cur->object, &before, &after);
531 if (FAILED(hr))
532 after = before = DWRITE_BREAK_CONDITION_NEUTRAL;
534 if (!layout->actual_breakpoints) {
535 layout->actual_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
536 if (!layout->actual_breakpoints)
537 return E_OUTOFMEMORY;
538 memcpy(layout->actual_breakpoints, layout->nominal_breakpoints, sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
541 length = get_clipped_range_length(layout, cur);
542 for (i = cur->h.range.startPosition; i < length + cur->h.range.startPosition; i++) {
543 /* for first codepoint check if there's anything before it and update accordingly */
544 if (i == cur->h.range.startPosition) {
545 if (i > 0)
546 layout->actual_breakpoints[i].breakConditionBefore = layout->actual_breakpoints[i-1].breakConditionAfter =
547 override_break_condition(layout->actual_breakpoints[i-1].breakConditionAfter, before);
548 else
549 layout->actual_breakpoints[i].breakConditionBefore = before;
550 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
552 /* similar check for last codepoint */
553 else if (i == cur->h.range.startPosition + length - 1) {
554 if (i == layout->len - 1)
555 layout->actual_breakpoints[i].breakConditionAfter = after;
556 else
557 layout->actual_breakpoints[i].breakConditionAfter = layout->actual_breakpoints[i+1].breakConditionBefore =
558 override_break_condition(layout->actual_breakpoints[i+1].breakConditionBefore, after);
559 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
561 /* for all positions within a range disable breaks */
562 else {
563 layout->actual_breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
564 layout->actual_breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
567 layout->actual_breakpoints[i].isWhitespace = FALSE;
568 layout->actual_breakpoints[i].isSoftHyphen = FALSE;
571 return S_OK;
574 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos);
576 static inline DWRITE_LINE_BREAKPOINT get_effective_breakpoint(const struct dwrite_textlayout *layout, UINT32 pos)
578 if (layout->actual_breakpoints)
579 return layout->actual_breakpoints[pos];
580 return layout->nominal_breakpoints[pos];
583 static inline void init_cluster_metrics(const struct dwrite_textlayout *layout, const struct regular_layout_run *run,
584 UINT16 start_glyph, UINT16 stop_glyph, UINT32 stop_position, UINT16 length, DWRITE_CLUSTER_METRICS *metrics)
586 UINT8 breakcondition;
587 UINT32 position;
588 UINT16 j;
590 /* For clusters made of control chars we report zero glyphs, and we need zero cluster
591 width as well; advances are already computed at this point and are not necessary zero. */
592 metrics->width = 0.0f;
593 if (run->run.glyphCount) {
594 for (j = start_glyph; j < stop_glyph; j++)
595 metrics->width += run->run.glyphAdvances[j];
597 metrics->length = length;
599 position = stop_position;
600 if (stop_glyph == run->glyphcount)
601 breakcondition = get_effective_breakpoint(layout, stop_position).breakConditionAfter;
602 else {
603 breakcondition = get_effective_breakpoint(layout, stop_position).breakConditionBefore;
604 if (stop_position) position = stop_position - 1;
607 metrics->canWrapLineAfter = breakcondition == DWRITE_BREAK_CONDITION_CAN_BREAK ||
608 breakcondition == DWRITE_BREAK_CONDITION_MUST_BREAK;
609 if (metrics->length == 1) {
610 WORD type = 0;
612 GetStringTypeW(CT_CTYPE1, &layout->str[position], 1, &type);
613 metrics->isWhitespace = !!(type & C1_SPACE);
614 metrics->isNewline = FALSE /* FIXME */;
615 metrics->isSoftHyphen = layout->str[position] == 0x00ad /* Unicode Soft Hyphen */;
617 else {
618 metrics->isWhitespace = FALSE;
619 metrics->isNewline = FALSE;
620 metrics->isSoftHyphen = FALSE;
622 metrics->isRightToLeft = run->run.bidiLevel & 1;
623 metrics->padding = 0;
628 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
629 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
630 Note that there's no need to reallocate anything at this point as we allocate one cluster per
631 codepoint initially.
634 static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 *cluster)
636 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[*cluster];
637 struct layout_cluster *c = &layout->clusters[*cluster];
638 const struct regular_layout_run *run = &r->u.regular;
639 UINT32 i, start = 0;
641 for (i = 0; i < run->descr.stringLength; i++) {
642 BOOL end = i == run->descr.stringLength - 1;
644 if (run->descr.clusterMap[start] != run->descr.clusterMap[i]) {
645 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->descr.clusterMap[i], i,
646 i - start, metrics);
647 c->position = start;
648 c->run = r;
650 *cluster += 1;
651 metrics++;
652 c++;
653 start = i;
656 if (end) {
657 init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->glyphcount, i,
658 i - start + 1, metrics);
659 c->position = start;
660 c->run = r;
662 *cluster += 1;
663 return;
668 #define SCALE_FONT_METRIC(metric, emSize, metrics) ((FLOAT)(metric) * (emSize) / (FLOAT)(metrics)->designUnitsPerEm)
670 static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
672 IDWriteTextAnalyzer *analyzer;
673 struct layout_range *range;
674 struct layout_run *r;
675 UINT32 cluster = 0;
676 HRESULT hr;
678 free_layout_eruns(layout);
679 free_layout_runs(layout);
681 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
682 if (!layout->clustermetrics) {
683 layout->clustermetrics = heap_alloc(layout->len*sizeof(*layout->clustermetrics));
684 layout->clusters = heap_alloc(layout->len*sizeof(*layout->clusters));
685 if (!layout->clustermetrics || !layout->clusters) {
686 heap_free(layout->clustermetrics);
687 heap_free(layout->clusters);
688 return E_OUTOFMEMORY;
691 layout->cluster_count = 0;
693 hr = get_textanalyzer(&analyzer);
694 if (FAILED(hr))
695 return hr;
697 LIST_FOR_EACH_ENTRY(range, &layout->ranges, struct layout_range, h.entry) {
698 /* we don't care about ranges that don't contain any text */
699 if (range->h.range.startPosition >= layout->len)
700 break;
702 /* inline objects override actual text in a range */
703 if (range->object) {
704 hr = layout_update_breakpoints_range(layout, range);
705 if (FAILED(hr))
706 return hr;
708 r = alloc_layout_run(LAYOUT_RUN_INLINE);
709 if (!r)
710 return E_OUTOFMEMORY;
712 r->u.object.object = range->object;
713 r->u.object.length = get_clipped_range_length(layout, range);
714 list_add_tail(&layout->runs, &r->entry);
715 continue;
718 /* initial splitting by script */
719 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, &layout->IDWriteTextAnalysisSource_iface,
720 range->h.range.startPosition, get_clipped_range_length(layout, range), &layout->IDWriteTextAnalysisSink_iface);
721 if (FAILED(hr))
722 break;
724 /* this splits it further */
725 hr = IDWriteTextAnalyzer_AnalyzeBidi(analyzer, &layout->IDWriteTextAnalysisSource_iface,
726 range->h.range.startPosition, get_clipped_range_length(layout, range), &layout->IDWriteTextAnalysisSink_iface);
727 if (FAILED(hr))
728 break;
731 /* fill run info */
732 LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
733 DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props = NULL;
734 DWRITE_SHAPING_TEXT_PROPERTIES *text_props = NULL;
735 struct regular_layout_run *run = &r->u.regular;
736 DWRITE_FONT_METRICS fontmetrics = { 0 };
737 IDWriteFontFamily *family;
738 UINT32 index, max_count;
739 IDWriteFont *font;
740 BOOL exists = TRUE;
742 /* we need to do very little in case of inline objects */
743 if (r->kind == LAYOUT_RUN_INLINE) {
744 DWRITE_CLUSTER_METRICS *metrics = &layout->clustermetrics[cluster];
745 struct layout_cluster *c = &layout->clusters[cluster];
746 DWRITE_INLINE_OBJECT_METRICS inlinemetrics;
748 metrics->width = 0.0f;
749 metrics->length = r->u.object.length;
750 metrics->canWrapLineAfter = FALSE;
751 metrics->isWhitespace = FALSE;
752 metrics->isNewline = FALSE;
753 metrics->isSoftHyphen = FALSE;
754 metrics->isRightToLeft = FALSE;
755 metrics->padding = 0;
756 c->run = r;
757 c->position = 0; /* there's always one cluster per inline object, so 0 is valid value */
758 cluster++;
760 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
761 hr = IDWriteInlineObject_GetMetrics(r->u.object.object, &inlinemetrics);
762 if (FAILED(hr)) {
763 memset(&inlinemetrics, 0, sizeof(inlinemetrics));
764 hr = S_OK;
766 metrics->width = inlinemetrics.width;
767 r->baseline = inlinemetrics.baseline;
768 r->height = inlinemetrics.height;
770 /* FIXME: use resolved breakpoints in this case too */
772 continue;
775 range = get_layout_range_by_pos(layout, run->descr.textPosition);
777 hr = IDWriteFontCollection_FindFamilyName(range->collection, range->fontfamily, &index, &exists);
778 if (FAILED(hr) || !exists) {
779 WARN("%s: family %s not found in collection %p\n", debugstr_run(run), debugstr_w(range->fontfamily), range->collection);
780 continue;
783 hr = IDWriteFontCollection_GetFontFamily(range->collection, index, &family);
784 if (FAILED(hr))
785 continue;
787 hr = IDWriteFontFamily_GetFirstMatchingFont(family, range->weight, range->stretch, range->style, &font);
788 IDWriteFontFamily_Release(family);
789 if (FAILED(hr)) {
790 WARN("%s: failed to get a matching font\n", debugstr_run(run));
791 continue;
794 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
795 IDWriteFont_Release(font);
796 if (FAILED(hr))
797 continue;
799 run->run.fontEmSize = range->fontsize;
800 run->descr.localeName = range->locale;
801 run->clustermap = heap_alloc(run->descr.stringLength*sizeof(UINT16));
803 max_count = 3*run->descr.stringLength/2 + 16;
804 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
805 if (!run->clustermap || !run->glyphs)
806 goto memerr;
808 text_props = heap_alloc(run->descr.stringLength*sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
809 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
810 if (!text_props || !glyph_props)
811 goto memerr;
813 while (1) {
814 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, run->descr.string, run->descr.stringLength,
815 run->run.fontFace, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
816 NULL /* FIXME */, NULL, NULL, 0, max_count, run->clustermap, text_props, run->glyphs, glyph_props,
817 &run->glyphcount);
818 if (hr == E_NOT_SUFFICIENT_BUFFER) {
819 heap_free(run->glyphs);
820 heap_free(glyph_props);
822 max_count = run->glyphcount;
824 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
825 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
826 if (!run->glyphs || !glyph_props)
827 goto memerr;
829 continue;
832 break;
835 if (FAILED(hr)) {
836 heap_free(text_props);
837 heap_free(glyph_props);
838 WARN("%s: shaping failed 0x%08x\n", debugstr_run(run), hr);
839 continue;
842 run->run.glyphIndices = run->glyphs;
843 run->descr.clusterMap = run->clustermap;
845 run->advances = heap_alloc(run->glyphcount*sizeof(FLOAT));
846 run->offsets = heap_alloc(run->glyphcount*sizeof(DWRITE_GLYPH_OFFSET));
847 if (!run->advances || !run->offsets)
848 goto memerr;
850 /* now set advances and offsets */
851 if (is_layout_gdi_compatible(layout))
852 hr = IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap,
853 text_props, run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount,
854 run->run.fontFace, run->run.fontEmSize, layout->ppdip, &layout->transform,
855 layout->measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->run.isSideways,
856 run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL, NULL, 0, run->advances, run->offsets);
857 else
858 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap, text_props,
859 run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount, run->run.fontFace,
860 run->run.fontEmSize, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
861 NULL, NULL, 0, run->advances, run->offsets);
863 heap_free(text_props);
864 heap_free(glyph_props);
865 if (FAILED(hr))
866 WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_run(run), hr);
868 run->run.glyphAdvances = run->advances;
869 run->run.glyphOffsets = run->offsets;
871 /* Special treatment of control script, shaping code adds normal glyphs for it,
872 with non-zero advances, and layout code exposes those as zero width clusters,
873 so we have to do it manually. */
874 if (run->sa.script == Script_Common)
875 run->run.glyphCount = 0;
876 else
877 run->run.glyphCount = run->glyphcount;
879 /* baseline derived from font metrics */
880 if (is_layout_gdi_compatible(layout)) {
881 hr = IDWriteFontFace_GetGdiCompatibleMetrics(run->run.fontFace,
882 run->run.fontEmSize,
883 layout->ppdip,
884 &layout->transform,
885 &fontmetrics);
886 if (FAILED(hr))
887 WARN("failed to get compat metrics, 0x%08x\n", hr);
889 else
890 IDWriteFontFace_GetMetrics(run->run.fontFace, &fontmetrics);
892 r->baseline = SCALE_FONT_METRIC(fontmetrics.ascent, run->run.fontEmSize, &fontmetrics);
893 r->height = SCALE_FONT_METRIC(fontmetrics.ascent + fontmetrics.descent, run->run.fontEmSize, &fontmetrics);
895 layout_set_cluster_metrics(layout, r, &cluster);
897 continue;
899 memerr:
900 heap_free(text_props);
901 heap_free(glyph_props);
902 heap_free(run->clustermap);
903 heap_free(run->glyphs);
904 heap_free(run->advances);
905 heap_free(run->offsets);
906 run->advances = NULL;
907 run->offsets = NULL;
908 run->clustermap = run->glyphs = NULL;
909 hr = E_OUTOFMEMORY;
910 break;
913 if (hr == S_OK) {
914 layout->cluster_count = cluster;
915 if (cluster)
916 layout->clustermetrics[cluster-1].canWrapLineAfter = TRUE;
919 IDWriteTextAnalyzer_Release(analyzer);
920 return hr;
923 static HRESULT layout_compute(struct dwrite_textlayout *layout)
925 HRESULT hr;
927 if (!(layout->recompute & RECOMPUTE_NOMINAL_RUNS))
928 return S_OK;
930 /* nominal breakpoints are evaluated only once, because string never changes */
931 if (!layout->nominal_breakpoints) {
932 IDWriteTextAnalyzer *analyzer;
933 HRESULT hr;
935 layout->nominal_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
936 if (!layout->nominal_breakpoints)
937 return E_OUTOFMEMORY;
939 hr = get_textanalyzer(&analyzer);
940 if (FAILED(hr))
941 return hr;
943 hr = IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer, &layout->IDWriteTextAnalysisSource_iface,
944 0, layout->len, &layout->IDWriteTextAnalysisSink_iface);
945 IDWriteTextAnalyzer_Release(analyzer);
947 if (layout->actual_breakpoints) {
948 heap_free(layout->actual_breakpoints);
949 layout->actual_breakpoints = NULL;
952 hr = layout_compute_runs(layout);
954 if (TRACE_ON(dwrite)) {
955 struct layout_run *cur;
957 LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
958 if (cur->kind == LAYOUT_RUN_INLINE)
959 TRACE("run inline object %p, len %u\n", cur->u.object.object, cur->u.object.length);
960 else
961 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur->u.regular.descr.textPosition, cur->u.regular.descr.textPosition +
962 cur->u.regular.descr.stringLength-1, cur->u.regular.descr.stringLength, cur->u.regular.run.bidiLevel);
966 layout->recompute &= ~RECOMPUTE_NOMINAL_RUNS;
967 return hr;
970 static inline FLOAT get_cluster_range_width(struct dwrite_textlayout *layout, UINT32 start, UINT32 end)
972 FLOAT width = 0.0f;
973 for (; start < end; start++)
974 width += layout->clustermetrics[start].width;
975 return width;
978 static struct layout_range_header *get_layout_range_header_by_pos(struct list *ranges, UINT32 pos)
980 struct layout_range_header *cur;
982 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
983 DWRITE_TEXT_RANGE *r = &cur->range;
984 if (r->startPosition <= pos && pos < r->startPosition + r->length)
985 return cur;
988 return NULL;
991 static inline IUnknown *layout_get_effect_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
993 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->effects, pos);
994 return ((struct layout_range_iface*)h)->iface;
997 static inline BOOL layout_is_erun_rtl(const struct layout_effective_run *erun)
999 return erun->run->u.regular.run.bidiLevel & 1;
1002 /* A set of parameters that additionally slits resulting runs. It happens after shaping and all text processing,
1003 no glyph changes are possible. It's understandable for effects, because DrawGlyphRun() will report them,
1004 but it also happens for decorations, so every effective run has uniform underline/strikethough/effect tuple. */
1005 struct layout_final_splitting_params {
1006 BOOL strikethrough;
1007 BOOL underline;
1008 IUnknown *effect;
1011 static inline BOOL layout_get_strikethrough_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1013 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->strike_ranges, pos);
1014 return ((struct layout_range_bool*)h)->value;
1017 static inline BOOL layout_get_underline_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
1019 struct layout_range_header *h = get_layout_range_header_by_pos(&layout->underline_ranges, pos);
1020 return ((struct layout_range_bool*)h)->value;
1023 static void layout_splitting_params_from_pos(struct dwrite_textlayout *layout, UINT32 pos,
1024 struct layout_final_splitting_params *params)
1026 params->strikethrough = layout_get_strikethrough_from_pos(layout, pos);
1027 params->underline = layout_get_underline_from_pos(layout, pos);
1028 params->effect = layout_get_effect_from_pos(layout, pos);
1031 static BOOL is_same_splitting_params(const struct layout_final_splitting_params *left,
1032 const struct layout_final_splitting_params *right)
1034 return left->strikethrough == right->strikethrough &&
1035 left->underline == right->underline &&
1036 left->effect == right->effect;
1039 static void layout_get_erun_font_metrics(struct dwrite_textlayout *layout, struct layout_effective_run *erun,
1040 DWRITE_FONT_METRICS *metrics)
1042 memset(metrics, 0, sizeof(*metrics));
1043 if (is_layout_gdi_compatible(layout)) {
1044 HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(
1045 erun->run->u.regular.run.fontFace,
1046 erun->run->u.regular.run.fontEmSize,
1047 layout->ppdip,
1048 &layout->transform,
1049 metrics);
1050 if (FAILED(hr))
1051 WARN("failed to get font metrics, 0x%08x\n", hr);
1053 else
1054 IDWriteFontFace_GetMetrics(erun->run->u.regular.run.fontFace, metrics);
1057 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
1058 'cluster_count' indicates how many clusters to add, including first one. */
1059 static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 first_cluster,
1060 UINT32 cluster_count, UINT32 line, FLOAT origin_x, struct layout_final_splitting_params *params)
1062 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1063 UINT32 i, start, length, last_cluster;
1064 struct layout_effective_run *run;
1066 if (r->kind == LAYOUT_RUN_INLINE) {
1067 struct layout_effective_inline *inlineobject;
1069 inlineobject = heap_alloc(sizeof(*inlineobject));
1070 if (!inlineobject)
1071 return E_OUTOFMEMORY;
1073 inlineobject->object = r->u.object.object;
1074 inlineobject->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1075 inlineobject->origin_x = is_rtl ? origin_x - inlineobject->width : origin_x;
1076 inlineobject->origin_y = 0.0f; /* set after line is built */
1077 inlineobject->align_dx = 0.0f;
1079 /* It's not clear how these two are set, possibly directionality
1080 is derived from surrounding text (replaced text could have
1081 different ranges which differ in reading direction). */
1082 inlineobject->is_sideways = FALSE;
1083 inlineobject->is_rtl = FALSE;
1084 inlineobject->line = line;
1086 /* effect assigned from start position and on is used for inline objects */
1087 inlineobject->effect = layout_get_effect_from_pos(layout, layout->clusters[first_cluster].position);
1089 list_add_tail(&layout->inlineobjects, &inlineobject->entry);
1090 return S_OK;
1093 run = heap_alloc(sizeof(*run));
1094 if (!run)
1095 return E_OUTOFMEMORY;
1097 /* No need to iterate for that, use simple fact that:
1098 <last cluster position> = first cluster position> + <sum of cluster lengths not including last one> */
1099 last_cluster = first_cluster + cluster_count - 1;
1100 length = layout->clusters[last_cluster].position - layout->clusters[first_cluster].position +
1101 layout->clustermetrics[last_cluster].length;
1103 run->clustermap = heap_alloc(sizeof(UINT16)*length);
1104 if (!run->clustermap) {
1105 heap_free(run);
1106 return E_OUTOFMEMORY;
1109 run->run = r;
1110 run->start = start = layout->clusters[first_cluster].position;
1111 run->length = length;
1112 run->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1114 /* Check if run direction matches paragraph direction, if it doesn't adjust by
1115 run width */
1116 if (layout_is_erun_rtl(run) ^ is_rtl)
1117 run->origin_x = is_rtl ? origin_x - run->width : origin_x + run->width;
1118 else
1119 run->origin_x = origin_x;
1121 run->origin_y = 0.0f; /* set after line is built */
1122 run->align_dx = 0.0f;
1123 run->line = line;
1125 if (r->u.regular.run.glyphCount) {
1126 /* trim from the left */
1127 run->glyphcount = r->u.regular.run.glyphCount - r->u.regular.clustermap[start];
1128 /* trim from the right */
1129 if (start + length < r->u.regular.descr.stringLength - 1)
1130 run->glyphcount -= r->u.regular.run.glyphCount - r->u.regular.clustermap[start + length];
1132 else
1133 run->glyphcount = 0;
1135 /* cluster map needs to be shifted */
1136 for (i = 0; i < length; i++)
1137 run->clustermap[i] = r->u.regular.clustermap[start + i] - r->u.regular.clustermap[start];
1139 run->effect = params->effect;
1140 run->underlined = params->underline;
1141 list_add_tail(&layout->eruns, &run->entry);
1143 /* Strikethrough style is guaranteed to be consistent within effective run,
1144 it's width equals to run width, thikness and offset are derived from
1145 font metrics, rest of the values are from layout or run itself */
1146 if (params->strikethrough) {
1147 struct layout_strikethrough *s;
1148 DWRITE_FONT_METRICS metrics;
1150 s = heap_alloc(sizeof(*s));
1151 if (!s)
1152 return E_OUTOFMEMORY;
1154 layout_get_erun_font_metrics(layout, run, &metrics);
1155 s->s.width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
1156 s->s.thickness = SCALE_FONT_METRIC(metrics.strikethroughThickness, r->u.regular.run.fontEmSize, &metrics);
1157 /* Negative offset moves it above baseline as Y coordinate grows downward. */
1158 s->s.offset = -SCALE_FONT_METRIC(metrics.strikethroughPosition, r->u.regular.run.fontEmSize, &metrics);
1159 s->s.readingDirection = layout->format.readingdir;
1160 s->s.flowDirection = layout->format.flow;
1161 s->s.localeName = r->u.regular.descr.localeName;
1162 s->s.measuringMode = layout->measuringmode;
1163 s->run = run;
1165 list_add_tail(&layout->strikethrough, &s->entry);
1168 return S_OK;
1171 static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_LINE_METRICS *metrics, UINT32 *line)
1173 if (!layout->line_alloc) {
1174 layout->line_alloc = 5;
1175 layout->lines = heap_alloc(layout->line_alloc*sizeof(*layout->lines));
1176 if (!layout->lines)
1177 return E_OUTOFMEMORY;
1180 if (layout->metrics.lineCount == layout->line_alloc) {
1181 DWRITE_LINE_METRICS *l = heap_realloc(layout->lines, layout->line_alloc*2*sizeof(*layout->lines));
1182 if (!l)
1183 return E_OUTOFMEMORY;
1184 layout->lines = l;
1185 layout->line_alloc *= 2;
1188 layout->lines[*line] = *metrics;
1189 layout->metrics.lineCount += 1;
1190 *line += 1;
1191 return S_OK;
1195 static inline struct layout_effective_run *layout_get_next_erun(struct dwrite_textlayout *layout,
1196 const struct layout_effective_run *cur)
1198 struct list *e;
1200 if (!cur)
1201 e = list_head(&layout->eruns);
1202 else
1203 e = list_next(&layout->eruns, &cur->entry);
1204 if (!e)
1205 return NULL;
1206 return LIST_ENTRY(e, struct layout_effective_run, entry);
1209 static inline struct layout_effective_run *layout_get_prev_erun(struct dwrite_textlayout *layout,
1210 const struct layout_effective_run *cur)
1212 struct list *e;
1214 if (!cur)
1215 e = list_tail(&layout->eruns);
1216 else
1217 e = list_prev(&layout->eruns, &cur->entry);
1218 if (!e)
1219 return NULL;
1220 return LIST_ENTRY(e, struct layout_effective_run, entry);
1223 static inline struct layout_effective_inline *layout_get_next_inline_run(struct dwrite_textlayout *layout,
1224 const struct layout_effective_inline *cur)
1226 struct list *e;
1228 if (!cur)
1229 e = list_head(&layout->inlineobjects);
1230 else
1231 e = list_next(&layout->inlineobjects, &cur->entry);
1232 if (!e)
1233 return NULL;
1234 return LIST_ENTRY(e, struct layout_effective_inline, entry);
1237 static FLOAT layout_get_line_width(struct dwrite_textlayout *layout,
1238 struct layout_effective_run *erun, struct layout_effective_inline *inrun, UINT32 line)
1240 FLOAT width = 0.0f;
1242 while (erun && erun->line == line) {
1243 width += erun->width;
1244 erun = layout_get_next_erun(layout, erun);
1245 if (!erun)
1246 break;
1249 while (inrun && inrun->line == line) {
1250 width += inrun->width;
1251 inrun = layout_get_next_inline_run(layout, inrun);
1252 if (!inrun)
1253 break;
1256 return width;
1259 static inline BOOL should_skip_transform(const DWRITE_MATRIX *m, FLOAT *det)
1261 *det = m->m11 * m->m22 - m->m12 * m->m21;
1262 /* on certain conditions we can skip transform */
1263 return (!memcmp(m, &identity, sizeof(*m)) || fabsf(*det) <= 1e-10f);
1266 static inline void layout_apply_snapping(struct dwrite_vec *vec, BOOL skiptransform, FLOAT ppdip,
1267 const DWRITE_MATRIX *m, FLOAT det)
1269 if (!skiptransform) {
1270 FLOAT vec2[2];
1272 /* apply transform */
1273 vec->x *= ppdip;
1274 vec->y *= ppdip;
1276 vec2[0] = m->m11 * vec->x + m->m21 * vec->y + m->dx;
1277 vec2[1] = m->m12 * vec->x + m->m22 * vec->y + m->dy;
1279 /* snap */
1280 vec2[0] = floorf(vec2[0] + 0.5f);
1281 vec2[1] = floorf(vec2[1] + 0.5f);
1283 /* apply inverted transform, we don't care about X component at this point */
1284 vec->x = (m->m22 * vec2[0] - m->m21 * vec2[1] + m->m21 * m->dy - m->m22 * m->dx) / det;
1285 vec->x /= ppdip;
1287 vec->y = (-m->m12 * vec2[0] + m->m11 * vec2[1] - (m->m11 * m->dy - m->m12 * m->dx)) / det;
1288 vec->y /= ppdip;
1290 else {
1291 vec->x = floorf(vec->x * ppdip + 0.5f) / ppdip;
1292 vec->y = floorf(vec->y * ppdip + 0.5f) / ppdip;
1296 static void layout_apply_leading_alignment(struct dwrite_textlayout *layout)
1298 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1299 struct layout_effective_inline *inrun;
1300 struct layout_effective_run *erun;
1302 erun = layout_get_next_erun(layout, NULL);
1303 inrun = layout_get_next_inline_run(layout, NULL);
1305 while (erun) {
1306 erun->align_dx = 0.0f;
1307 erun = layout_get_next_erun(layout, erun);
1310 while (inrun) {
1311 inrun->align_dx = 0.0f;
1312 inrun = layout_get_next_inline_run(layout, inrun);
1315 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
1318 static void layout_apply_trailing_alignment(struct dwrite_textlayout *layout)
1320 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1321 struct layout_effective_inline *inrun;
1322 struct layout_effective_run *erun;
1323 UINT32 line;
1325 erun = layout_get_next_erun(layout, NULL);
1326 inrun = layout_get_next_inline_run(layout, NULL);
1328 for (line = 0; line < layout->metrics.lineCount; line++) {
1329 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1330 FLOAT shift = layout->metrics.layoutWidth - width;
1332 if (is_rtl)
1333 shift *= -1.0f;
1335 while (erun && erun->line == line) {
1336 erun->align_dx = shift;
1337 erun = layout_get_next_erun(layout, erun);
1340 while (inrun && inrun->line == line) {
1341 inrun->align_dx = shift;
1342 inrun = layout_get_next_inline_run(layout, inrun);
1346 layout->metrics.left = is_rtl ? 0.0f : layout->metrics.layoutWidth - layout->metrics.width;
1349 static inline FLOAT layout_get_centered_shift(struct dwrite_textlayout *layout, BOOL skiptransform,
1350 FLOAT width, FLOAT det)
1352 if (is_layout_gdi_compatible(layout)) {
1353 struct dwrite_vec vec = { layout->metrics.layoutWidth - width, 0.0f};
1354 layout_apply_snapping(&vec, skiptransform, layout->ppdip, &layout->transform, det);
1355 return floorf(vec.x / 2.0f);
1357 else
1358 return (layout->metrics.layoutWidth - width) / 2.0f;
1361 static void layout_apply_centered_alignment(struct dwrite_textlayout *layout)
1363 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1364 struct layout_effective_inline *inrun;
1365 struct layout_effective_run *erun;
1366 BOOL skiptransform;
1367 UINT32 line;
1368 FLOAT det;
1370 erun = layout_get_next_erun(layout, NULL);
1371 inrun = layout_get_next_inline_run(layout, NULL);
1373 skiptransform = should_skip_transform(&layout->transform, &det);
1375 for (line = 0; line < layout->metrics.lineCount; line++) {
1376 FLOAT width = layout_get_line_width(layout, erun, inrun, line);
1377 FLOAT shift = layout_get_centered_shift(layout, skiptransform, width, det);
1379 if (is_rtl)
1380 shift *= -1.0f;
1382 while (erun && erun->line == line) {
1383 erun->align_dx = shift;
1384 erun = layout_get_next_erun(layout, erun);
1387 while (inrun && inrun->line == line) {
1388 inrun->align_dx = shift;
1389 inrun = layout_get_next_inline_run(layout, inrun);
1393 layout->metrics.left = (layout->metrics.layoutWidth - layout->metrics.width) / 2.0f;
1396 static void layout_apply_text_alignment(struct dwrite_textlayout *layout)
1398 switch (layout->format.textalignment)
1400 case DWRITE_TEXT_ALIGNMENT_LEADING:
1401 layout_apply_leading_alignment(layout);
1402 break;
1403 case DWRITE_TEXT_ALIGNMENT_TRAILING:
1404 layout_apply_trailing_alignment(layout);
1405 break;
1406 case DWRITE_TEXT_ALIGNMENT_CENTER:
1407 layout_apply_centered_alignment(layout);
1408 break;
1409 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED:
1410 FIXME("alignment %d not implemented\n", layout->format.textalignment);
1411 break;
1412 default:
1417 static void layout_apply_par_alignment(struct dwrite_textlayout *layout)
1419 struct layout_effective_inline *inrun;
1420 struct layout_effective_run *erun;
1421 FLOAT origin_y = 0.0f;
1422 UINT32 line;
1424 /* alignment mode defines origin, after that all run origins are updated
1425 the same way */
1427 switch (layout->format.paralign)
1429 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR:
1430 origin_y = 0.0f;
1431 break;
1432 case DWRITE_PARAGRAPH_ALIGNMENT_FAR:
1433 origin_y = layout->metrics.layoutHeight - layout->metrics.height;
1434 break;
1435 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER:
1436 origin_y = (layout->metrics.layoutHeight - layout->metrics.height) / 2.0f;
1437 break;
1438 default:
1442 layout->metrics.top = origin_y;
1444 erun = layout_get_next_erun(layout, NULL);
1445 inrun = layout_get_next_inline_run(layout, NULL);
1446 for (line = 0; line < layout->metrics.lineCount; line++) {
1447 origin_y += layout->lines[line].baseline;
1449 while (erun && erun->line == line) {
1450 erun->origin_y = origin_y;
1451 erun = layout_get_next_erun(layout, erun);
1454 while (inrun && inrun->line == line) {
1455 inrun->origin_y = origin_y;
1456 inrun = layout_get_next_inline_run(layout, inrun);
1461 struct layout_underline_splitting_params {
1462 const WCHAR *locale; /* points to range data, no additional allocation */
1463 IUnknown *effect; /* does not hold another reference */
1466 static void init_u_splitting_params_from_erun(struct layout_effective_run *erun,
1467 struct layout_underline_splitting_params *params)
1469 params->locale = erun->run->u.regular.descr.localeName;
1470 params->effect = erun->effect;
1473 static BOOL is_same_u_splitting(struct layout_underline_splitting_params *left,
1474 struct layout_underline_splitting_params *right)
1476 return left->effect == right->effect && !strcmpiW(left->locale, right->locale);
1479 static HRESULT layout_add_underline(struct dwrite_textlayout *layout, struct layout_effective_run *first,
1480 struct layout_effective_run *last)
1482 struct layout_underline_splitting_params params, prev_params;
1483 struct layout_effective_run *cur;
1484 DWRITE_FONT_METRICS metrics;
1485 FLOAT thickness, offset;
1487 if (first == layout_get_prev_erun(layout, last)) {
1488 layout_get_erun_font_metrics(layout, first, &metrics);
1489 thickness = SCALE_FONT_METRIC(metrics.underlineThickness, first->run->u.regular.run.fontEmSize, &metrics);
1490 offset = SCALE_FONT_METRIC(metrics.underlinePosition, first->run->u.regular.run.fontEmSize, &metrics);
1492 else {
1493 FLOAT width = 0.0f;
1495 /* Single underline is added for consecutive underlined runs. In this case underline parameters are
1496 calculated as weighted average, where run width acts as a weight. */
1497 thickness = offset = 0.0f;
1498 cur = first;
1499 do {
1500 layout_get_erun_font_metrics(layout, cur, &metrics);
1502 thickness += SCALE_FONT_METRIC(metrics.underlineThickness, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
1503 offset += SCALE_FONT_METRIC(metrics.underlinePosition, cur->run->u.regular.run.fontEmSize, &metrics) * cur->width;
1504 width += cur->width;
1506 cur = layout_get_next_erun(layout, cur);
1507 } while (cur != last);
1509 thickness /= width;
1510 offset /= width;
1513 cur = first;
1514 prev_params = params;
1515 do {
1516 struct layout_effective_run *next, *w;
1517 struct layout_underline *u;
1519 init_u_splitting_params_from_erun(cur, &prev_params);
1520 while ((next = layout_get_next_erun(layout, cur)) != last) {
1521 init_u_splitting_params_from_erun(next, &params);
1522 if (!is_same_u_splitting(&prev_params, &params))
1523 break;
1524 cur = next;
1527 u = heap_alloc(sizeof(*u));
1528 if (!u)
1529 return E_OUTOFMEMORY;
1531 w = cur;
1532 u->u.width = 0.0f;
1533 while (w != next) {
1534 u->u.width += w->width;
1535 w = layout_get_next_erun(layout, w);
1538 u->u.thickness = thickness;
1539 /* Font metrics convention is to have it negative when below baseline, for rendering
1540 however Y grows from baseline down for horizontal baseline. */
1541 u->u.offset = -offset;
1542 u->u.runHeight = 0.0f; /* FIXME */
1543 u->u.readingDirection = layout->format.readingdir;
1544 u->u.flowDirection = layout->format.flow;
1545 u->u.localeName = cur->run->u.regular.descr.localeName;
1546 u->u.measuringMode = layout->measuringmode;
1547 u->run = cur;
1548 list_add_tail(&layout->underlines, &u->entry);
1550 cur = next;
1551 } while (cur != last);
1553 return S_OK;
1556 static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
1558 BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
1559 struct layout_final_splitting_params prev_params, params;
1560 struct layout_effective_run *erun, *first_underlined;
1561 struct layout_effective_inline *inrun;
1562 const struct layout_run *run;
1563 DWRITE_LINE_METRICS metrics;
1564 FLOAT width, origin_x, origin_y;
1565 UINT32 i, start, line, textpos;
1566 HRESULT hr;
1568 if (!(layout->recompute & RECOMPUTE_EFFECTIVE_RUNS))
1569 return S_OK;
1571 hr = layout_compute(layout);
1572 if (FAILED(hr))
1573 return hr;
1575 layout->metrics.lineCount = 0;
1576 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0f;
1577 line = 0;
1578 run = layout->clusters[0].run;
1579 memset(&metrics, 0, sizeof(metrics));
1581 layout_splitting_params_from_pos(layout, 0, &params);
1582 prev_params = params;
1584 for (i = 0, start = 0, textpos = 0, width = 0.0f; i < layout->cluster_count; i++) {
1585 BOOL overflow;
1587 layout_splitting_params_from_pos(layout, textpos, &params);
1589 /* switched to next nominal run, at this point all previous pending clusters are already
1590 checked for layout line overflow, so new effective run will fit in current line */
1591 if (run != layout->clusters[i].run || !is_same_splitting_params(&prev_params, &params)) {
1592 hr = layout_add_effective_run(layout, run, start, i - start, line, origin_x, &prev_params);
1593 if (FAILED(hr))
1594 return hr;
1595 origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) :
1596 get_cluster_range_width(layout, start, i);
1597 run = layout->clusters[i].run;
1598 start = i;
1601 overflow = layout->clustermetrics[i].canWrapLineAfter &&
1602 (width + layout->clustermetrics[i].width > layout->metrics.layoutWidth);
1603 /* check if we got new */
1604 if (overflow ||
1605 layout->clustermetrics[i].isNewline || /* always wrap on new line */
1606 i == layout->cluster_count - 1) /* end of the text */ {
1608 UINT32 strlength, last_cluster, index;
1609 FLOAT descent, trailingspacewidth;
1610 struct layout_final_splitting_params *p;
1612 if (!overflow) {
1613 width += layout->clustermetrics[i].width;
1614 metrics.length += layout->clustermetrics[i].length;
1615 last_cluster = i;
1616 p = &params;
1618 else {
1619 last_cluster = i ? i - 1 : i;
1620 p = &prev_params;
1623 if (i >= start) {
1624 hr = layout_add_effective_run(layout, run, start, last_cluster - start + 1, line, origin_x, p);
1625 if (FAILED(hr))
1626 return hr;
1627 /* we don't need to update origin for next run as we're going to wrap */
1630 /* take a look at clusters we got for this line in reverse order to set
1631 trailing properties for current line */
1632 strlength = metrics.length;
1633 index = last_cluster;
1634 trailingspacewidth = 0.0f;
1635 while (strlength) {
1636 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1638 if (!cluster->isNewline && !cluster->isWhitespace)
1639 break;
1641 if (cluster->isNewline) {
1642 metrics.trailingWhitespaceLength += cluster->length;
1643 metrics.newlineLength += cluster->length;
1646 if (cluster->isWhitespace) {
1647 metrics.trailingWhitespaceLength += cluster->length;
1648 trailingspacewidth += cluster->width;
1651 strlength -= cluster->length;
1652 index--;
1655 /* look for max baseline and descent for this line */
1656 strlength = metrics.length;
1657 index = last_cluster;
1658 metrics.baseline = 0.0f;
1659 descent = 0.0f;
1660 while (strlength) {
1661 DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
1662 const struct layout_run *cur = layout->clusters[index].run;
1663 FLOAT cur_descent = cur->height - cur->baseline;
1665 if (cur->baseline > metrics.baseline)
1666 metrics.baseline = cur->baseline;
1668 if (cur_descent > descent)
1669 descent = cur_descent;
1671 strlength -= cluster->length;
1672 index--;
1674 metrics.height = descent + metrics.baseline;
1676 if (width > layout->metrics.widthIncludingTrailingWhitespace)
1677 layout->metrics.widthIncludingTrailingWhitespace = width;
1678 if (width - trailingspacewidth > layout->metrics.width)
1679 layout->metrics.width = width - trailingspacewidth;
1681 metrics.isTrimmed = width > layout->metrics.layoutWidth;
1682 hr = layout_set_line_metrics(layout, &metrics, &line);
1683 if (FAILED(hr))
1684 return hr;
1686 width = layout->clustermetrics[i].width;
1687 memset(&metrics, 0, sizeof(metrics));
1688 origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0f;
1689 start = i;
1691 else {
1692 metrics.length += layout->clustermetrics[i].length;
1693 width += layout->clustermetrics[i].width;
1696 prev_params = params;
1697 textpos += layout->clustermetrics[i].length;
1700 layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0;
1701 layout->metrics.top = 0.0f;
1702 layout->metrics.maxBidiReorderingDepth = 1; /* FIXME */
1703 layout->metrics.height = 0.0f;
1705 /* Now all line info is here, update effective runs positions in flow direction */
1706 erun = layout_get_next_erun(layout, NULL);
1707 first_underlined = erun && erun->underlined ? erun : NULL;
1709 inrun = layout_get_next_inline_run(layout, NULL);
1711 origin_y = 0.0f;
1712 for (line = 0; line < layout->metrics.lineCount; line++) {
1714 origin_y += layout->lines[line].baseline;
1716 /* For all runs on this line */
1717 while (erun && erun->line == line) {
1718 erun->origin_y = origin_y;
1719 erun = layout_get_next_erun(layout, erun);
1721 if (first_underlined && (!erun || !erun->underlined)) {
1722 layout_add_underline(layout, first_underlined, erun);
1723 first_underlined = NULL;
1725 else if (!first_underlined && erun && erun->underlined)
1726 first_underlined = erun;
1729 /* Same for inline runs */
1730 while (inrun && inrun->line == line) {
1731 inrun->origin_y = origin_y;
1732 inrun = layout_get_next_inline_run(layout, inrun);
1735 layout->metrics.height += layout->lines[line].height;
1738 /* initial alignment is always leading */
1739 if (layout->format.textalignment != DWRITE_TEXT_ALIGNMENT_LEADING)
1740 layout_apply_text_alignment(layout);
1742 /* initial paragraph alignment is always near */
1743 if (layout->format.paralign != DWRITE_PARAGRAPH_ALIGNMENT_NEAR)
1744 layout_apply_par_alignment(layout);
1746 layout->metrics.heightIncludingTrailingWhitespace = layout->metrics.height; /* FIXME: not true for vertical text */
1748 layout->recompute &= ~RECOMPUTE_EFFECTIVE_RUNS;
1749 return hr;
1752 static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
1754 struct layout_range_spacing const *range_spacing = (struct layout_range_spacing*)h;
1755 struct layout_range_iface const *range_iface = (struct layout_range_iface*)h;
1756 struct layout_range_bool const *range_bool = (struct layout_range_bool*)h;
1757 struct layout_range const *range = (struct layout_range*)h;
1759 switch (attr) {
1760 case LAYOUT_RANGE_ATTR_WEIGHT:
1761 return range->weight == value->u.weight;
1762 case LAYOUT_RANGE_ATTR_STYLE:
1763 return range->style == value->u.style;
1764 case LAYOUT_RANGE_ATTR_STRETCH:
1765 return range->stretch == value->u.stretch;
1766 case LAYOUT_RANGE_ATTR_FONTSIZE:
1767 return range->fontsize == value->u.fontsize;
1768 case LAYOUT_RANGE_ATTR_INLINE:
1769 return range->object == value->u.object;
1770 case LAYOUT_RANGE_ATTR_EFFECT:
1771 return range_iface->iface == value->u.effect;
1772 case LAYOUT_RANGE_ATTR_UNDERLINE:
1773 return range_bool->value == value->u.underline;
1774 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
1775 return range_bool->value == value->u.strikethrough;
1776 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
1777 return range->pair_kerning == value->u.pair_kerning;
1778 case LAYOUT_RANGE_ATTR_FONTCOLL:
1779 return range->collection == value->u.collection;
1780 case LAYOUT_RANGE_ATTR_LOCALE:
1781 return strcmpiW(range->locale, value->u.locale) == 0;
1782 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1783 return strcmpW(range->fontfamily, value->u.fontfamily) == 0;
1784 case LAYOUT_RANGE_ATTR_SPACING:
1785 return range_spacing->leading == value->u.spacing[0] &&
1786 range_spacing->trailing == value->u.spacing[1] &&
1787 range_spacing->min_advance == value->u.spacing[2];
1788 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
1789 return range_iface->iface == (IUnknown*)value->u.typography;
1790 default:
1794 return FALSE;
1797 static inline BOOL is_same_layout_attributes(struct layout_range_header const *hleft, struct layout_range_header const *hright)
1799 switch (hleft->kind)
1801 case LAYOUT_RANGE_REGULAR:
1803 struct layout_range const *left = (struct layout_range const*)hleft;
1804 struct layout_range const *right = (struct layout_range const*)hright;
1805 return left->weight == right->weight &&
1806 left->style == right->style &&
1807 left->stretch == right->stretch &&
1808 left->fontsize == right->fontsize &&
1809 left->object == right->object &&
1810 left->pair_kerning == right->pair_kerning &&
1811 left->collection == right->collection &&
1812 !strcmpiW(left->locale, right->locale) &&
1813 !strcmpW(left->fontfamily, right->fontfamily);
1815 case LAYOUT_RANGE_UNDERLINE:
1816 case LAYOUT_RANGE_STRIKETHROUGH:
1818 struct layout_range_bool const *left = (struct layout_range_bool const*)hleft;
1819 struct layout_range_bool const *right = (struct layout_range_bool const*)hright;
1820 return left->value == right->value;
1822 case LAYOUT_RANGE_EFFECT:
1823 case LAYOUT_RANGE_TYPOGRAPHY:
1825 struct layout_range_iface const *left = (struct layout_range_iface const*)hleft;
1826 struct layout_range_iface const *right = (struct layout_range_iface const*)hright;
1827 return left->iface == right->iface;
1829 case LAYOUT_RANGE_SPACING:
1831 struct layout_range_spacing const *left = (struct layout_range_spacing const*)hleft;
1832 struct layout_range_spacing const *right = (struct layout_range_spacing const*)hright;
1833 return left->leading == right->leading &&
1834 left->trailing == right->trailing &&
1835 left->min_advance == right->min_advance;
1837 default:
1838 FIXME("unknown range kind %d\n", hleft->kind);
1839 return FALSE;
1843 static inline BOOL is_same_text_range(const DWRITE_TEXT_RANGE *left, const DWRITE_TEXT_RANGE *right)
1845 return left->startPosition == right->startPosition && left->length == right->length;
1848 /* Allocates range and inits it with default values from text format. */
1849 static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout *layout, const DWRITE_TEXT_RANGE *r,
1850 enum layout_range_kind kind)
1852 struct layout_range_header *h;
1854 switch (kind)
1856 case LAYOUT_RANGE_REGULAR:
1858 struct layout_range *range;
1860 range = heap_alloc(sizeof(*range));
1861 if (!range) return NULL;
1863 range->weight = layout->format.weight;
1864 range->style = layout->format.style;
1865 range->stretch = layout->format.stretch;
1866 range->fontsize = layout->format.fontsize;
1867 range->object = NULL;
1868 range->pair_kerning = FALSE;
1870 range->fontfamily = heap_strdupW(layout->format.family_name);
1871 if (!range->fontfamily) {
1872 heap_free(range);
1873 return NULL;
1876 range->collection = layout->format.collection;
1877 if (range->collection)
1878 IDWriteFontCollection_AddRef(range->collection);
1879 strcpyW(range->locale, layout->format.locale);
1881 h = &range->h;
1882 break;
1884 case LAYOUT_RANGE_UNDERLINE:
1885 case LAYOUT_RANGE_STRIKETHROUGH:
1887 struct layout_range_bool *range;
1889 range = heap_alloc(sizeof(*range));
1890 if (!range) return NULL;
1892 range->value = FALSE;
1893 h = &range->h;
1894 break;
1896 case LAYOUT_RANGE_EFFECT:
1897 case LAYOUT_RANGE_TYPOGRAPHY:
1899 struct layout_range_iface *range;
1901 range = heap_alloc(sizeof(*range));
1902 if (!range) return NULL;
1904 range->iface = NULL;
1905 h = &range->h;
1906 break;
1908 case LAYOUT_RANGE_SPACING:
1910 struct layout_range_spacing *range;
1912 range = heap_alloc(sizeof(*range));
1913 if (!range) return NULL;
1915 range->leading = 0.0f;
1916 range->trailing = 0.0f;
1917 range->min_advance = 0.0f;
1918 h = &range->h;
1919 break;
1921 default:
1922 FIXME("unknown range kind %d\n", kind);
1923 return NULL;
1926 h->kind = kind;
1927 h->range = *r;
1928 return h;
1931 static struct layout_range_header *alloc_layout_range_from(struct layout_range_header *h, const DWRITE_TEXT_RANGE *r)
1933 struct layout_range_header *ret;
1935 switch (h->kind)
1937 case LAYOUT_RANGE_REGULAR:
1939 struct layout_range *from = (struct layout_range*)h;
1941 struct layout_range *range = heap_alloc(sizeof(*range));
1942 if (!range) return NULL;
1944 *range = *from;
1945 range->fontfamily = heap_strdupW(from->fontfamily);
1946 if (!range->fontfamily) {
1947 heap_free(range);
1948 return NULL;
1951 /* update refcounts */
1952 if (range->object)
1953 IDWriteInlineObject_AddRef(range->object);
1954 if (range->collection)
1955 IDWriteFontCollection_AddRef(range->collection);
1956 ret = &range->h;
1957 break;
1959 case LAYOUT_RANGE_UNDERLINE:
1960 case LAYOUT_RANGE_STRIKETHROUGH:
1962 struct layout_range_bool *strike = heap_alloc(sizeof(*strike));
1963 if (!strike) return NULL;
1965 *strike = *(struct layout_range_bool*)h;
1966 ret = &strike->h;
1967 break;
1969 case LAYOUT_RANGE_EFFECT:
1970 case LAYOUT_RANGE_TYPOGRAPHY:
1972 struct layout_range_iface *effect = heap_alloc(sizeof(*effect));
1973 if (!effect) return NULL;
1975 *effect = *(struct layout_range_iface*)h;
1976 if (effect->iface)
1977 IUnknown_AddRef(effect->iface);
1978 ret = &effect->h;
1979 break;
1981 case LAYOUT_RANGE_SPACING:
1983 struct layout_range_spacing *spacing = heap_alloc(sizeof(*spacing));
1984 if (!spacing) return NULL;
1986 *spacing = *(struct layout_range_spacing*)h;
1987 ret = &spacing->h;
1988 break;
1990 default:
1991 FIXME("unknown range kind %d\n", h->kind);
1992 return NULL;
1995 ret->range = *r;
1996 return ret;
1999 static void free_layout_range(struct layout_range_header *h)
2001 if (!h)
2002 return;
2004 switch (h->kind)
2006 case LAYOUT_RANGE_REGULAR:
2008 struct layout_range *range = (struct layout_range*)h;
2010 if (range->object)
2011 IDWriteInlineObject_Release(range->object);
2012 if (range->collection)
2013 IDWriteFontCollection_Release(range->collection);
2014 heap_free(range->fontfamily);
2015 break;
2017 case LAYOUT_RANGE_EFFECT:
2018 case LAYOUT_RANGE_TYPOGRAPHY:
2020 struct layout_range_iface *range = (struct layout_range_iface*)h;
2021 if (range->iface)
2022 IUnknown_Release(range->iface);
2023 break;
2025 default:
2029 heap_free(h);
2032 static void free_layout_ranges_list(struct dwrite_textlayout *layout)
2034 struct layout_range_header *cur, *cur2;
2036 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->ranges, struct layout_range_header, entry) {
2037 list_remove(&cur->entry);
2038 free_layout_range(cur);
2041 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->underline_ranges, struct layout_range_header, entry) {
2042 list_remove(&cur->entry);
2043 free_layout_range(cur);
2046 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->strike_ranges, struct layout_range_header, entry) {
2047 list_remove(&cur->entry);
2048 free_layout_range(cur);
2051 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->effects, struct layout_range_header, entry) {
2052 list_remove(&cur->entry);
2053 free_layout_range(cur);
2056 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->spacing, struct layout_range_header, entry) {
2057 list_remove(&cur->entry);
2058 free_layout_range(cur);
2061 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->typographies, struct layout_range_header, entry) {
2062 list_remove(&cur->entry);
2063 free_layout_range(cur);
2067 static struct layout_range_header *find_outer_range(struct list *ranges, const DWRITE_TEXT_RANGE *range)
2069 struct layout_range_header *cur;
2071 LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
2073 if (cur->range.startPosition > range->startPosition)
2074 return NULL;
2076 if ((cur->range.startPosition + cur->range.length < range->startPosition + range->length) &&
2077 (range->startPosition < cur->range.startPosition + cur->range.length))
2078 return NULL;
2079 if (cur->range.startPosition + cur->range.length >= range->startPosition + range->length)
2080 return cur;
2083 return NULL;
2086 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos)
2088 struct layout_range *cur;
2090 LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, h.entry) {
2091 DWRITE_TEXT_RANGE *r = &cur->h.range;
2092 if (r->startPosition <= pos && pos < r->startPosition + r->length)
2093 return cur;
2096 return NULL;
2099 static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
2101 if (*dest == value) return FALSE;
2103 if (*dest)
2104 IUnknown_Release(*dest);
2105 *dest = value;
2106 if (*dest)
2107 IUnknown_AddRef(*dest);
2109 return TRUE;
2112 static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2114 struct layout_range_spacing *dest_spacing = (struct layout_range_spacing*)h;
2115 struct layout_range_iface *dest_iface = (struct layout_range_iface*)h;
2116 struct layout_range_bool *dest_bool = (struct layout_range_bool*)h;
2117 struct layout_range *dest = (struct layout_range*)h;
2119 BOOL changed = FALSE;
2121 switch (attr) {
2122 case LAYOUT_RANGE_ATTR_WEIGHT:
2123 changed = dest->weight != value->u.weight;
2124 dest->weight = value->u.weight;
2125 break;
2126 case LAYOUT_RANGE_ATTR_STYLE:
2127 changed = dest->style != value->u.style;
2128 dest->style = value->u.style;
2129 break;
2130 case LAYOUT_RANGE_ATTR_STRETCH:
2131 changed = dest->stretch != value->u.stretch;
2132 dest->stretch = value->u.stretch;
2133 break;
2134 case LAYOUT_RANGE_ATTR_FONTSIZE:
2135 changed = dest->fontsize != value->u.fontsize;
2136 dest->fontsize = value->u.fontsize;
2137 break;
2138 case LAYOUT_RANGE_ATTR_INLINE:
2139 changed = set_layout_range_iface_attr((IUnknown**)&dest->object, (IUnknown*)value->u.object);
2140 break;
2141 case LAYOUT_RANGE_ATTR_EFFECT:
2142 changed = set_layout_range_iface_attr((IUnknown**)&dest_iface->iface, (IUnknown*)value->u.effect);
2143 break;
2144 case LAYOUT_RANGE_ATTR_UNDERLINE:
2145 changed = dest_bool->value != value->u.underline;
2146 dest_bool->value = value->u.underline;
2147 break;
2148 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2149 changed = dest_bool->value != value->u.strikethrough;
2150 dest_bool->value = value->u.strikethrough;
2151 break;
2152 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2153 changed = dest->pair_kerning != value->u.pair_kerning;
2154 dest->pair_kerning = value->u.pair_kerning;
2155 break;
2156 case LAYOUT_RANGE_ATTR_FONTCOLL:
2157 changed = set_layout_range_iface_attr((IUnknown**)&dest->collection, (IUnknown*)value->u.collection);
2158 break;
2159 case LAYOUT_RANGE_ATTR_LOCALE:
2160 changed = strcmpiW(dest->locale, value->u.locale) != 0;
2161 if (changed) {
2162 strcpyW(dest->locale, value->u.locale);
2163 strlwrW(dest->locale);
2165 break;
2166 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2167 changed = strcmpW(dest->fontfamily, value->u.fontfamily) != 0;
2168 if (changed) {
2169 heap_free(dest->fontfamily);
2170 dest->fontfamily = heap_strdupW(value->u.fontfamily);
2172 break;
2173 case LAYOUT_RANGE_ATTR_SPACING:
2174 changed = dest_spacing->leading != value->u.spacing[0] ||
2175 dest_spacing->trailing != value->u.spacing[1] ||
2176 dest_spacing->min_advance != value->u.spacing[2];
2177 dest_spacing->leading = value->u.spacing[0];
2178 dest_spacing->trailing = value->u.spacing[1];
2179 dest_spacing->min_advance = value->u.spacing[2];
2180 break;
2181 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2182 changed = set_layout_range_iface_attr((IUnknown**)&dest_iface->iface, (IUnknown*)value->u.typography);
2183 break;
2184 default:
2188 return changed;
2191 static inline BOOL is_in_layout_range(const DWRITE_TEXT_RANGE *outer, const DWRITE_TEXT_RANGE *inner)
2193 return (inner->startPosition >= outer->startPosition) &&
2194 (inner->startPosition + inner->length <= outer->startPosition + outer->length);
2197 static inline HRESULT return_range(const struct layout_range_header *h, DWRITE_TEXT_RANGE *r)
2199 if (r) *r = h->range;
2200 return S_OK;
2203 /* Set attribute value for given range, does all needed splitting/merging of existing ranges. */
2204 static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
2206 struct layout_range_header *cur, *right, *left, *outer;
2207 BOOL changed = FALSE;
2208 struct list *ranges;
2209 DWRITE_TEXT_RANGE r;
2211 /* ignore zero length ranges */
2212 if (value->range.length == 0)
2213 return S_OK;
2215 /* select from ranges lists */
2216 switch (attr)
2218 case LAYOUT_RANGE_ATTR_WEIGHT:
2219 case LAYOUT_RANGE_ATTR_STYLE:
2220 case LAYOUT_RANGE_ATTR_STRETCH:
2221 case LAYOUT_RANGE_ATTR_FONTSIZE:
2222 case LAYOUT_RANGE_ATTR_INLINE:
2223 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
2224 case LAYOUT_RANGE_ATTR_FONTCOLL:
2225 case LAYOUT_RANGE_ATTR_LOCALE:
2226 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2227 ranges = &layout->ranges;
2228 break;
2229 case LAYOUT_RANGE_ATTR_UNDERLINE:
2230 ranges = &layout->underline_ranges;
2231 break;
2232 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
2233 ranges = &layout->strike_ranges;
2234 break;
2235 case LAYOUT_RANGE_ATTR_EFFECT:
2236 ranges = &layout->effects;
2237 break;
2238 case LAYOUT_RANGE_ATTR_SPACING:
2239 ranges = &layout->spacing;
2240 break;
2241 case LAYOUT_RANGE_ATTR_TYPOGRAPHY:
2242 ranges = &layout->typographies;
2243 break;
2244 default:
2245 FIXME("unknown attr kind %d\n", attr);
2246 return E_FAIL;
2249 /* If new range is completely within existing range, split existing range in two */
2250 if ((outer = find_outer_range(ranges, &value->range))) {
2252 /* no need to add same range */
2253 if (is_same_layout_attrvalue(outer, attr, value))
2254 return S_OK;
2256 /* for matching range bounds just replace data */
2257 if (is_same_text_range(&outer->range, &value->range)) {
2258 changed = set_layout_range_attrval(outer, attr, value);
2259 goto done;
2262 /* add new range to the left */
2263 if (value->range.startPosition == outer->range.startPosition) {
2264 left = alloc_layout_range_from(outer, &value->range);
2265 if (!left) return E_OUTOFMEMORY;
2267 changed = set_layout_range_attrval(left, attr, value);
2268 list_add_before(&outer->entry, &left->entry);
2269 outer->range.startPosition += value->range.length;
2270 outer->range.length -= value->range.length;
2271 goto done;
2274 /* add new range to the right */
2275 if (value->range.startPosition + value->range.length == outer->range.startPosition + outer->range.length) {
2276 right = alloc_layout_range_from(outer, &value->range);
2277 if (!right) return E_OUTOFMEMORY;
2279 changed = set_layout_range_attrval(right, attr, value);
2280 list_add_after(&outer->entry, &right->entry);
2281 outer->range.length -= value->range.length;
2282 goto done;
2285 r.startPosition = value->range.startPosition + value->range.length;
2286 r.length = outer->range.length + outer->range.startPosition - r.startPosition;
2288 /* right part */
2289 right = alloc_layout_range_from(outer, &r);
2290 /* new range in the middle */
2291 cur = alloc_layout_range_from(outer, &value->range);
2292 if (!right || !cur) {
2293 free_layout_range(right);
2294 free_layout_range(cur);
2295 return E_OUTOFMEMORY;
2298 /* reuse container range as a left part */
2299 outer->range.length = value->range.startPosition - outer->range.startPosition;
2301 /* new part */
2302 set_layout_range_attrval(cur, attr, value);
2304 list_add_after(&outer->entry, &cur->entry);
2305 list_add_after(&cur->entry, &right->entry);
2307 return S_OK;
2310 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2311 Update all of them. */
2312 left = get_layout_range_header_by_pos(ranges, value->range.startPosition);
2313 if (left->range.startPosition == value->range.startPosition)
2314 changed = set_layout_range_attrval(left, attr, value);
2315 else /* need to split */ {
2316 r.startPosition = value->range.startPosition;
2317 r.length = left->range.length - value->range.startPosition + left->range.startPosition;
2318 left->range.length -= r.length;
2319 cur = alloc_layout_range_from(left, &r);
2320 changed = set_layout_range_attrval(cur, attr, value);
2321 list_add_after(&left->entry, &cur->entry);
2323 cur = LIST_ENTRY(list_next(ranges, &left->entry), struct layout_range_header, entry);
2325 /* for all existing ranges covered by new one update value */
2326 while (cur && is_in_layout_range(&value->range, &cur->range)) {
2327 changed |= set_layout_range_attrval(cur, attr, value);
2328 cur = LIST_ENTRY(list_next(ranges, &cur->entry), struct layout_range_header, entry);
2331 /* it's possible rightmost range intersects */
2332 if (cur && (cur->range.startPosition < value->range.startPosition + value->range.length)) {
2333 r.startPosition = cur->range.startPosition;
2334 r.length = value->range.startPosition + value->range.length - cur->range.startPosition;
2335 left = alloc_layout_range_from(cur, &r);
2336 changed |= set_layout_range_attrval(left, attr, value);
2337 cur->range.startPosition += left->range.length;
2338 cur->range.length -= left->range.length;
2339 list_add_before(&cur->entry, &left->entry);
2342 done:
2343 if (changed) {
2344 struct list *next, *i;
2346 layout->recompute = RECOMPUTE_EVERYTHING;
2347 i = list_head(ranges);
2348 while ((next = list_next(ranges, i))) {
2349 struct layout_range_header *next_range = LIST_ENTRY(next, struct layout_range_header, entry);
2351 cur = LIST_ENTRY(i, struct layout_range_header, entry);
2352 if (is_same_layout_attributes(cur, next_range)) {
2353 /* remove similar range */
2354 cur->range.length += next_range->range.length;
2355 list_remove(next);
2356 free_layout_range(next_range);
2358 else
2359 i = list_next(ranges, i);
2363 return S_OK;
2366 static inline const WCHAR *get_string_attribute_ptr(struct layout_range *range, enum layout_range_attr_kind kind)
2368 const WCHAR *str;
2370 switch (kind) {
2371 case LAYOUT_RANGE_ATTR_LOCALE:
2372 str = range->locale;
2373 break;
2374 case LAYOUT_RANGE_ATTR_FONTFAMILY:
2375 str = range->fontfamily;
2376 break;
2377 default:
2378 str = NULL;
2381 return str;
2384 static HRESULT get_string_attribute_length(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2385 UINT32 *length, DWRITE_TEXT_RANGE *r)
2387 struct layout_range *range;
2388 const WCHAR *str;
2390 range = get_layout_range_by_pos(layout, position);
2391 if (!range) {
2392 *length = 0;
2393 return S_OK;
2396 str = get_string_attribute_ptr(range, kind);
2397 *length = strlenW(str);
2398 return return_range(&range->h, r);
2401 static HRESULT get_string_attribute_value(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
2402 WCHAR *ret, UINT32 length, DWRITE_TEXT_RANGE *r)
2404 struct layout_range *range;
2405 const WCHAR *str;
2407 if (length == 0)
2408 return E_INVALIDARG;
2410 ret[0] = 0;
2411 range = get_layout_range_by_pos(layout, position);
2412 if (!range)
2413 return E_INVALIDARG;
2415 str = get_string_attribute_ptr(range, kind);
2416 if (length < strlenW(str) + 1)
2417 return E_NOT_SUFFICIENT_BUFFER;
2419 strcpyW(ret, str);
2420 return return_range(&range->h, r);
2423 static HRESULT WINAPI dwritetextlayout_QueryInterface(IDWriteTextLayout2 *iface, REFIID riid, void **obj)
2425 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2427 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2429 *obj = NULL;
2431 if (IsEqualIID(riid, &IID_IDWriteTextLayout2) ||
2432 IsEqualIID(riid, &IID_IDWriteTextLayout1) ||
2433 IsEqualIID(riid, &IID_IDWriteTextLayout) ||
2434 IsEqualIID(riid, &IID_IUnknown))
2436 *obj = iface;
2438 else if (IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
2439 IsEqualIID(riid, &IID_IDWriteTextFormat))
2440 *obj = &This->IDWriteTextFormat1_iface;
2442 if (*obj) {
2443 IDWriteTextLayout2_AddRef(iface);
2444 return S_OK;
2447 return E_NOINTERFACE;
2450 static ULONG WINAPI dwritetextlayout_AddRef(IDWriteTextLayout2 *iface)
2452 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2453 ULONG ref = InterlockedIncrement(&This->ref);
2454 TRACE("(%p)->(%d)\n", This, ref);
2455 return ref;
2458 static ULONG WINAPI dwritetextlayout_Release(IDWriteTextLayout2 *iface)
2460 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2461 ULONG ref = InterlockedDecrement(&This->ref);
2463 TRACE("(%p)->(%d)\n", This, ref);
2465 if (!ref) {
2466 free_layout_ranges_list(This);
2467 free_layout_eruns(This);
2468 free_layout_runs(This);
2469 release_format_data(&This->format);
2470 heap_free(This->nominal_breakpoints);
2471 heap_free(This->actual_breakpoints);
2472 heap_free(This->clustermetrics);
2473 heap_free(This->clusters);
2474 heap_free(This->lines);
2475 heap_free(This->str);
2476 heap_free(This);
2479 return ref;
2482 static HRESULT WINAPI dwritetextlayout_SetTextAlignment(IDWriteTextLayout2 *iface, DWRITE_TEXT_ALIGNMENT alignment)
2484 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2485 return IDWriteTextFormat1_SetTextAlignment(&This->IDWriteTextFormat1_iface, alignment);
2488 static HRESULT WINAPI dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout2 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
2490 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2491 return IDWriteTextFormat1_SetParagraphAlignment(&This->IDWriteTextFormat1_iface, alignment);
2494 static HRESULT WINAPI dwritetextlayout_SetWordWrapping(IDWriteTextLayout2 *iface, DWRITE_WORD_WRAPPING wrapping)
2496 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2497 return IDWriteTextFormat1_SetWordWrapping(&This->IDWriteTextFormat1_iface, wrapping);
2500 static HRESULT WINAPI dwritetextlayout_SetReadingDirection(IDWriteTextLayout2 *iface, DWRITE_READING_DIRECTION direction)
2502 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2503 return IDWriteTextFormat1_SetReadingDirection(&This->IDWriteTextFormat1_iface, direction);
2506 static HRESULT WINAPI dwritetextlayout_SetFlowDirection(IDWriteTextLayout2 *iface, DWRITE_FLOW_DIRECTION direction)
2508 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2509 TRACE("(%p)->(%d)\n", This, direction);
2510 return IDWriteTextFormat1_SetFlowDirection(&This->IDWriteTextFormat1_iface, direction);
2513 static HRESULT WINAPI dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout2 *iface, FLOAT tabstop)
2515 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2516 TRACE("(%p)->(%.2f)\n", This, tabstop);
2517 return IDWriteTextFormat1_SetIncrementalTabStop(&This->IDWriteTextFormat1_iface, tabstop);
2520 static HRESULT WINAPI dwritetextlayout_SetTrimming(IDWriteTextLayout2 *iface, DWRITE_TRIMMING const *trimming,
2521 IDWriteInlineObject *trimming_sign)
2523 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2524 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
2525 return IDWriteTextFormat1_SetTrimming(&This->IDWriteTextFormat1_iface, trimming, trimming_sign);
2528 static HRESULT WINAPI dwritetextlayout_SetLineSpacing(IDWriteTextLayout2 *iface, DWRITE_LINE_SPACING_METHOD spacing,
2529 FLOAT line_spacing, FLOAT baseline)
2531 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2532 TRACE("(%p)->(%d %.2f %.2f)\n", This, spacing, line_spacing, baseline);
2533 return IDWriteTextFormat1_SetLineSpacing(&This->IDWriteTextFormat1_iface, spacing, line_spacing, baseline);
2536 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextlayout_GetTextAlignment(IDWriteTextLayout2 *iface)
2538 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2539 return IDWriteTextFormat1_GetTextAlignment(&This->IDWriteTextFormat1_iface);
2542 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout2 *iface)
2544 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2545 return IDWriteTextFormat1_GetParagraphAlignment(&This->IDWriteTextFormat1_iface);
2548 static DWRITE_WORD_WRAPPING WINAPI dwritetextlayout_GetWordWrapping(IDWriteTextLayout2 *iface)
2550 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2551 return IDWriteTextFormat1_GetWordWrapping(&This->IDWriteTextFormat1_iface);
2554 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_GetReadingDirection(IDWriteTextLayout2 *iface)
2556 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2557 return IDWriteTextFormat1_GetReadingDirection(&This->IDWriteTextFormat1_iface);
2560 static DWRITE_FLOW_DIRECTION WINAPI dwritetextlayout_GetFlowDirection(IDWriteTextLayout2 *iface)
2562 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2563 return IDWriteTextFormat1_GetFlowDirection(&This->IDWriteTextFormat1_iface);
2566 static FLOAT WINAPI dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout2 *iface)
2568 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2569 return IDWriteTextFormat1_GetIncrementalTabStop(&This->IDWriteTextFormat1_iface);
2572 static HRESULT WINAPI dwritetextlayout_GetTrimming(IDWriteTextLayout2 *iface, DWRITE_TRIMMING *options,
2573 IDWriteInlineObject **trimming_sign)
2575 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2576 return IDWriteTextFormat1_GetTrimming(&This->IDWriteTextFormat1_iface, options, trimming_sign);
2579 static HRESULT WINAPI dwritetextlayout_GetLineSpacing(IDWriteTextLayout2 *iface, DWRITE_LINE_SPACING_METHOD *method,
2580 FLOAT *spacing, FLOAT *baseline)
2582 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2583 return IDWriteTextFormat1_GetLineSpacing(&This->IDWriteTextFormat1_iface, method, spacing, baseline);
2586 static HRESULT WINAPI dwritetextlayout_GetFontCollection(IDWriteTextLayout2 *iface, IDWriteFontCollection **collection)
2588 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2589 return IDWriteTextFormat1_GetFontCollection(&This->IDWriteTextFormat1_iface, collection);
2592 static UINT32 WINAPI dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout2 *iface)
2594 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2595 return IDWriteTextFormat1_GetFontFamilyNameLength(&This->IDWriteTextFormat1_iface);
2598 static HRESULT WINAPI dwritetextlayout_GetFontFamilyName(IDWriteTextLayout2 *iface, WCHAR *name, UINT32 size)
2600 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2601 return IDWriteTextFormat1_GetFontFamilyName(&This->IDWriteTextFormat1_iface, name, size);
2604 static DWRITE_FONT_WEIGHT WINAPI dwritetextlayout_GetFontWeight(IDWriteTextLayout2 *iface)
2606 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2607 return IDWriteTextFormat1_GetFontWeight(&This->IDWriteTextFormat1_iface);
2610 static DWRITE_FONT_STYLE WINAPI dwritetextlayout_GetFontStyle(IDWriteTextLayout2 *iface)
2612 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2613 return IDWriteTextFormat1_GetFontStyle(&This->IDWriteTextFormat1_iface);
2616 static DWRITE_FONT_STRETCH WINAPI dwritetextlayout_GetFontStretch(IDWriteTextLayout2 *iface)
2618 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2619 return IDWriteTextFormat1_GetFontStretch(&This->IDWriteTextFormat1_iface);
2622 static FLOAT WINAPI dwritetextlayout_GetFontSize(IDWriteTextLayout2 *iface)
2624 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2625 return IDWriteTextFormat1_GetFontSize(&This->IDWriteTextFormat1_iface);
2628 static UINT32 WINAPI dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout2 *iface)
2630 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2631 return IDWriteTextFormat1_GetLocaleNameLength(&This->IDWriteTextFormat1_iface);
2634 static HRESULT WINAPI dwritetextlayout_GetLocaleName(IDWriteTextLayout2 *iface, WCHAR *name, UINT32 size)
2636 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2637 return IDWriteTextFormat1_GetLocaleName(&This->IDWriteTextFormat1_iface, name, size);
2640 static HRESULT WINAPI dwritetextlayout_SetMaxWidth(IDWriteTextLayout2 *iface, FLOAT maxWidth)
2642 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2644 TRACE("(%p)->(%.2f)\n", This, maxWidth);
2646 if (maxWidth < 0.0f)
2647 return E_INVALIDARG;
2649 This->metrics.layoutWidth = maxWidth;
2650 return S_OK;
2653 static HRESULT WINAPI dwritetextlayout_SetMaxHeight(IDWriteTextLayout2 *iface, FLOAT maxHeight)
2655 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2657 TRACE("(%p)->(%.2f)\n", This, maxHeight);
2659 if (maxHeight < 0.0f)
2660 return E_INVALIDARG;
2662 This->metrics.layoutHeight = maxHeight;
2663 return S_OK;
2666 static HRESULT WINAPI dwritetextlayout_SetFontCollection(IDWriteTextLayout2 *iface, IDWriteFontCollection* collection, DWRITE_TEXT_RANGE range)
2668 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2669 struct layout_range_attr_value value;
2671 TRACE("(%p)->(%p %s)\n", This, collection, debugstr_range(&range));
2673 value.range = range;
2674 value.u.collection = collection;
2675 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTCOLL, &value);
2678 static HRESULT WINAPI dwritetextlayout_SetFontFamilyName(IDWriteTextLayout2 *iface, WCHAR const *name, DWRITE_TEXT_RANGE range)
2680 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2681 struct layout_range_attr_value value;
2683 TRACE("(%p)->(%s %s)\n", This, debugstr_w(name), debugstr_range(&range));
2685 if (!name)
2686 return E_INVALIDARG;
2688 value.range = range;
2689 value.u.fontfamily = name;
2690 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTFAMILY, &value);
2693 static HRESULT WINAPI dwritetextlayout_SetFontWeight(IDWriteTextLayout2 *iface, DWRITE_FONT_WEIGHT weight, DWRITE_TEXT_RANGE range)
2695 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2696 struct layout_range_attr_value value;
2698 TRACE("(%p)->(%d %s)\n", This, weight, debugstr_range(&range));
2700 value.range = range;
2701 value.u.weight = weight;
2702 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_WEIGHT, &value);
2705 static HRESULT WINAPI dwritetextlayout_SetFontStyle(IDWriteTextLayout2 *iface, DWRITE_FONT_STYLE style, DWRITE_TEXT_RANGE range)
2707 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2708 struct layout_range_attr_value value;
2710 TRACE("(%p)->(%d %s)\n", This, style, debugstr_range(&range));
2712 if ((UINT32)style > DWRITE_FONT_STYLE_ITALIC)
2713 return E_INVALIDARG;
2715 value.range = range;
2716 value.u.style = style;
2717 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STYLE, &value);
2720 static HRESULT WINAPI dwritetextlayout_SetFontStretch(IDWriteTextLayout2 *iface, DWRITE_FONT_STRETCH stretch, DWRITE_TEXT_RANGE range)
2722 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2723 struct layout_range_attr_value value;
2725 TRACE("(%p)->(%d %s)\n", This, stretch, debugstr_range(&range));
2727 if (stretch == DWRITE_FONT_STRETCH_UNDEFINED || (UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
2728 return E_INVALIDARG;
2730 value.range = range;
2731 value.u.stretch = stretch;
2732 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRETCH, &value);
2735 static HRESULT WINAPI dwritetextlayout_SetFontSize(IDWriteTextLayout2 *iface, FLOAT size, DWRITE_TEXT_RANGE range)
2737 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2738 struct layout_range_attr_value value;
2740 TRACE("(%p)->(%.2f %s)\n", This, size, debugstr_range(&range));
2742 if (size <= 0.0f)
2743 return E_INVALIDARG;
2745 value.range = range;
2746 value.u.fontsize = size;
2747 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTSIZE, &value);
2750 static HRESULT WINAPI dwritetextlayout_SetUnderline(IDWriteTextLayout2 *iface, BOOL underline, DWRITE_TEXT_RANGE range)
2752 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2753 struct layout_range_attr_value value;
2755 TRACE("(%p)->(%d %s)\n", This, underline, debugstr_range(&range));
2757 value.range = range;
2758 value.u.underline = underline;
2759 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_UNDERLINE, &value);
2762 static HRESULT WINAPI dwritetextlayout_SetStrikethrough(IDWriteTextLayout2 *iface, BOOL strikethrough, DWRITE_TEXT_RANGE range)
2764 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2765 struct layout_range_attr_value value;
2767 TRACE("(%p)->(%d %s)\n", This, strikethrough, debugstr_range(&range));
2769 value.range = range;
2770 value.u.strikethrough = strikethrough;
2771 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRIKETHROUGH, &value);
2774 static HRESULT WINAPI dwritetextlayout_SetDrawingEffect(IDWriteTextLayout2 *iface, IUnknown* effect, DWRITE_TEXT_RANGE range)
2776 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2777 struct layout_range_attr_value value;
2779 TRACE("(%p)->(%p %s)\n", This, effect, debugstr_range(&range));
2781 value.range = range;
2782 value.u.effect = effect;
2783 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_EFFECT, &value);
2786 static HRESULT WINAPI dwritetextlayout_SetInlineObject(IDWriteTextLayout2 *iface, IDWriteInlineObject *object, DWRITE_TEXT_RANGE range)
2788 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2789 struct layout_range_attr_value value;
2791 TRACE("(%p)->(%p %s)\n", This, object, debugstr_range(&range));
2793 value.range = range;
2794 value.u.object = object;
2795 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_INLINE, &value);
2798 static HRESULT WINAPI dwritetextlayout_SetTypography(IDWriteTextLayout2 *iface, IDWriteTypography* typography, DWRITE_TEXT_RANGE range)
2800 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2801 struct layout_range_attr_value value;
2803 TRACE("(%p)->(%p %s)\n", This, typography, debugstr_range(&range));
2805 value.range = range;
2806 value.u.typography = typography;
2807 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_TYPOGRAPHY, &value);
2810 static HRESULT WINAPI dwritetextlayout_SetLocaleName(IDWriteTextLayout2 *iface, WCHAR const* locale, DWRITE_TEXT_RANGE range)
2812 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2813 struct layout_range_attr_value value;
2815 TRACE("(%p)->(%s %s)\n", This, debugstr_w(locale), debugstr_range(&range));
2817 if (!locale || strlenW(locale) > LOCALE_NAME_MAX_LENGTH-1)
2818 return E_INVALIDARG;
2820 value.range = range;
2821 value.u.locale = locale;
2822 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_LOCALE, &value);
2825 static FLOAT WINAPI dwritetextlayout_GetMaxWidth(IDWriteTextLayout2 *iface)
2827 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2828 TRACE("(%p)\n", This);
2829 return This->metrics.layoutWidth;
2832 static FLOAT WINAPI dwritetextlayout_GetMaxHeight(IDWriteTextLayout2 *iface)
2834 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2835 TRACE("(%p)\n", This);
2836 return This->metrics.layoutHeight;
2839 static HRESULT WINAPI dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout2 *iface, UINT32 position,
2840 IDWriteFontCollection** collection, DWRITE_TEXT_RANGE *r)
2842 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2843 struct layout_range *range;
2845 TRACE("(%p)->(%u %p %p)\n", This, position, collection, r);
2847 if (position >= This->len)
2848 return S_OK;
2850 range = get_layout_range_by_pos(This, position);
2851 *collection = range->collection;
2852 if (*collection)
2853 IDWriteFontCollection_AddRef(*collection);
2855 return return_range(&range->h, r);
2858 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout2 *iface,
2859 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
2861 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2862 TRACE("(%p)->(%d %p %p)\n", This, position, length, r);
2863 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, length, r);
2866 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout2 *iface,
2867 UINT32 position, WCHAR *name, UINT32 length, DWRITE_TEXT_RANGE *r)
2869 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2870 TRACE("(%p)->(%u %p %u %p)\n", This, position, name, length, r);
2871 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, name, length, r);
2874 static HRESULT WINAPI dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout2 *iface,
2875 UINT32 position, DWRITE_FONT_WEIGHT *weight, DWRITE_TEXT_RANGE *r)
2877 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2878 struct layout_range *range;
2880 TRACE("(%p)->(%u %p %p)\n", This, position, weight, r);
2882 if (position >= This->len)
2883 return S_OK;
2885 range = get_layout_range_by_pos(This, position);
2886 *weight = range->weight;
2888 return return_range(&range->h, r);
2891 static HRESULT WINAPI dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout2 *iface,
2892 UINT32 position, DWRITE_FONT_STYLE *style, DWRITE_TEXT_RANGE *r)
2894 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2895 struct layout_range *range;
2897 TRACE("(%p)->(%u %p %p)\n", This, position, style, r);
2899 range = get_layout_range_by_pos(This, position);
2900 *style = range->style;
2901 return return_range(&range->h, r);
2904 static HRESULT WINAPI dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout2 *iface,
2905 UINT32 position, DWRITE_FONT_STRETCH *stretch, DWRITE_TEXT_RANGE *r)
2907 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2908 struct layout_range *range;
2910 TRACE("(%p)->(%u %p %p)\n", This, position, stretch, r);
2912 range = get_layout_range_by_pos(This, position);
2913 *stretch = range->stretch;
2914 return return_range(&range->h, r);
2917 static HRESULT WINAPI dwritetextlayout_layout_GetFontSize(IDWriteTextLayout2 *iface,
2918 UINT32 position, FLOAT *size, DWRITE_TEXT_RANGE *r)
2920 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2921 struct layout_range *range;
2923 TRACE("(%p)->(%u %p %p)\n", This, position, size, r);
2925 range = get_layout_range_by_pos(This, position);
2926 *size = range->fontsize;
2927 return return_range(&range->h, r);
2930 static HRESULT WINAPI dwritetextlayout_GetUnderline(IDWriteTextLayout2 *iface,
2931 UINT32 position, BOOL *underline, DWRITE_TEXT_RANGE *r)
2933 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2934 struct layout_range_bool *range;
2936 TRACE("(%p)->(%u %p %p)\n", This, position, underline, r);
2938 range = (struct layout_range_bool*)get_layout_range_header_by_pos(&This->underline_ranges, position);
2939 *underline = range->value;
2941 return return_range(&range->h, r);
2944 static HRESULT WINAPI dwritetextlayout_GetStrikethrough(IDWriteTextLayout2 *iface,
2945 UINT32 position, BOOL *strikethrough, DWRITE_TEXT_RANGE *r)
2947 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2948 struct layout_range_bool *range;
2950 TRACE("(%p)->(%u %p %p)\n", This, position, strikethrough, r);
2952 range = (struct layout_range_bool*)get_layout_range_header_by_pos(&This->strike_ranges, position);
2953 *strikethrough = range->value;
2955 return return_range(&range->h, r);
2958 static HRESULT WINAPI dwritetextlayout_GetDrawingEffect(IDWriteTextLayout2 *iface,
2959 UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r)
2961 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2962 struct layout_range_iface *range;
2964 TRACE("(%p)->(%u %p %p)\n", This, position, effect, r);
2966 range = (struct layout_range_iface*)get_layout_range_header_by_pos(&This->effects, position);
2967 *effect = range->iface;
2968 if (*effect)
2969 IUnknown_AddRef(*effect);
2971 return return_range(&range->h, r);
2974 static HRESULT WINAPI dwritetextlayout_GetInlineObject(IDWriteTextLayout2 *iface,
2975 UINT32 position, IDWriteInlineObject **object, DWRITE_TEXT_RANGE *r)
2977 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2978 struct layout_range *range;
2980 TRACE("(%p)->(%u %p %p)\n", This, position, object, r);
2982 if (position >= This->len)
2983 return S_OK;
2985 range = get_layout_range_by_pos(This, position);
2986 *object = range->object;
2987 if (*object)
2988 IDWriteInlineObject_AddRef(*object);
2990 return return_range(&range->h, r);
2993 static HRESULT WINAPI dwritetextlayout_GetTypography(IDWriteTextLayout2 *iface,
2994 UINT32 position, IDWriteTypography** typography, DWRITE_TEXT_RANGE *r)
2996 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
2997 struct layout_range_iface *range;
2999 TRACE("(%p)->(%u %p %p)\n", This, position, typography, r);
3001 range = (struct layout_range_iface*)get_layout_range_header_by_pos(&This->typographies, position);
3002 *typography = (IDWriteTypography*)range->iface;
3003 if (*typography)
3004 IDWriteTypography_AddRef(*typography);
3006 return return_range(&range->h, r);
3009 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout2 *iface,
3010 UINT32 position, UINT32* length, DWRITE_TEXT_RANGE *r)
3012 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3013 TRACE("(%p)->(%u %p %p)\n", This, position, length, r);
3014 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_LOCALE, position, length, r);
3017 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout2 *iface,
3018 UINT32 position, WCHAR* locale, UINT32 length, DWRITE_TEXT_RANGE *r)
3020 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3021 TRACE("(%p)->(%u %p %u %p)\n", This, position, locale, length, r);
3022 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_LOCALE, position, locale, length, r);
3025 static inline FLOAT renderer_apply_snapping(FLOAT coord, BOOL skiptransform, FLOAT ppdip, FLOAT det,
3026 const DWRITE_MATRIX *m)
3028 FLOAT vec[2], vec2[2];
3030 if (!skiptransform) {
3031 /* apply transform */
3032 vec[0] = 0.0f;
3033 vec[1] = coord * ppdip;
3035 vec2[0] = m->m11 * vec[0] + m->m21 * vec[1] + m->dx;
3036 vec2[1] = m->m12 * vec[0] + m->m22 * vec[1] + m->dy;
3038 /* snap */
3039 vec2[0] = floorf(vec2[0] + 0.5f);
3040 vec2[1] = floorf(vec2[1] + 0.5f);
3042 /* apply inverted transform, we don't care about X component at this point */
3043 vec[1] = (-m->m12 * vec2[0] + m->m11 * vec2[1] - (m->m11 * m->dy - m->m12 * m->dx)) / det;
3044 vec[1] /= ppdip;
3046 else
3047 vec[1] = floorf(coord * ppdip + 0.5f) / ppdip;
3049 return vec[1];
3052 static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface,
3053 void *context, IDWriteTextRenderer* renderer, FLOAT origin_x, FLOAT origin_y)
3055 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3056 BOOL disabled = FALSE, skiptransform = FALSE;
3057 struct layout_effective_inline *inlineobject;
3058 struct layout_effective_run *run;
3059 struct layout_strikethrough *s;
3060 struct layout_underline *u;
3061 FLOAT det = 0.0f, ppdip = 0.0f;
3062 DWRITE_MATRIX m = { 0 };
3063 HRESULT hr;
3065 TRACE("(%p)->(%p %p %.2f %.2f)\n", This, context, renderer, origin_x, origin_y);
3067 hr = layout_compute_effective_runs(This);
3068 if (FAILED(hr))
3069 return hr;
3071 hr = IDWriteTextRenderer_IsPixelSnappingDisabled(renderer, context, &disabled);
3072 if (FAILED(hr))
3073 return hr;
3075 if (!disabled) {
3076 hr = IDWriteTextRenderer_GetPixelsPerDip(renderer, context, &ppdip);
3077 if (FAILED(hr))
3078 return hr;
3080 hr = IDWriteTextRenderer_GetCurrentTransform(renderer, context, &m);
3081 if (FAILED(hr))
3082 return hr;
3084 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
3085 if (ppdip <= 0.0f ||
3086 (m.m11 * m.m22 != 0.0f && (m.m12 != 0.0f || m.m21 != 0.0f)) ||
3087 (m.m12 * m.m21 != 0.0f && (m.m11 != 0.0f || m.m22 != 0.0f)))
3088 disabled = TRUE;
3089 else
3090 skiptransform = should_skip_transform(&m, &det);
3093 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
3094 /* 1. Regular runs */
3095 LIST_FOR_EACH_ENTRY(run, &This->eruns, struct layout_effective_run, entry) {
3096 const struct regular_layout_run *regular = &run->run->u.regular;
3097 UINT32 start_glyph = regular->clustermap[run->start];
3098 DWRITE_GLYPH_RUN_DESCRIPTION descr;
3099 DWRITE_GLYPH_RUN glyph_run;
3101 /* Everything but cluster map will be reused from nominal run, as we only need
3102 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
3103 it can't be reused because it has to start with 0 index for each reported run. */
3104 glyph_run = regular->run;
3105 glyph_run.glyphCount = run->glyphcount;
3107 /* fixup glyph data arrays */
3108 glyph_run.glyphIndices += start_glyph;
3109 glyph_run.glyphAdvances += start_glyph;
3110 glyph_run.glyphOffsets += start_glyph;
3112 /* description */
3113 descr = regular->descr;
3114 descr.stringLength = run->length;
3115 descr.string += run->start;
3116 descr.clusterMap = run->clustermap;
3117 descr.textPosition += run->start;
3119 /* return value is ignored */
3120 IDWriteTextRenderer_DrawGlyphRun(renderer,
3121 context,
3122 run->origin_x + run->align_dx + origin_x,
3123 SNAP_COORD(run->origin_y + origin_y),
3124 This->measuringmode,
3125 &glyph_run,
3126 &descr,
3127 run->effect);
3130 /* 2. Inline objects */
3131 LIST_FOR_EACH_ENTRY(inlineobject, &This->inlineobjects, struct layout_effective_inline, entry) {
3132 IDWriteTextRenderer_DrawInlineObject(renderer,
3133 context,
3134 inlineobject->origin_x + inlineobject->align_dx + origin_x,
3135 SNAP_COORD(inlineobject->origin_y + origin_y),
3136 inlineobject->object,
3137 inlineobject->is_sideways,
3138 inlineobject->is_rtl,
3139 inlineobject->effect);
3142 /* 3. Underlines */
3143 LIST_FOR_EACH_ENTRY(u, &This->underlines, struct layout_underline, entry) {
3144 IDWriteTextRenderer_DrawUnderline(renderer,
3145 context,
3146 u->run->origin_x + run->align_dx + origin_x,
3147 SNAP_COORD(u->run->origin_y + origin_y),
3148 &u->u,
3149 u->run->effect);
3152 /* 4. Strikethrough */
3153 LIST_FOR_EACH_ENTRY(s, &This->strikethrough, struct layout_strikethrough, entry) {
3154 IDWriteTextRenderer_DrawStrikethrough(renderer,
3155 context,
3156 s->run->origin_x + run->align_dx + origin_x,
3157 SNAP_COORD(s->run->origin_y + origin_y),
3158 &s->s,
3159 s->run->effect);
3161 #undef SNAP_COORD
3163 return S_OK;
3166 static HRESULT WINAPI dwritetextlayout_GetLineMetrics(IDWriteTextLayout2 *iface,
3167 DWRITE_LINE_METRICS *metrics, UINT32 max_count, UINT32 *count)
3169 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3170 HRESULT hr;
3172 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
3174 hr = layout_compute_effective_runs(This);
3175 if (FAILED(hr))
3176 return hr;
3178 if (metrics)
3179 memcpy(metrics, This->lines, sizeof(*metrics)*min(max_count, This->metrics.lineCount));
3181 *count = This->metrics.lineCount;
3182 return max_count >= This->metrics.lineCount ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3185 static HRESULT WINAPI dwritetextlayout_GetMetrics(IDWriteTextLayout2 *iface, DWRITE_TEXT_METRICS *metrics)
3187 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3188 DWRITE_TEXT_METRICS1 metrics1;
3189 HRESULT hr;
3191 TRACE("(%p)->(%p)\n", This, metrics);
3193 hr = IDWriteTextLayout2_GetMetrics(iface, &metrics1);
3194 if (hr == S_OK)
3195 memcpy(metrics, &metrics1, sizeof(*metrics));
3197 return hr;
3200 static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout2 *iface, DWRITE_OVERHANG_METRICS *overhangs)
3202 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3203 FIXME("(%p)->(%p): stub\n", This, overhangs);
3204 return E_NOTIMPL;
3207 static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout2 *iface,
3208 DWRITE_CLUSTER_METRICS *metrics, UINT32 max_count, UINT32 *count)
3210 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3211 HRESULT hr;
3213 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
3215 hr = layout_compute(This);
3216 if (FAILED(hr))
3217 return hr;
3219 if (metrics)
3220 memcpy(metrics, This->clustermetrics, sizeof(DWRITE_CLUSTER_METRICS)*min(max_count, This->cluster_count));
3222 *count = This->cluster_count;
3223 return max_count >= This->cluster_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
3226 /* Only to be used with DetermineMinWidth() to find the longest cluster sequence that we don't want to try
3227 too hard to break. */
3228 static inline BOOL is_terminal_cluster(struct dwrite_textlayout *layout, UINT32 index)
3230 if (layout->clustermetrics[index].isWhitespace || layout->clustermetrics[index].isNewline ||
3231 (index == layout->cluster_count - 1))
3232 return TRUE;
3233 /* check next one */
3234 return (index < layout->cluster_count - 1) && layout->clustermetrics[index+1].isWhitespace;
3237 static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout2 *iface, FLOAT* min_width)
3239 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3240 FLOAT width;
3241 HRESULT hr;
3242 UINT32 i;
3244 TRACE("(%p)->(%p)\n", This, min_width);
3246 if (!min_width)
3247 return E_INVALIDARG;
3249 if (!(This->recompute & RECOMPUTE_MINIMAL_WIDTH))
3250 goto width_done;
3252 *min_width = 0.0f;
3253 hr = layout_compute(This);
3254 if (FAILED(hr))
3255 return hr;
3257 for (i = 0; i < This->cluster_count;) {
3258 if (is_terminal_cluster(This, i)) {
3259 width = This->clustermetrics[i].width;
3260 i++;
3262 else {
3263 width = 0.0f;
3264 while (!is_terminal_cluster(This, i)) {
3265 width += This->clustermetrics[i].width;
3266 i++;
3268 /* count last one too */
3269 width += This->clustermetrics[i].width;
3272 if (width > This->minwidth)
3273 This->minwidth = width;
3275 This->recompute &= ~RECOMPUTE_MINIMAL_WIDTH;
3277 width_done:
3278 *min_width = This->minwidth;
3279 return S_OK;
3282 static HRESULT WINAPI dwritetextlayout_HitTestPoint(IDWriteTextLayout2 *iface,
3283 FLOAT pointX, FLOAT pointY, BOOL* is_trailinghit, BOOL* is_inside, DWRITE_HIT_TEST_METRICS *metrics)
3285 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3286 FIXME("(%p)->(%f %f %p %p %p): stub\n", This, pointX, pointY, is_trailinghit, is_inside, metrics);
3287 return E_NOTIMPL;
3290 static HRESULT WINAPI dwritetextlayout_HitTestTextPosition(IDWriteTextLayout2 *iface,
3291 UINT32 textPosition, BOOL is_trailinghit, FLOAT* pointX, FLOAT* pointY, DWRITE_HIT_TEST_METRICS *metrics)
3293 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3294 FIXME("(%p)->(%u %d %p %p %p): stub\n", This, textPosition, is_trailinghit, pointX, pointY, metrics);
3295 return E_NOTIMPL;
3298 static HRESULT WINAPI dwritetextlayout_HitTestTextRange(IDWriteTextLayout2 *iface,
3299 UINT32 textPosition, UINT32 textLength, FLOAT originX, FLOAT originY,
3300 DWRITE_HIT_TEST_METRICS *metrics, UINT32 max_metricscount, UINT32* actual_metricscount)
3302 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3303 FIXME("(%p)->(%u %u %f %f %p %u %p): stub\n", This, textPosition, textLength, originX, originY, metrics,
3304 max_metricscount, actual_metricscount);
3305 return E_NOTIMPL;
3308 static HRESULT WINAPI dwritetextlayout1_SetPairKerning(IDWriteTextLayout2 *iface, BOOL is_pairkerning_enabled,
3309 DWRITE_TEXT_RANGE range)
3311 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3312 struct layout_range_attr_value value;
3314 TRACE("(%p)->(%d %s)\n", This, is_pairkerning_enabled, debugstr_range(&range));
3316 value.range = range;
3317 value.u.pair_kerning = !!is_pairkerning_enabled;
3318 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_PAIR_KERNING, &value);
3321 static HRESULT WINAPI dwritetextlayout1_GetPairKerning(IDWriteTextLayout2 *iface, UINT32 position, BOOL *is_pairkerning_enabled,
3322 DWRITE_TEXT_RANGE *r)
3324 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3325 struct layout_range *range;
3327 TRACE("(%p)->(%u %p %p)\n", This, position, is_pairkerning_enabled, r);
3329 if (position >= This->len)
3330 return S_OK;
3332 range = get_layout_range_by_pos(This, position);
3333 *is_pairkerning_enabled = range->pair_kerning;
3335 return return_range(&range->h, r);
3338 static HRESULT WINAPI dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout2 *iface, FLOAT leading, FLOAT trailing,
3339 FLOAT min_advance, DWRITE_TEXT_RANGE range)
3341 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3342 struct layout_range_attr_value value;
3344 TRACE("(%p)->(%.2f %.2f %.2f %s)\n", This, leading, trailing, min_advance, debugstr_range(&range));
3346 if (min_advance < 0.0f)
3347 return E_INVALIDARG;
3349 value.range = range;
3350 value.u.spacing[0] = leading;
3351 value.u.spacing[1] = trailing;
3352 value.u.spacing[2] = min_advance;
3353 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_SPACING, &value);
3356 static HRESULT WINAPI dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout2 *iface, UINT32 position, FLOAT *leading,
3357 FLOAT *trailing, FLOAT *min_advance, DWRITE_TEXT_RANGE *r)
3359 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3360 struct layout_range_spacing *range;
3362 TRACE("(%p)->(%u %p %p %p %p)\n", This, position, leading, trailing, min_advance, r);
3364 range = (struct layout_range_spacing*)get_layout_range_header_by_pos(&This->spacing, position);
3365 *leading = range->leading;
3366 *trailing = range->trailing;
3367 *min_advance = range->min_advance;
3369 return return_range(&range->h, r);
3372 static HRESULT WINAPI dwritetextlayout2_GetMetrics(IDWriteTextLayout2 *iface, DWRITE_TEXT_METRICS1 *metrics)
3374 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3375 HRESULT hr;
3377 TRACE("(%p)->(%p)\n", This, metrics);
3379 hr = layout_compute_effective_runs(This);
3380 if (FAILED(hr))
3381 return hr;
3383 *metrics = This->metrics;
3384 return S_OK;
3387 static HRESULT WINAPI dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout2 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
3389 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3391 TRACE("(%p)->(%d)\n", This, orientation);
3393 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
3394 return E_INVALIDARG;
3396 This->format.vertical_orientation = orientation;
3397 return S_OK;
3400 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout2 *iface)
3402 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3403 TRACE("(%p)\n", This);
3404 return This->format.vertical_orientation;
3407 static HRESULT WINAPI dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout2 *iface, BOOL lastline_wrapping_enabled)
3409 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3410 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
3411 return IDWriteTextFormat1_SetLastLineWrapping(&This->IDWriteTextFormat1_iface, lastline_wrapping_enabled);
3414 static BOOL WINAPI dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout2 *iface)
3416 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3417 TRACE("(%p)\n", This);
3418 return IDWriteTextFormat1_GetLastLineWrapping(&This->IDWriteTextFormat1_iface);
3421 static HRESULT WINAPI dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout2 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
3423 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3424 TRACE("(%p)->(%d)\n", This, alignment);
3425 return IDWriteTextFormat1_SetOpticalAlignment(&This->IDWriteTextFormat1_iface, alignment);
3428 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout2 *iface)
3430 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3431 TRACE("(%p)\n", This);
3432 return IDWriteTextFormat1_GetOpticalAlignment(&This->IDWriteTextFormat1_iface);
3435 static HRESULT WINAPI dwritetextlayout2_SetFontFallback(IDWriteTextLayout2 *iface, IDWriteFontFallback *fallback)
3437 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3438 TRACE("(%p)->(%p)\n", This, fallback);
3439 return set_fontfallback_for_format(&This->format, fallback);
3442 static HRESULT WINAPI dwritetextlayout2_GetFontFallback(IDWriteTextLayout2 *iface, IDWriteFontFallback **fallback)
3444 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
3445 TRACE("(%p)->(%p)\n", This, fallback);
3446 return get_fontfallback_from_format(&This->format, fallback);
3449 static const IDWriteTextLayout2Vtbl dwritetextlayoutvtbl = {
3450 dwritetextlayout_QueryInterface,
3451 dwritetextlayout_AddRef,
3452 dwritetextlayout_Release,
3453 dwritetextlayout_SetTextAlignment,
3454 dwritetextlayout_SetParagraphAlignment,
3455 dwritetextlayout_SetWordWrapping,
3456 dwritetextlayout_SetReadingDirection,
3457 dwritetextlayout_SetFlowDirection,
3458 dwritetextlayout_SetIncrementalTabStop,
3459 dwritetextlayout_SetTrimming,
3460 dwritetextlayout_SetLineSpacing,
3461 dwritetextlayout_GetTextAlignment,
3462 dwritetextlayout_GetParagraphAlignment,
3463 dwritetextlayout_GetWordWrapping,
3464 dwritetextlayout_GetReadingDirection,
3465 dwritetextlayout_GetFlowDirection,
3466 dwritetextlayout_GetIncrementalTabStop,
3467 dwritetextlayout_GetTrimming,
3468 dwritetextlayout_GetLineSpacing,
3469 dwritetextlayout_GetFontCollection,
3470 dwritetextlayout_GetFontFamilyNameLength,
3471 dwritetextlayout_GetFontFamilyName,
3472 dwritetextlayout_GetFontWeight,
3473 dwritetextlayout_GetFontStyle,
3474 dwritetextlayout_GetFontStretch,
3475 dwritetextlayout_GetFontSize,
3476 dwritetextlayout_GetLocaleNameLength,
3477 dwritetextlayout_GetLocaleName,
3478 dwritetextlayout_SetMaxWidth,
3479 dwritetextlayout_SetMaxHeight,
3480 dwritetextlayout_SetFontCollection,
3481 dwritetextlayout_SetFontFamilyName,
3482 dwritetextlayout_SetFontWeight,
3483 dwritetextlayout_SetFontStyle,
3484 dwritetextlayout_SetFontStretch,
3485 dwritetextlayout_SetFontSize,
3486 dwritetextlayout_SetUnderline,
3487 dwritetextlayout_SetStrikethrough,
3488 dwritetextlayout_SetDrawingEffect,
3489 dwritetextlayout_SetInlineObject,
3490 dwritetextlayout_SetTypography,
3491 dwritetextlayout_SetLocaleName,
3492 dwritetextlayout_GetMaxWidth,
3493 dwritetextlayout_GetMaxHeight,
3494 dwritetextlayout_layout_GetFontCollection,
3495 dwritetextlayout_layout_GetFontFamilyNameLength,
3496 dwritetextlayout_layout_GetFontFamilyName,
3497 dwritetextlayout_layout_GetFontWeight,
3498 dwritetextlayout_layout_GetFontStyle,
3499 dwritetextlayout_layout_GetFontStretch,
3500 dwritetextlayout_layout_GetFontSize,
3501 dwritetextlayout_GetUnderline,
3502 dwritetextlayout_GetStrikethrough,
3503 dwritetextlayout_GetDrawingEffect,
3504 dwritetextlayout_GetInlineObject,
3505 dwritetextlayout_GetTypography,
3506 dwritetextlayout_layout_GetLocaleNameLength,
3507 dwritetextlayout_layout_GetLocaleName,
3508 dwritetextlayout_Draw,
3509 dwritetextlayout_GetLineMetrics,
3510 dwritetextlayout_GetMetrics,
3511 dwritetextlayout_GetOverhangMetrics,
3512 dwritetextlayout_GetClusterMetrics,
3513 dwritetextlayout_DetermineMinWidth,
3514 dwritetextlayout_HitTestPoint,
3515 dwritetextlayout_HitTestTextPosition,
3516 dwritetextlayout_HitTestTextRange,
3517 dwritetextlayout1_SetPairKerning,
3518 dwritetextlayout1_GetPairKerning,
3519 dwritetextlayout1_SetCharacterSpacing,
3520 dwritetextlayout1_GetCharacterSpacing,
3521 dwritetextlayout2_GetMetrics,
3522 dwritetextlayout2_SetVerticalGlyphOrientation,
3523 dwritetextlayout2_GetVerticalGlyphOrientation,
3524 dwritetextlayout2_SetLastLineWrapping,
3525 dwritetextlayout2_GetLastLineWrapping,
3526 dwritetextlayout2_SetOpticalAlignment,
3527 dwritetextlayout2_GetOpticalAlignment,
3528 dwritetextlayout2_SetFontFallback,
3529 dwritetextlayout2_GetFontFallback
3532 static HRESULT WINAPI dwritetextformat1_layout_QueryInterface(IDWriteTextFormat1 *iface, REFIID riid, void **obj)
3534 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3535 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3536 return IDWriteTextLayout2_QueryInterface(&This->IDWriteTextLayout2_iface, riid, obj);
3539 static ULONG WINAPI dwritetextformat1_layout_AddRef(IDWriteTextFormat1 *iface)
3541 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3542 return IDWriteTextLayout2_AddRef(&This->IDWriteTextLayout2_iface);
3545 static ULONG WINAPI dwritetextformat1_layout_Release(IDWriteTextFormat1 *iface)
3547 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3548 return IDWriteTextLayout2_Release(&This->IDWriteTextLayout2_iface);
3551 static HRESULT WINAPI dwritetextformat1_layout_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
3553 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3554 BOOL changed;
3555 HRESULT hr;
3557 TRACE("(%p)->(%d)\n", This, alignment);
3559 hr = format_set_textalignment(&This->format, alignment, &changed);
3560 if (FAILED(hr))
3561 return hr;
3563 /* if layout is not ready there's nothing to align */
3564 if (changed && !(This->recompute & RECOMPUTE_EFFECTIVE_RUNS))
3565 layout_apply_text_alignment(This);
3567 return S_OK;
3570 static HRESULT WINAPI dwritetextformat1_layout_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
3572 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3573 BOOL changed;
3574 HRESULT hr;
3576 TRACE("(%p)->(%d)\n", This, alignment);
3578 hr = format_set_paralignment(&This->format, alignment, &changed);
3579 if (FAILED(hr))
3580 return hr;
3582 /* if layout is not ready there's nothing to align */
3583 if (changed && !(This->recompute & RECOMPUTE_EFFECTIVE_RUNS))
3584 layout_apply_par_alignment(This);
3586 return S_OK;
3589 static HRESULT WINAPI dwritetextformat1_layout_SetWordWrapping(IDWriteTextFormat1 *iface, DWRITE_WORD_WRAPPING wrapping)
3591 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3592 BOOL changed;
3593 HRESULT hr;
3595 TRACE("(%p)->(%d)\n", This, wrapping);
3597 hr = format_set_wordwrapping(&This->format, wrapping, &changed);
3598 if (FAILED(hr))
3599 return hr;
3601 if (changed)
3602 This->recompute |= RECOMPUTE_EFFECTIVE_RUNS;
3604 return S_OK;
3607 static HRESULT WINAPI dwritetextformat1_layout_SetReadingDirection(IDWriteTextFormat1 *iface, DWRITE_READING_DIRECTION direction)
3609 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3610 BOOL changed;
3611 HRESULT hr;
3613 TRACE("(%p)->(%d)\n", This, direction);
3615 hr = format_set_readingdirection(&This->format, direction, &changed);
3616 if (FAILED(hr))
3617 return hr;
3619 if (changed)
3620 This->recompute = RECOMPUTE_EVERYTHING;
3622 return S_OK;
3625 static HRESULT WINAPI dwritetextformat1_layout_SetFlowDirection(IDWriteTextFormat1 *iface, DWRITE_FLOW_DIRECTION direction)
3627 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3628 FIXME("(%p)->(%d): stub\n", This, direction);
3629 return E_NOTIMPL;
3632 static HRESULT WINAPI dwritetextformat1_layout_SetIncrementalTabStop(IDWriteTextFormat1 *iface, FLOAT tabstop)
3634 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3635 FIXME("(%p)->(%f): stub\n", This, tabstop);
3636 return E_NOTIMPL;
3639 static HRESULT WINAPI dwritetextformat1_layout_SetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING const *trimming,
3640 IDWriteInlineObject *trimming_sign)
3642 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3643 FIXME("(%p)->(%p %p): stub\n", This, trimming, trimming_sign);
3644 return E_NOTIMPL;
3647 static HRESULT WINAPI dwritetextformat1_layout_SetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD spacing,
3648 FLOAT line_spacing, FLOAT baseline)
3650 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3651 FIXME("(%p)->(%d %f %f): stub\n", This, spacing, line_spacing, baseline);
3652 return E_NOTIMPL;
3655 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat1_layout_GetTextAlignment(IDWriteTextFormat1 *iface)
3657 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3658 TRACE("(%p)\n", This);
3659 return This->format.textalignment;
3662 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat1_layout_GetParagraphAlignment(IDWriteTextFormat1 *iface)
3664 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3665 TRACE("(%p)\n", This);
3666 return This->format.paralign;
3669 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat1_layout_GetWordWrapping(IDWriteTextFormat1 *iface)
3671 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3672 TRACE("(%p)\n", This);
3673 return This->format.wrapping;
3676 static DWRITE_READING_DIRECTION WINAPI dwritetextformat1_layout_GetReadingDirection(IDWriteTextFormat1 *iface)
3678 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3679 TRACE("(%p)\n", This);
3680 return This->format.readingdir;
3683 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat1_layout_GetFlowDirection(IDWriteTextFormat1 *iface)
3685 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3686 TRACE("(%p)\n", This);
3687 return This->format.flow;
3690 static FLOAT WINAPI dwritetextformat1_layout_GetIncrementalTabStop(IDWriteTextFormat1 *iface)
3692 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3693 FIXME("(%p): stub\n", This);
3694 return 0.0f;
3697 static HRESULT WINAPI dwritetextformat1_layout_GetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING *options,
3698 IDWriteInlineObject **trimming_sign)
3700 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3702 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
3704 *options = This->format.trimming;
3705 *trimming_sign = This->format.trimmingsign;
3706 if (*trimming_sign)
3707 IDWriteInlineObject_AddRef(*trimming_sign);
3708 return S_OK;
3711 static HRESULT WINAPI dwritetextformat1_layout_GetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD *method,
3712 FLOAT *spacing, FLOAT *baseline)
3714 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3716 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
3718 *method = This->format.spacingmethod;
3719 *spacing = This->format.spacing;
3720 *baseline = This->format.baseline;
3721 return S_OK;
3724 static HRESULT WINAPI dwritetextformat1_layout_GetFontCollection(IDWriteTextFormat1 *iface, IDWriteFontCollection **collection)
3726 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3728 TRACE("(%p)->(%p)\n", This, collection);
3730 *collection = This->format.collection;
3731 if (*collection)
3732 IDWriteFontCollection_AddRef(*collection);
3733 return S_OK;
3736 static UINT32 WINAPI dwritetextformat1_layout_GetFontFamilyNameLength(IDWriteTextFormat1 *iface)
3738 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3739 TRACE("(%p)\n", This);
3740 return This->format.family_len;
3743 static HRESULT WINAPI dwritetextformat1_layout_GetFontFamilyName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
3745 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3747 TRACE("(%p)->(%p %u)\n", This, name, size);
3749 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
3750 strcpyW(name, This->format.family_name);
3751 return S_OK;
3754 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat1_layout_GetFontWeight(IDWriteTextFormat1 *iface)
3756 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3757 TRACE("(%p)\n", This);
3758 return This->format.weight;
3761 static DWRITE_FONT_STYLE WINAPI dwritetextformat1_layout_GetFontStyle(IDWriteTextFormat1 *iface)
3763 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3764 TRACE("(%p)\n", This);
3765 return This->format.style;
3768 static DWRITE_FONT_STRETCH WINAPI dwritetextformat1_layout_GetFontStretch(IDWriteTextFormat1 *iface)
3770 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3771 TRACE("(%p)\n", This);
3772 return This->format.stretch;
3775 static FLOAT WINAPI dwritetextformat1_layout_GetFontSize(IDWriteTextFormat1 *iface)
3777 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3778 TRACE("(%p)\n", This);
3779 return This->format.fontsize;
3782 static UINT32 WINAPI dwritetextformat1_layout_GetLocaleNameLength(IDWriteTextFormat1 *iface)
3784 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3785 TRACE("(%p)\n", This);
3786 return This->format.locale_len;
3789 static HRESULT WINAPI dwritetextformat1_layout_GetLocaleName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
3791 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3793 TRACE("(%p)->(%p %u)\n", This, name, size);
3795 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
3796 strcpyW(name, This->format.locale);
3797 return S_OK;
3800 static HRESULT WINAPI dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat1 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
3802 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3803 FIXME("(%p)->(%d): stub\n", This, orientation);
3804 return E_NOTIMPL;
3807 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat1 *iface)
3809 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3810 FIXME("(%p): stub\n", This);
3811 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
3814 static HRESULT WINAPI dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat1 *iface, BOOL lastline_wrapping_enabled)
3816 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3818 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
3820 This->format.last_line_wrapping = !!lastline_wrapping_enabled;
3821 return S_OK;
3824 static BOOL WINAPI dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat1 *iface)
3826 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3827 TRACE("(%p)\n", This);
3828 return This->format.last_line_wrapping;
3831 static HRESULT WINAPI dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat1 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
3833 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3834 TRACE("(%p)->(%d)\n", This, alignment);
3835 return format_set_optical_alignment(&This->format, alignment);
3838 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat1 *iface)
3840 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3841 TRACE("(%p)\n", This);
3842 return This->format.optical_alignment;
3845 static HRESULT WINAPI dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback *fallback)
3847 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3848 TRACE("(%p)->(%p)\n", This, fallback);
3849 return IDWriteTextLayout2_SetFontFallback(&This->IDWriteTextLayout2_iface, fallback);
3852 static HRESULT WINAPI dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback **fallback)
3854 struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
3855 TRACE("(%p)->(%p)\n", This, fallback);
3856 return IDWriteTextLayout2_GetFontFallback(&This->IDWriteTextLayout2_iface, fallback);
3859 static const IDWriteTextFormat1Vtbl dwritetextformat1_layout_vtbl = {
3860 dwritetextformat1_layout_QueryInterface,
3861 dwritetextformat1_layout_AddRef,
3862 dwritetextformat1_layout_Release,
3863 dwritetextformat1_layout_SetTextAlignment,
3864 dwritetextformat1_layout_SetParagraphAlignment,
3865 dwritetextformat1_layout_SetWordWrapping,
3866 dwritetextformat1_layout_SetReadingDirection,
3867 dwritetextformat1_layout_SetFlowDirection,
3868 dwritetextformat1_layout_SetIncrementalTabStop,
3869 dwritetextformat1_layout_SetTrimming,
3870 dwritetextformat1_layout_SetLineSpacing,
3871 dwritetextformat1_layout_GetTextAlignment,
3872 dwritetextformat1_layout_GetParagraphAlignment,
3873 dwritetextformat1_layout_GetWordWrapping,
3874 dwritetextformat1_layout_GetReadingDirection,
3875 dwritetextformat1_layout_GetFlowDirection,
3876 dwritetextformat1_layout_GetIncrementalTabStop,
3877 dwritetextformat1_layout_GetTrimming,
3878 dwritetextformat1_layout_GetLineSpacing,
3879 dwritetextformat1_layout_GetFontCollection,
3880 dwritetextformat1_layout_GetFontFamilyNameLength,
3881 dwritetextformat1_layout_GetFontFamilyName,
3882 dwritetextformat1_layout_GetFontWeight,
3883 dwritetextformat1_layout_GetFontStyle,
3884 dwritetextformat1_layout_GetFontStretch,
3885 dwritetextformat1_layout_GetFontSize,
3886 dwritetextformat1_layout_GetLocaleNameLength,
3887 dwritetextformat1_layout_GetLocaleName,
3888 dwritetextformat1_layout_SetVerticalGlyphOrientation,
3889 dwritetextformat1_layout_GetVerticalGlyphOrientation,
3890 dwritetextformat1_layout_SetLastLineWrapping,
3891 dwritetextformat1_layout_GetLastLineWrapping,
3892 dwritetextformat1_layout_SetOpticalAlignment,
3893 dwritetextformat1_layout_GetOpticalAlignment,
3894 dwritetextformat1_layout_SetFontFallback,
3895 dwritetextformat1_layout_GetFontFallback
3898 static HRESULT WINAPI dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink *iface,
3899 REFIID riid, void **obj)
3901 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) || IsEqualIID(riid, &IID_IUnknown)) {
3902 *obj = iface;
3903 IDWriteTextAnalysisSink_AddRef(iface);
3904 return S_OK;
3907 *obj = NULL;
3908 return E_NOINTERFACE;
3911 static ULONG WINAPI dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink *iface)
3913 return 2;
3916 static ULONG WINAPI dwritetextlayout_sink_Release(IDWriteTextAnalysisSink *iface)
3918 return 1;
3921 static HRESULT WINAPI dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink *iface,
3922 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
3924 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
3925 struct layout_run *run;
3927 TRACE("%u %u script=%d\n", position, length, sa->script);
3929 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
3930 if (!run)
3931 return E_OUTOFMEMORY;
3933 run->u.regular.descr.string = &layout->str[position];
3934 run->u.regular.descr.stringLength = length;
3935 run->u.regular.descr.textPosition = position;
3936 run->u.regular.sa = *sa;
3937 list_add_tail(&layout->runs, &run->entry);
3938 return S_OK;
3941 static HRESULT WINAPI dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink *iface,
3942 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
3944 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
3946 if (position + length > layout->len)
3947 return E_FAIL;
3949 memcpy(&layout->nominal_breakpoints[position], breakpoints, length*sizeof(DWRITE_LINE_BREAKPOINT));
3950 return S_OK;
3953 static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink *iface, UINT32 position,
3954 UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
3956 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
3957 struct layout_run *cur_run;
3959 TRACE("%u %u %u %u\n", position, length, explicitLevel, resolvedLevel);
3961 LIST_FOR_EACH_ENTRY(cur_run, &layout->runs, struct layout_run, entry) {
3962 struct regular_layout_run *cur = &cur_run->u.regular;
3963 struct layout_run *run;
3965 if (cur_run->kind == LAYOUT_RUN_INLINE)
3966 continue;
3968 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
3969 if (position < cur->descr.textPosition || position >= cur->descr.textPosition + cur->descr.stringLength)
3970 continue;
3972 /* full hit - just set run level */
3973 if (cur->descr.textPosition == position && cur->descr.stringLength == length) {
3974 cur->run.bidiLevel = resolvedLevel;
3975 break;
3978 /* current run is fully covered, move to next one */
3979 if (cur->descr.textPosition == position && cur->descr.stringLength < length) {
3980 cur->run.bidiLevel = resolvedLevel;
3981 position += cur->descr.stringLength;
3982 length -= cur->descr.stringLength;
3983 continue;
3986 /* all fully covered runs are processed at this point, reuse existing run for remaining
3987 reported bidi range and add another run for the rest of original one */
3989 run = alloc_layout_run(LAYOUT_RUN_REGULAR);
3990 if (!run)
3991 return E_OUTOFMEMORY;
3993 *run = *cur_run;
3994 run->u.regular.descr.textPosition = position + length;
3995 run->u.regular.descr.stringLength = cur->descr.stringLength - length;
3996 run->u.regular.descr.string = &layout->str[position + length];
3998 /* reduce existing run */
3999 cur->run.bidiLevel = resolvedLevel;
4000 cur->descr.stringLength = length;
4002 list_add_after(&cur_run->entry, &run->entry);
4003 break;
4006 return S_OK;
4009 static HRESULT WINAPI dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink *iface,
4010 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
4012 return E_NOTIMPL;
4015 static const IDWriteTextAnalysisSinkVtbl dwritetextlayoutsinkvtbl = {
4016 dwritetextlayout_sink_QueryInterface,
4017 dwritetextlayout_sink_AddRef,
4018 dwritetextlayout_sink_Release,
4019 dwritetextlayout_sink_SetScriptAnalysis,
4020 dwritetextlayout_sink_SetLineBreakpoints,
4021 dwritetextlayout_sink_SetBidiLevel,
4022 dwritetextlayout_sink_SetNumberSubstitution
4025 static HRESULT WINAPI dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource *iface,
4026 REFIID riid, void **obj)
4028 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) ||
4029 IsEqualIID(riid, &IID_IUnknown))
4031 *obj = iface;
4032 IDWriteTextAnalysisSource_AddRef(iface);
4033 return S_OK;
4036 *obj = NULL;
4037 return E_NOINTERFACE;
4040 static ULONG WINAPI dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource *iface)
4042 return 2;
4045 static ULONG WINAPI dwritetextlayout_source_Release(IDWriteTextAnalysisSource *iface)
4047 return 1;
4050 static HRESULT WINAPI dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource *iface,
4051 UINT32 position, WCHAR const** text, UINT32* text_len)
4053 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource(iface);
4055 TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
4057 if (position < layout->len) {
4058 *text = &layout->str[position];
4059 *text_len = layout->len - position;
4061 else {
4062 *text = NULL;
4063 *text_len = 0;
4066 return S_OK;
4069 static HRESULT WINAPI dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource *iface,
4070 UINT32 position, WCHAR const** text, UINT32* text_len)
4072 FIXME("%u %p %p: stub\n", position, text, text_len);
4073 return E_NOTIMPL;
4076 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource *iface)
4078 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource(iface);
4079 return IDWriteTextLayout2_GetReadingDirection(&layout->IDWriteTextLayout2_iface);
4082 static HRESULT WINAPI dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource *iface,
4083 UINT32 position, UINT32* text_len, WCHAR const** locale)
4085 FIXME("%u %p %p: stub\n", position, text_len, locale);
4086 return E_NOTIMPL;
4089 static HRESULT WINAPI dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource *iface,
4090 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
4092 FIXME("%u %p %p: stub\n", position, text_len, substitution);
4093 return E_NOTIMPL;
4096 static const IDWriteTextAnalysisSourceVtbl dwritetextlayoutsourcevtbl = {
4097 dwritetextlayout_source_QueryInterface,
4098 dwritetextlayout_source_AddRef,
4099 dwritetextlayout_source_Release,
4100 dwritetextlayout_source_GetTextAtPosition,
4101 dwritetextlayout_source_GetTextBeforePosition,
4102 dwritetextlayout_source_GetParagraphReadingDirection,
4103 dwritetextlayout_source_GetLocaleName,
4104 dwritetextlayout_source_GetNumberSubstitution
4107 static HRESULT layout_format_from_textformat(struct dwrite_textlayout *layout, IDWriteTextFormat *format)
4109 struct dwrite_textformat *textformat;
4110 IDWriteTextFormat1 *format1;
4111 UINT32 len;
4112 HRESULT hr;
4114 if ((textformat = unsafe_impl_from_IDWriteTextFormat(format))) {
4115 layout->format = textformat->format;
4117 layout->format.locale = heap_strdupW(textformat->format.locale);
4118 layout->format.family_name = heap_strdupW(textformat->format.family_name);
4119 if (!layout->format.locale || !layout->format.family_name)
4121 heap_free(layout->format.locale);
4122 heap_free(layout->format.family_name);
4123 return E_OUTOFMEMORY;
4126 if (layout->format.trimmingsign)
4127 IDWriteInlineObject_AddRef(layout->format.trimmingsign);
4128 if (layout->format.collection)
4129 IDWriteFontCollection_AddRef(layout->format.collection);
4130 if (layout->format.fallback)
4131 IDWriteFontFallback_AddRef(layout->format.fallback);
4133 return S_OK;
4136 layout->format.weight = IDWriteTextFormat_GetFontWeight(format);
4137 layout->format.style = IDWriteTextFormat_GetFontStyle(format);
4138 layout->format.stretch = IDWriteTextFormat_GetFontStretch(format);
4139 layout->format.fontsize= IDWriteTextFormat_GetFontSize(format);
4140 layout->format.textalignment = IDWriteTextFormat_GetTextAlignment(format);
4141 layout->format.paralign = IDWriteTextFormat_GetParagraphAlignment(format);
4142 layout->format.wrapping = IDWriteTextFormat_GetWordWrapping(format);
4143 layout->format.readingdir = IDWriteTextFormat_GetReadingDirection(format);
4144 layout->format.flow = IDWriteTextFormat_GetFlowDirection(format);
4145 layout->format.fallback = NULL;
4146 hr = IDWriteTextFormat_GetLineSpacing(format, &layout->format.spacingmethod,
4147 &layout->format.spacing, &layout->format.baseline);
4148 if (FAILED(hr))
4149 return hr;
4151 hr = IDWriteTextFormat_GetTrimming(format, &layout->format.trimming, &layout->format.trimmingsign);
4152 if (FAILED(hr))
4153 return hr;
4155 /* locale name and length */
4156 len = IDWriteTextFormat_GetLocaleNameLength(format);
4157 layout->format.locale = heap_alloc((len+1)*sizeof(WCHAR));
4158 if (!layout->format.locale)
4159 return E_OUTOFMEMORY;
4161 hr = IDWriteTextFormat_GetLocaleName(format, layout->format.locale, len+1);
4162 if (FAILED(hr))
4163 return hr;
4164 layout->format.locale_len = len;
4166 /* font family name and length */
4167 len = IDWriteTextFormat_GetFontFamilyNameLength(format);
4168 layout->format.family_name = heap_alloc((len+1)*sizeof(WCHAR));
4169 if (!layout->format.family_name)
4170 return E_OUTOFMEMORY;
4172 hr = IDWriteTextFormat_GetFontFamilyName(format, layout->format.family_name, len+1);
4173 if (FAILED(hr))
4174 return hr;
4175 layout->format.family_len = len;
4177 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
4178 if (hr == S_OK) {
4179 layout->format.vertical_orientation = IDWriteTextFormat1_GetVerticalGlyphOrientation(format1);
4180 layout->format.optical_alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
4181 IDWriteTextFormat1_GetFontFallback(format1, &layout->format.fallback);
4182 IDWriteTextFormat1_Release(format1);
4184 else {
4185 layout->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
4186 layout->format.optical_alignment = DWRITE_OPTICAL_ALIGNMENT_NONE;
4189 return IDWriteTextFormat_GetFontCollection(format, &layout->format.collection);
4192 static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, struct dwrite_textlayout *layout)
4194 struct layout_range_header *range, *strike, *underline, *effect, *spacing, *typography;
4195 static const DWRITE_TEXT_RANGE r = { 0, ~0u };
4196 HRESULT hr;
4198 layout->IDWriteTextLayout2_iface.lpVtbl = &dwritetextlayoutvtbl;
4199 layout->IDWriteTextFormat1_iface.lpVtbl = &dwritetextformat1_layout_vtbl;
4200 layout->IDWriteTextAnalysisSink_iface.lpVtbl = &dwritetextlayoutsinkvtbl;
4201 layout->IDWriteTextAnalysisSource_iface.lpVtbl = &dwritetextlayoutsourcevtbl;
4202 layout->ref = 1;
4203 layout->len = len;
4204 layout->recompute = RECOMPUTE_EVERYTHING;
4205 layout->nominal_breakpoints = NULL;
4206 layout->actual_breakpoints = NULL;
4207 layout->cluster_count = 0;
4208 layout->clustermetrics = NULL;
4209 layout->clusters = NULL;
4210 layout->lines = NULL;
4211 layout->line_alloc = 0;
4212 layout->minwidth = 0.0f;
4213 list_init(&layout->eruns);
4214 list_init(&layout->inlineobjects);
4215 list_init(&layout->underlines);
4216 list_init(&layout->strikethrough);
4217 list_init(&layout->runs);
4218 list_init(&layout->ranges);
4219 list_init(&layout->strike_ranges);
4220 list_init(&layout->underline_ranges);
4221 list_init(&layout->effects);
4222 list_init(&layout->spacing);
4223 list_init(&layout->typographies);
4224 memset(&layout->format, 0, sizeof(layout->format));
4225 memset(&layout->metrics, 0, sizeof(layout->metrics));
4226 layout->metrics.layoutWidth = maxwidth;
4227 layout->metrics.layoutHeight = maxheight;
4228 layout->measuringmode = DWRITE_MEASURING_MODE_NATURAL;
4230 layout->ppdip = 0.0f;
4231 memset(&layout->transform, 0, sizeof(layout->transform));
4233 layout->str = heap_strdupnW(str, len);
4234 if (len && !layout->str) {
4235 hr = E_OUTOFMEMORY;
4236 goto fail;
4239 hr = layout_format_from_textformat(layout, format);
4240 if (FAILED(hr))
4241 goto fail;
4243 range = alloc_layout_range(layout, &r, LAYOUT_RANGE_REGULAR);
4244 strike = alloc_layout_range(layout, &r, LAYOUT_RANGE_STRIKETHROUGH);
4245 underline = alloc_layout_range(layout, &r, LAYOUT_RANGE_UNDERLINE);
4246 effect = alloc_layout_range(layout, &r, LAYOUT_RANGE_EFFECT);
4247 spacing = alloc_layout_range(layout, &r, LAYOUT_RANGE_SPACING);
4248 typography = alloc_layout_range(layout, &r, LAYOUT_RANGE_TYPOGRAPHY);
4249 if (!range || !strike || !effect || !spacing || !typography || !underline) {
4250 free_layout_range(range);
4251 free_layout_range(strike);
4252 free_layout_range(underline);
4253 free_layout_range(effect);
4254 free_layout_range(spacing);
4255 free_layout_range(typography);
4256 hr = E_OUTOFMEMORY;
4257 goto fail;
4260 list_add_head(&layout->ranges, &range->entry);
4261 list_add_head(&layout->strike_ranges, &strike->entry);
4262 list_add_head(&layout->underline_ranges, &underline->entry);
4263 list_add_head(&layout->effects, &effect->entry);
4264 list_add_head(&layout->spacing, &spacing->entry);
4265 list_add_head(&layout->typographies, &typography->entry);
4266 return S_OK;
4268 fail:
4269 IDWriteTextLayout2_Release(&layout->IDWriteTextLayout2_iface);
4270 return hr;
4273 HRESULT create_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, IDWriteTextLayout **ret)
4275 struct dwrite_textlayout *layout;
4276 HRESULT hr;
4278 *ret = NULL;
4280 layout = heap_alloc(sizeof(struct dwrite_textlayout));
4281 if (!layout) return E_OUTOFMEMORY;
4283 hr = init_textlayout(str, len, format, maxwidth, maxheight, layout);
4284 if (hr == S_OK)
4285 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout2_iface;
4287 return hr;
4290 HRESULT create_gdicompat_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight,
4291 FLOAT ppdip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural, IDWriteTextLayout **ret)
4293 struct dwrite_textlayout *layout;
4294 HRESULT hr;
4296 *ret = NULL;
4298 layout = heap_alloc(sizeof(struct dwrite_textlayout));
4299 if (!layout) return E_OUTOFMEMORY;
4301 hr = init_textlayout(str, len, format, maxwidth, maxheight, layout);
4302 if (hr == S_OK) {
4303 layout->measuringmode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
4305 /* set gdi-specific properties */
4306 layout->ppdip = ppdip;
4307 layout->transform = transform ? *transform : identity;
4309 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout2_iface;
4312 return hr;
4315 static HRESULT WINAPI dwritetrimmingsign_QueryInterface(IDWriteInlineObject *iface, REFIID riid, void **obj)
4317 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4319 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4321 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteInlineObject)) {
4322 *obj = iface;
4323 IDWriteInlineObject_AddRef(iface);
4324 return S_OK;
4327 *obj = NULL;
4328 return E_NOINTERFACE;
4331 static ULONG WINAPI dwritetrimmingsign_AddRef(IDWriteInlineObject *iface)
4333 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4334 ULONG ref = InterlockedIncrement(&This->ref);
4335 TRACE("(%p)->(%d)\n", This, ref);
4336 return ref;
4339 static ULONG WINAPI dwritetrimmingsign_Release(IDWriteInlineObject *iface)
4341 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4342 ULONG ref = InterlockedDecrement(&This->ref);
4344 TRACE("(%p)->(%d)\n", This, ref);
4346 if (!ref) {
4347 IDWriteTextLayout_Release(This->layout);
4348 heap_free(This);
4351 return ref;
4354 static HRESULT WINAPI dwritetrimmingsign_Draw(IDWriteInlineObject *iface, void *context, IDWriteTextRenderer *renderer,
4355 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *effect)
4357 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4358 DWRITE_TEXT_RANGE range = { 0, ~0u };
4360 TRACE("(%p)->(%p %p %.2f %.2f %d %d %p)\n", This, context, renderer, originX, originY, is_sideways, is_rtl, effect);
4362 IDWriteTextLayout_SetDrawingEffect(This->layout, effect, range);
4363 return IDWriteTextLayout_Draw(This->layout, context, renderer, originX, originY);
4366 static HRESULT WINAPI dwritetrimmingsign_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *ret)
4368 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4369 DWRITE_TEXT_METRICS metrics;
4370 HRESULT hr;
4372 TRACE("(%p)->(%p)\n", This, ret);
4374 hr = IDWriteTextLayout_GetMetrics(This->layout, &metrics);
4375 if (FAILED(hr)) {
4376 memset(ret, 0, sizeof(*ret));
4377 return hr;
4380 ret->width = metrics.width;
4381 ret->height = 0.0f;
4382 ret->baseline = 0.0f;
4383 ret->supportsSideways = FALSE;
4384 return S_OK;
4387 static HRESULT WINAPI dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
4389 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4390 FIXME("(%p)->(%p): stub\n", This, overhangs);
4391 return E_NOTIMPL;
4394 static HRESULT WINAPI dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
4395 DWRITE_BREAK_CONDITION *after)
4397 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
4399 TRACE("(%p)->(%p %p)\n", This, before, after);
4401 *before = *after = DWRITE_BREAK_CONDITION_NEUTRAL;
4402 return S_OK;
4405 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl = {
4406 dwritetrimmingsign_QueryInterface,
4407 dwritetrimmingsign_AddRef,
4408 dwritetrimmingsign_Release,
4409 dwritetrimmingsign_Draw,
4410 dwritetrimmingsign_GetMetrics,
4411 dwritetrimmingsign_GetOverhangMetrics,
4412 dwritetrimmingsign_GetBreakConditions
4415 static inline BOOL is_reading_direction_horz(DWRITE_READING_DIRECTION direction)
4417 return (direction == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT) ||
4418 (direction == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
4421 static inline BOOL is_reading_direction_vert(DWRITE_READING_DIRECTION direction)
4423 return (direction == DWRITE_READING_DIRECTION_TOP_TO_BOTTOM) ||
4424 (direction == DWRITE_READING_DIRECTION_BOTTOM_TO_TOP);
4427 static inline BOOL is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction)
4429 return (direction == DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT) ||
4430 (direction == DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT);
4433 static inline BOOL is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction)
4435 return (direction == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM) ||
4436 (direction == DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP);
4439 HRESULT create_trimmingsign(IDWriteFactory2 *factory, IDWriteTextFormat *format, IDWriteInlineObject **sign)
4441 static const WCHAR ellipsisW = 0x2026;
4442 struct dwrite_trimmingsign *This;
4443 DWRITE_READING_DIRECTION reading;
4444 DWRITE_FLOW_DIRECTION flow;
4445 HRESULT hr;
4447 *sign = NULL;
4449 /* Validate reading/flow direction here, layout creation won't complain about
4450 invalid combinations. */
4451 reading = IDWriteTextFormat_GetReadingDirection(format);
4452 flow = IDWriteTextFormat_GetFlowDirection(format);
4454 if ((is_reading_direction_horz(reading) && is_flow_direction_horz(flow)) ||
4455 (is_reading_direction_vert(reading) && is_flow_direction_vert(flow)))
4456 return DWRITE_E_FLOWDIRECTIONCONFLICTS;
4458 This = heap_alloc(sizeof(*This));
4459 if (!This)
4460 return E_OUTOFMEMORY;
4462 This->IDWriteInlineObject_iface.lpVtbl = &dwritetrimmingsignvtbl;
4463 This->ref = 1;
4465 hr = IDWriteFactory2_CreateTextLayout(factory, &ellipsisW, 1, format, 0.0f, 0.0f, &This->layout);
4466 if (FAILED(hr)) {
4467 heap_free(This);
4468 return hr;
4471 IDWriteTextLayout_SetWordWrapping(This->layout, DWRITE_WORD_WRAPPING_NO_WRAP);
4472 *sign = &This->IDWriteInlineObject_iface;
4474 return S_OK;
4477 static HRESULT WINAPI dwritetextformat_QueryInterface(IDWriteTextFormat1 *iface, REFIID riid, void **obj)
4479 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4481 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4483 if (IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
4484 IsEqualIID(riid, &IID_IDWriteTextFormat) ||
4485 IsEqualIID(riid, &IID_IUnknown))
4487 *obj = iface;
4488 IDWriteTextFormat1_AddRef(iface);
4489 return S_OK;
4492 *obj = NULL;
4494 return E_NOINTERFACE;
4497 static ULONG WINAPI dwritetextformat_AddRef(IDWriteTextFormat1 *iface)
4499 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4500 ULONG ref = InterlockedIncrement(&This->ref);
4501 TRACE("(%p)->(%d)\n", This, ref);
4502 return ref;
4505 static ULONG WINAPI dwritetextformat_Release(IDWriteTextFormat1 *iface)
4507 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4508 ULONG ref = InterlockedDecrement(&This->ref);
4510 TRACE("(%p)->(%d)\n", This, ref);
4512 if (!ref)
4514 release_format_data(&This->format);
4515 heap_free(This);
4518 return ref;
4521 static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
4523 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4524 TRACE("(%p)->(%d)\n", This, alignment);
4525 return format_set_textalignment(&This->format, alignment, NULL);
4528 static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
4530 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4531 TRACE("(%p)->(%d)\n", This, alignment);
4532 return format_set_paralignment(&This->format, alignment, NULL);
4535 static HRESULT WINAPI dwritetextformat_SetWordWrapping(IDWriteTextFormat1 *iface, DWRITE_WORD_WRAPPING wrapping)
4537 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4538 TRACE("(%p)->(%d)\n", This, wrapping);
4539 return format_set_wordwrapping(&This->format, wrapping, NULL);
4542 static HRESULT WINAPI dwritetextformat_SetReadingDirection(IDWriteTextFormat1 *iface, DWRITE_READING_DIRECTION direction)
4544 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4545 TRACE("(%p)->(%d)\n", This, direction);
4546 return format_set_readingdirection(&This->format, direction, NULL);
4549 static HRESULT WINAPI dwritetextformat_SetFlowDirection(IDWriteTextFormat1 *iface, DWRITE_FLOW_DIRECTION direction)
4551 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4553 TRACE("(%p)->(%d)\n", This, direction);
4555 if ((UINT32)direction > DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT)
4556 return E_INVALIDARG;
4558 This->format.flow = direction;
4559 return S_OK;
4562 static HRESULT WINAPI dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat1 *iface, FLOAT tabstop)
4564 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4565 FIXME("(%p)->(%f): stub\n", This, tabstop);
4566 return E_NOTIMPL;
4569 static HRESULT WINAPI dwritetextformat_SetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING const *trimming,
4570 IDWriteInlineObject *trimming_sign)
4572 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4573 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
4575 This->format.trimming = *trimming;
4576 if (This->format.trimmingsign)
4577 IDWriteInlineObject_Release(This->format.trimmingsign);
4578 This->format.trimmingsign = trimming_sign;
4579 if (This->format.trimmingsign)
4580 IDWriteInlineObject_AddRef(This->format.trimmingsign);
4581 return S_OK;
4584 static HRESULT WINAPI dwritetextformat_SetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD method,
4585 FLOAT spacing, FLOAT baseline)
4587 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4589 TRACE("(%p)->(%d %f %f)\n", This, method, spacing, baseline);
4591 if (spacing < 0.0f || (UINT32)method > DWRITE_LINE_SPACING_METHOD_UNIFORM)
4592 return E_INVALIDARG;
4594 This->format.spacingmethod = method;
4595 This->format.spacing = spacing;
4596 This->format.baseline = baseline;
4597 return S_OK;
4600 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_GetTextAlignment(IDWriteTextFormat1 *iface)
4602 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4603 TRACE("(%p)\n", This);
4604 return This->format.textalignment;
4607 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_GetParagraphAlignment(IDWriteTextFormat1 *iface)
4609 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4610 TRACE("(%p)\n", This);
4611 return This->format.paralign;
4614 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_GetWordWrapping(IDWriteTextFormat1 *iface)
4616 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4617 TRACE("(%p)\n", This);
4618 return This->format.wrapping;
4621 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_GetReadingDirection(IDWriteTextFormat1 *iface)
4623 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4624 TRACE("(%p)\n", This);
4625 return This->format.readingdir;
4628 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_GetFlowDirection(IDWriteTextFormat1 *iface)
4630 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4631 TRACE("(%p)\n", This);
4632 return This->format.flow;
4635 static FLOAT WINAPI dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat1 *iface)
4637 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4638 FIXME("(%p): stub\n", This);
4639 return 0.0f;
4642 static HRESULT WINAPI dwritetextformat_GetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING *options,
4643 IDWriteInlineObject **trimming_sign)
4645 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4646 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
4648 *options = This->format.trimming;
4649 if ((*trimming_sign = This->format.trimmingsign))
4650 IDWriteInlineObject_AddRef(*trimming_sign);
4652 return S_OK;
4655 static HRESULT WINAPI dwritetextformat_GetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD *method,
4656 FLOAT *spacing, FLOAT *baseline)
4658 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4659 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
4661 *method = This->format.spacingmethod;
4662 *spacing = This->format.spacing;
4663 *baseline = This->format.baseline;
4664 return S_OK;
4667 static HRESULT WINAPI dwritetextformat_GetFontCollection(IDWriteTextFormat1 *iface, IDWriteFontCollection **collection)
4669 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4671 TRACE("(%p)->(%p)\n", This, collection);
4673 *collection = This->format.collection;
4674 IDWriteFontCollection_AddRef(*collection);
4676 return S_OK;
4679 static UINT32 WINAPI dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat1 *iface)
4681 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4682 TRACE("(%p)\n", This);
4683 return This->format.family_len;
4686 static HRESULT WINAPI dwritetextformat_GetFontFamilyName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
4688 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4690 TRACE("(%p)->(%p %u)\n", This, name, size);
4692 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
4693 strcpyW(name, This->format.family_name);
4694 return S_OK;
4697 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_GetFontWeight(IDWriteTextFormat1 *iface)
4699 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4700 TRACE("(%p)\n", This);
4701 return This->format.weight;
4704 static DWRITE_FONT_STYLE WINAPI dwritetextformat_GetFontStyle(IDWriteTextFormat1 *iface)
4706 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4707 TRACE("(%p)\n", This);
4708 return This->format.style;
4711 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_GetFontStretch(IDWriteTextFormat1 *iface)
4713 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4714 TRACE("(%p)\n", This);
4715 return This->format.stretch;
4718 static FLOAT WINAPI dwritetextformat_GetFontSize(IDWriteTextFormat1 *iface)
4720 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4721 TRACE("(%p)\n", This);
4722 return This->format.fontsize;
4725 static UINT32 WINAPI dwritetextformat_GetLocaleNameLength(IDWriteTextFormat1 *iface)
4727 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4728 TRACE("(%p)\n", This);
4729 return This->format.locale_len;
4732 static HRESULT WINAPI dwritetextformat_GetLocaleName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
4734 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4736 TRACE("(%p)->(%p %u)\n", This, name, size);
4738 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
4739 strcpyW(name, This->format.locale);
4740 return S_OK;
4743 static HRESULT WINAPI dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat1 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
4745 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4747 TRACE("(%p)->(%d)\n", This, orientation);
4749 if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
4750 return E_INVALIDARG;
4752 This->format.vertical_orientation = orientation;
4753 return S_OK;
4756 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat1 *iface)
4758 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4759 TRACE("(%p)\n", This);
4760 return This->format.vertical_orientation;
4763 static HRESULT WINAPI dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat1 *iface, BOOL lastline_wrapping_enabled)
4765 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4767 TRACE("(%p)->(%d)\n", This, lastline_wrapping_enabled);
4769 This->format.last_line_wrapping = !!lastline_wrapping_enabled;
4770 return S_OK;
4773 static BOOL WINAPI dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat1 *iface)
4775 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4776 TRACE("(%p)\n", This);
4777 return This->format.last_line_wrapping;
4780 static HRESULT WINAPI dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat1 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
4782 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4783 TRACE("(%p)->(%d)\n", This, alignment);
4784 return format_set_optical_alignment(&This->format, alignment);
4787 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat1 *iface)
4789 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4790 TRACE("(%p)\n", This);
4791 return This->format.optical_alignment;
4794 static HRESULT WINAPI dwritetextformat1_SetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback *fallback)
4796 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4797 TRACE("(%p)->(%p)\n", This, fallback);
4798 return set_fontfallback_for_format(&This->format, fallback);
4801 static HRESULT WINAPI dwritetextformat1_GetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback **fallback)
4803 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
4804 TRACE("(%p)->(%p)\n", This, fallback);
4805 return get_fontfallback_from_format(&This->format, fallback);
4808 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl = {
4809 dwritetextformat_QueryInterface,
4810 dwritetextformat_AddRef,
4811 dwritetextformat_Release,
4812 dwritetextformat_SetTextAlignment,
4813 dwritetextformat_SetParagraphAlignment,
4814 dwritetextformat_SetWordWrapping,
4815 dwritetextformat_SetReadingDirection,
4816 dwritetextformat_SetFlowDirection,
4817 dwritetextformat_SetIncrementalTabStop,
4818 dwritetextformat_SetTrimming,
4819 dwritetextformat_SetLineSpacing,
4820 dwritetextformat_GetTextAlignment,
4821 dwritetextformat_GetParagraphAlignment,
4822 dwritetextformat_GetWordWrapping,
4823 dwritetextformat_GetReadingDirection,
4824 dwritetextformat_GetFlowDirection,
4825 dwritetextformat_GetIncrementalTabStop,
4826 dwritetextformat_GetTrimming,
4827 dwritetextformat_GetLineSpacing,
4828 dwritetextformat_GetFontCollection,
4829 dwritetextformat_GetFontFamilyNameLength,
4830 dwritetextformat_GetFontFamilyName,
4831 dwritetextformat_GetFontWeight,
4832 dwritetextformat_GetFontStyle,
4833 dwritetextformat_GetFontStretch,
4834 dwritetextformat_GetFontSize,
4835 dwritetextformat_GetLocaleNameLength,
4836 dwritetextformat_GetLocaleName,
4837 dwritetextformat1_SetVerticalGlyphOrientation,
4838 dwritetextformat1_GetVerticalGlyphOrientation,
4839 dwritetextformat1_SetLastLineWrapping,
4840 dwritetextformat1_GetLastLineWrapping,
4841 dwritetextformat1_SetOpticalAlignment,
4842 dwritetextformat1_GetOpticalAlignment,
4843 dwritetextformat1_SetFontFallback,
4844 dwritetextformat1_GetFontFallback
4847 static struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat *iface)
4849 return (iface->lpVtbl == (IDWriteTextFormatVtbl*)&dwritetextformatvtbl) ?
4850 CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat1_iface) : NULL;
4853 HRESULT create_textformat(const WCHAR *family_name, IDWriteFontCollection *collection, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style,
4854 DWRITE_FONT_STRETCH stretch, FLOAT size, const WCHAR *locale, IDWriteTextFormat **format)
4856 struct dwrite_textformat *This;
4858 *format = NULL;
4860 This = heap_alloc(sizeof(struct dwrite_textformat));
4861 if (!This) return E_OUTOFMEMORY;
4863 This->IDWriteTextFormat1_iface.lpVtbl = &dwritetextformatvtbl;
4864 This->ref = 1;
4865 This->format.family_name = heap_strdupW(family_name);
4866 This->format.family_len = strlenW(family_name);
4867 This->format.locale = heap_strdupW(locale);
4868 This->format.locale_len = strlenW(locale);
4869 /* force locale name to lower case, layout will inherit this modified value */
4870 strlwrW(This->format.locale);
4871 This->format.weight = weight;
4872 This->format.style = style;
4873 This->format.fontsize = size;
4874 This->format.stretch = stretch;
4875 This->format.textalignment = DWRITE_TEXT_ALIGNMENT_LEADING;
4876 This->format.optical_alignment = DWRITE_OPTICAL_ALIGNMENT_NONE;
4877 This->format.paralign = DWRITE_PARAGRAPH_ALIGNMENT_NEAR;
4878 This->format.wrapping = DWRITE_WORD_WRAPPING_WRAP;
4879 This->format.last_line_wrapping = TRUE;
4880 This->format.readingdir = DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
4881 This->format.flow = DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM;
4882 This->format.spacingmethod = DWRITE_LINE_SPACING_METHOD_DEFAULT;
4883 This->format.vertical_orientation = DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
4884 This->format.spacing = 0.0f;
4885 This->format.baseline = 0.0f;
4886 This->format.trimming.granularity = DWRITE_TRIMMING_GRANULARITY_NONE;
4887 This->format.trimming.delimiter = 0;
4888 This->format.trimming.delimiterCount = 0;
4889 This->format.trimmingsign = NULL;
4890 This->format.collection = collection;
4891 This->format.fallback = NULL;
4892 IDWriteFontCollection_AddRef(collection);
4894 *format = (IDWriteTextFormat*)&This->IDWriteTextFormat1_iface;
4896 return S_OK;
4899 static HRESULT WINAPI dwritetypography_QueryInterface(IDWriteTypography *iface, REFIID riid, void **obj)
4901 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4903 TRACE("(%p)->(%s %p)\n", typography, debugstr_guid(riid), obj);
4905 if (IsEqualIID(riid, &IID_IDWriteTypography) || IsEqualIID(riid, &IID_IUnknown)) {
4906 *obj = iface;
4907 IDWriteTypography_AddRef(iface);
4908 return S_OK;
4911 *obj = NULL;
4913 return E_NOINTERFACE;
4916 static ULONG WINAPI dwritetypography_AddRef(IDWriteTypography *iface)
4918 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4919 ULONG ref = InterlockedIncrement(&typography->ref);
4920 TRACE("(%p)->(%d)\n", typography, ref);
4921 return ref;
4924 static ULONG WINAPI dwritetypography_Release(IDWriteTypography *iface)
4926 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4927 ULONG ref = InterlockedDecrement(&typography->ref);
4929 TRACE("(%p)->(%d)\n", typography, ref);
4931 if (!ref) {
4932 heap_free(typography->features);
4933 heap_free(typography);
4936 return ref;
4939 static HRESULT WINAPI dwritetypography_AddFontFeature(IDWriteTypography *iface, DWRITE_FONT_FEATURE feature)
4941 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4943 TRACE("(%p)->(%x %u)\n", typography, feature.nameTag, feature.parameter);
4945 if (typography->count == typography->allocated) {
4946 DWRITE_FONT_FEATURE *ptr = heap_realloc(typography->features, 2*typography->allocated*sizeof(DWRITE_FONT_FEATURE));
4947 if (!ptr)
4948 return E_OUTOFMEMORY;
4950 typography->features = ptr;
4951 typography->allocated *= 2;
4954 typography->features[typography->count++] = feature;
4955 return S_OK;
4958 static UINT32 WINAPI dwritetypography_GetFontFeatureCount(IDWriteTypography *iface)
4960 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4961 TRACE("(%p)\n", typography);
4962 return typography->count;
4965 static HRESULT WINAPI dwritetypography_GetFontFeature(IDWriteTypography *iface, UINT32 index, DWRITE_FONT_FEATURE *feature)
4967 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
4969 TRACE("(%p)->(%u %p)\n", typography, index, feature);
4971 if (index >= typography->count)
4972 return E_INVALIDARG;
4974 *feature = typography->features[index];
4975 return S_OK;
4978 static const IDWriteTypographyVtbl dwritetypographyvtbl = {
4979 dwritetypography_QueryInterface,
4980 dwritetypography_AddRef,
4981 dwritetypography_Release,
4982 dwritetypography_AddFontFeature,
4983 dwritetypography_GetFontFeatureCount,
4984 dwritetypography_GetFontFeature
4987 HRESULT create_typography(IDWriteTypography **ret)
4989 struct dwrite_typography *typography;
4991 *ret = NULL;
4993 typography = heap_alloc(sizeof(*typography));
4994 if (!typography)
4995 return E_OUTOFMEMORY;
4997 typography->IDWriteTypography_iface.lpVtbl = &dwritetypographyvtbl;
4998 typography->ref = 1;
4999 typography->allocated = 2;
5000 typography->count = 0;
5002 typography->features = heap_alloc(typography->allocated*sizeof(DWRITE_FONT_FEATURE));
5003 if (!typography->features) {
5004 heap_free(typography);
5005 return E_OUTOFMEMORY;
5008 *ret = &typography->IDWriteTypography_iface;
5009 return S_OK;