dwrite: Store pair kerning range attribute.
[wine.git] / dlls / dwrite / layout.c
blobd26751e8c653689ea2a8be1111c1250fe30a1ee7
1 /*
2 * Text format and layout
4 * Copyright 2012, 2014 Nikolay Sivov for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "dwrite_private.h"
29 #include "scripts.h"
30 #include "wine/list.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
34 struct dwrite_textformat_data {
35 WCHAR *family_name;
36 UINT32 family_len;
37 WCHAR *locale;
38 UINT32 locale_len;
40 DWRITE_FONT_WEIGHT weight;
41 DWRITE_FONT_STYLE style;
42 DWRITE_FONT_STRETCH stretch;
44 DWRITE_PARAGRAPH_ALIGNMENT paralign;
45 DWRITE_READING_DIRECTION readingdir;
46 DWRITE_WORD_WRAPPING wrapping;
47 DWRITE_TEXT_ALIGNMENT textalignment;
48 DWRITE_FLOW_DIRECTION flow;
49 DWRITE_LINE_SPACING_METHOD spacingmethod;
51 FLOAT spacing;
52 FLOAT baseline;
53 FLOAT fontsize;
55 DWRITE_TRIMMING trimming;
56 IDWriteInlineObject *trimmingsign;
58 IDWriteFontCollection *collection;
61 enum layout_range_attr_kind {
62 LAYOUT_RANGE_ATTR_WEIGHT,
63 LAYOUT_RANGE_ATTR_STYLE,
64 LAYOUT_RANGE_ATTR_STRETCH,
65 LAYOUT_RANGE_ATTR_FONTSIZE,
66 LAYOUT_RANGE_ATTR_EFFECT,
67 LAYOUT_RANGE_ATTR_INLINE,
68 LAYOUT_RANGE_ATTR_UNDERLINE,
69 LAYOUT_RANGE_ATTR_STRIKETHROUGH,
70 LAYOUT_RANGE_ATTR_PAIR_KERNING,
71 LAYOUT_RANGE_ATTR_FONTCOLL,
72 LAYOUT_RANGE_ATTR_LOCALE,
73 LAYOUT_RANGE_ATTR_FONTFAMILY
76 struct layout_range_attr_value {
77 DWRITE_TEXT_RANGE range;
78 union {
79 DWRITE_FONT_WEIGHT weight;
80 DWRITE_FONT_STYLE style;
81 DWRITE_FONT_STRETCH stretch;
82 FLOAT fontsize;
83 IDWriteInlineObject *object;
84 IUnknown *effect;
85 BOOL underline;
86 BOOL strikethrough;
87 BOOL pair_kerning;
88 IDWriteFontCollection *collection;
89 const WCHAR *locale;
90 const WCHAR *fontfamily;
91 } u;
94 struct layout_range {
95 struct list entry;
96 DWRITE_TEXT_RANGE range;
97 DWRITE_FONT_WEIGHT weight;
98 DWRITE_FONT_STYLE style;
99 FLOAT fontsize;
100 DWRITE_FONT_STRETCH stretch;
101 IDWriteInlineObject *object;
102 IUnknown *effect;
103 BOOL underline;
104 BOOL strikethrough;
105 BOOL pair_kerning;
106 IDWriteFontCollection *collection;
107 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
108 WCHAR *fontfamily;
111 struct layout_run {
112 struct list entry;
113 DWRITE_GLYPH_RUN_DESCRIPTION descr;
114 DWRITE_GLYPH_RUN run;
115 DWRITE_SCRIPT_ANALYSIS sa;
116 UINT16 *glyphs;
117 UINT16 *clustermap;
118 FLOAT *advances;
119 DWRITE_GLYPH_OFFSET *offsets;
122 struct dwrite_textlayout {
123 IDWriteTextLayout2 IDWriteTextLayout2_iface;
124 IDWriteTextAnalysisSink IDWriteTextAnalysisSink_iface;
125 IDWriteTextAnalysisSource IDWriteTextAnalysisSource_iface;
126 LONG ref;
128 WCHAR *str;
129 UINT32 len;
130 struct dwrite_textformat_data format;
131 FLOAT maxwidth;
132 FLOAT maxheight;
133 struct list ranges;
134 struct list runs;
135 BOOL recompute;
137 DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
138 DWRITE_LINE_BREAKPOINT *actual_breakpoints;
140 DWRITE_CLUSTER_METRICS *clusters;
141 UINT32 clusters_count;
143 /* gdi-compatible layout specifics */
144 BOOL gdicompatible;
145 FLOAT pixels_per_dip;
146 BOOL use_gdi_natural;
147 DWRITE_MATRIX transform;
150 struct dwrite_textformat {
151 IDWriteTextFormat1 IDWriteTextFormat1_iface;
152 LONG ref;
153 struct dwrite_textformat_data format;
156 struct dwrite_trimmingsign {
157 IDWriteInlineObject IDWriteInlineObject_iface;
158 LONG ref;
161 struct dwrite_typography {
162 IDWriteTypography IDWriteTypography_iface;
163 LONG ref;
165 DWRITE_FONT_FEATURE *features;
166 UINT32 allocated;
167 UINT32 count;
170 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl;
172 static void release_format_data(struct dwrite_textformat_data *data)
174 if (data->collection) IDWriteFontCollection_Release(data->collection);
175 if (data->trimmingsign) IDWriteInlineObject_Release(data->trimmingsign);
176 heap_free(data->family_name);
177 heap_free(data->locale);
180 static inline struct dwrite_textlayout *impl_from_IDWriteTextLayout2(IDWriteTextLayout2 *iface)
182 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextLayout2_iface);
185 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSink(IDWriteTextAnalysisSink *iface)
187 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSink_iface);
190 static inline struct dwrite_textlayout *impl_from_IDWriteTextAnalysisSource(IDWriteTextAnalysisSource *iface)
192 return CONTAINING_RECORD(iface, struct dwrite_textlayout, IDWriteTextAnalysisSource_iface);
195 static inline struct dwrite_textformat *impl_from_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
197 return CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat1_iface);
200 static inline struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat1(IDWriteTextFormat1 *iface)
202 return iface->lpVtbl == &dwritetextformatvtbl ? impl_from_IDWriteTextFormat1(iface) : NULL;
205 static inline struct dwrite_trimmingsign *impl_from_IDWriteInlineObject(IDWriteInlineObject *iface)
207 return CONTAINING_RECORD(iface, struct dwrite_trimmingsign, IDWriteInlineObject_iface);
210 static inline struct dwrite_typography *impl_from_IDWriteTypography(IDWriteTypography *iface)
212 return CONTAINING_RECORD(iface, struct dwrite_typography, IDWriteTypography_iface);
215 static inline const char *debugstr_run(const struct layout_run *run)
217 return wine_dbg_sprintf("[%u,%u]", run->descr.textPosition, run->descr.textPosition +
218 run->descr.stringLength);
221 static struct layout_run *alloc_layout_run(void)
223 struct layout_run *ret;
225 ret = heap_alloc(sizeof(*ret));
226 if (!ret) return NULL;
228 ret->descr.localeName = NULL;
229 ret->descr.string = NULL;
230 ret->descr.stringLength = 0;
231 ret->descr.clusterMap = NULL;
232 ret->descr.textPosition = 0;
234 ret->run.fontFace = NULL;
235 ret->run.fontEmSize = 0.0;
236 ret->run.glyphCount = 0;
237 ret->run.glyphIndices = NULL;
238 ret->run.glyphAdvances = NULL;
239 ret->run.glyphOffsets = NULL;
240 ret->run.isSideways = FALSE;
241 ret->run.bidiLevel = 0;
243 ret->sa.script = Script_Unknown;
244 ret->sa.shapes = DWRITE_SCRIPT_SHAPES_DEFAULT;
246 ret->glyphs = NULL;
247 ret->clustermap = NULL;
248 ret->advances = NULL;
249 ret->offsets = NULL;
251 return ret;
254 static void free_layout_runs(struct dwrite_textlayout *layout)
256 struct layout_run *cur, *cur2;
257 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->runs, struct layout_run, entry) {
258 list_remove(&cur->entry);
259 if (cur->run.fontFace)
260 IDWriteFontFace_Release(cur->run.fontFace);
261 heap_free(cur->glyphs);
262 heap_free(cur->clustermap);
263 heap_free(cur->advances);
264 heap_free(cur->offsets);
265 heap_free(cur);
269 /* Used to resolve break condition by forcing stronger condition over weaker. */
270 static inline DWRITE_BREAK_CONDITION override_break_condition(DWRITE_BREAK_CONDITION existingbreak, DWRITE_BREAK_CONDITION newbreak)
272 switch (existingbreak) {
273 case DWRITE_BREAK_CONDITION_NEUTRAL:
274 return newbreak;
275 case DWRITE_BREAK_CONDITION_CAN_BREAK:
276 return newbreak == DWRITE_BREAK_CONDITION_NEUTRAL ? existingbreak : newbreak;
277 /* let's keep stronger conditions as is */
278 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK:
279 case DWRITE_BREAK_CONDITION_MUST_BREAK:
280 break;
281 default:
282 ERR("unknown break condition %d\n", existingbreak);
285 return existingbreak;
288 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
289 static HRESULT layout_update_breakpoints_range(struct dwrite_textlayout *layout, const struct layout_range *cur)
291 DWRITE_BREAK_CONDITION before, after;
292 HRESULT hr;
293 UINT32 i;
295 hr = IDWriteInlineObject_GetBreakConditions(cur->object, &before, &after);
296 if (FAILED(hr))
297 return hr;
299 if (!layout->actual_breakpoints) {
300 layout->actual_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
301 if (!layout->actual_breakpoints)
302 return E_OUTOFMEMORY;
304 memcpy(layout->actual_breakpoints, layout->nominal_breakpoints, sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
306 for (i = cur->range.startPosition; i < cur->range.length + cur->range.startPosition; i++) {
307 UINT32 j = i + cur->range.startPosition;
308 if (i == 0) {
309 if (j)
310 layout->actual_breakpoints[j].breakConditionBefore = layout->actual_breakpoints[j-1].breakConditionAfter =
311 override_break_condition(layout->actual_breakpoints[j-1].breakConditionAfter, before);
312 else
313 layout->actual_breakpoints[j].breakConditionBefore = before;
315 layout->actual_breakpoints[j].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
318 layout->actual_breakpoints[j].isWhitespace = 0;
319 layout->actual_breakpoints[j].isSoftHyphen = 0;
321 if (i == cur->range.length - 1) {
322 layout->actual_breakpoints[j].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
323 if (j < layout->len - 1)
324 layout->actual_breakpoints[j].breakConditionAfter = layout->actual_breakpoints[j+1].breakConditionAfter =
325 override_break_condition(layout->actual_breakpoints[j+1].breakConditionAfter, before);
326 else
327 layout->actual_breakpoints[j].breakConditionAfter = before;
331 return S_OK;
334 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos);
336 static void init_cluster_metrics(const struct layout_run *run, DWRITE_CLUSTER_METRICS *metrics)
338 metrics->width = 0.0;
339 metrics->length = 1;
340 metrics->canWrapLineAfter = FALSE;
341 metrics->isWhitespace = FALSE;
342 metrics->isNewline = FALSE;
343 metrics->isSoftHyphen = FALSE;
344 metrics->isRightToLeft = run->run.bidiLevel & 1;
345 metrics->padding = 0;
350 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
351 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
354 static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const struct layout_run *run, UINT32 *cluster)
356 DWRITE_CLUSTER_METRICS *metrics = &layout->clusters[*cluster];
357 UINT16 glyph;
358 UINT32 i;
360 glyph = run->descr.clusterMap[0];
361 init_cluster_metrics(run, metrics);
363 for (i = 0; i < run->descr.stringLength; i++) {
364 BOOL newcluster = glyph != run->descr.clusterMap[i];
366 /* add new cluster on starting glyph change or simply when run is over */
367 if (newcluster || i == run->descr.stringLength - 1) {
368 UINT8 breakcondition;
369 UINT16 j;
371 for (j = glyph; j < run->descr.clusterMap[i]; j++)
372 metrics->width += run->run.glyphAdvances[j];
374 /* FIXME: also set isWhitespace, isNewline and isSoftHyphen */
375 breakcondition = newcluster ? layout->nominal_breakpoints[i].breakConditionBefore :
376 layout->nominal_breakpoints[i].breakConditionAfter;
377 metrics->canWrapLineAfter = breakcondition == DWRITE_BREAK_CONDITION_CAN_BREAK ||
378 breakcondition == DWRITE_BREAK_CONDITION_MUST_BREAK;
380 /* advance to next cluster */
381 glyph = run->descr.clusterMap[i];
382 *cluster += 1;
383 metrics++;
384 init_cluster_metrics(run, metrics);
386 else
387 metrics->length++;
391 static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
393 IDWriteTextAnalyzer *analyzer;
394 struct layout_range *range;
395 struct layout_run *run;
396 UINT32 cluster = 0;
397 HRESULT hr;
399 free_layout_runs(layout);
400 heap_free(layout->clusters);
401 layout->clusters_count = 0;
402 layout->clusters = heap_alloc(layout->len*sizeof(DWRITE_CLUSTER_METRICS));
403 if (!layout->clusters)
404 return E_OUTOFMEMORY;
406 hr = get_textanalyzer(&analyzer);
407 if (FAILED(hr))
408 return hr;
410 LIST_FOR_EACH_ENTRY(range, &layout->ranges, struct layout_range, entry) {
411 /* inline objects override actual text in a range */
412 if (range->object) {
413 hr = layout_update_breakpoints_range(layout, range);
414 if (FAILED(hr))
415 return hr;
416 continue;
419 /* initial splitting by script */
420 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, &layout->IDWriteTextAnalysisSource_iface,
421 range->range.startPosition, range->range.length, &layout->IDWriteTextAnalysisSink_iface);
422 if (FAILED(hr))
423 break;
425 /* this splits it further */
426 hr = IDWriteTextAnalyzer_AnalyzeBidi(analyzer, &layout->IDWriteTextAnalysisSource_iface,
427 range->range.startPosition, range->range.length, &layout->IDWriteTextAnalysisSink_iface);
428 if (FAILED(hr))
429 break;
432 /* fill run info */
433 LIST_FOR_EACH_ENTRY(run, &layout->runs, struct layout_run, entry) {
434 DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props = NULL;
435 DWRITE_SHAPING_TEXT_PROPERTIES *text_props = NULL;
436 IDWriteFontFamily *family;
437 UINT32 index, max_count;
438 IDWriteFont *font;
439 BOOL exists = TRUE;
441 range = get_layout_range_by_pos(layout, run->descr.textPosition);
443 hr = IDWriteFontCollection_FindFamilyName(range->collection, range->fontfamily, &index, &exists);
444 if (FAILED(hr) || !exists) {
445 WARN("%s: family %s not found in collection %p\n", debugstr_run(run), debugstr_w(range->fontfamily), range->collection);
446 continue;
449 hr = IDWriteFontCollection_GetFontFamily(range->collection, index, &family);
450 if (FAILED(hr))
451 continue;
453 hr = IDWriteFontFamily_GetFirstMatchingFont(family, range->weight, range->stretch, range->style, &font);
454 IDWriteFontFamily_Release(family);
455 if (FAILED(hr)) {
456 WARN("%s: failed to get a matching font\n", debugstr_run(run));
457 continue;
460 hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
461 IDWriteFont_Release(font);
462 if (FAILED(hr))
463 continue;
465 run->run.fontEmSize = range->fontsize;
466 run->descr.localeName = range->locale;
467 run->clustermap = heap_alloc(run->descr.stringLength*sizeof(UINT16));
469 max_count = 3*run->descr.stringLength/2 + 16;
470 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
471 if (!run->clustermap || !run->glyphs)
472 goto memerr;
474 text_props = heap_alloc(run->descr.stringLength*sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
475 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
476 if (!text_props || !glyph_props)
477 goto memerr;
479 while (1) {
480 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, run->descr.string, run->descr.stringLength,
481 run->run.fontFace, FALSE /* FIXME */, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
482 NULL /* FIXME */, NULL, NULL, 0, max_count, run->clustermap, text_props, run->glyphs, glyph_props,
483 &run->run.glyphCount);
484 if (hr == E_NOT_SUFFICIENT_BUFFER) {
485 heap_free(run->glyphs);
486 heap_free(glyph_props);
488 max_count = run->run.glyphCount;
490 run->glyphs = heap_alloc(max_count*sizeof(UINT16));
491 glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
492 if (!run->glyphs || !glyph_props)
493 goto memerr;
495 continue;
498 break;
501 if (FAILED(hr)) {
502 heap_free(text_props);
503 heap_free(glyph_props);
504 WARN("%s: shaping failed 0x%08x\n", debugstr_run(run), hr);
505 continue;
508 run->run.glyphIndices = run->glyphs;
509 run->descr.clusterMap = run->clustermap;
511 run->advances = heap_alloc(run->run.glyphCount*sizeof(FLOAT));
512 run->offsets = heap_alloc(run->run.glyphCount*sizeof(DWRITE_GLYPH_OFFSET));
513 if (!run->advances || !run->offsets)
514 goto memerr;
516 /* now set advances and offsets */
517 if (layout->gdicompatible)
518 hr = IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap,
519 text_props, run->descr.stringLength, run->run.glyphIndices, glyph_props, run->run.glyphCount,
520 run->run.fontFace, run->run.fontEmSize, layout->pixels_per_dip, &layout->transform, layout->use_gdi_natural,
521 FALSE /* FIXME */, run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL, NULL, 0,
522 run->advances, run->offsets);
523 else
524 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap, text_props,
525 run->descr.stringLength, run->run.glyphIndices, glyph_props, run->run.glyphCount, run->run.fontFace,
526 run->run.fontEmSize, FALSE /* FIXME */, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
527 NULL, NULL, 0, run->advances, run->offsets);
529 heap_free(text_props);
530 heap_free(glyph_props);
531 if (FAILED(hr))
532 WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_run(run), hr);
534 run->run.glyphAdvances = run->advances;
535 run->run.glyphOffsets = run->offsets;
537 /* now set cluster metrics */
538 layout_set_cluster_metrics(layout, run, &cluster);
540 continue;
542 memerr:
543 heap_free(text_props);
544 heap_free(glyph_props);
545 heap_free(run->clustermap);
546 heap_free(run->glyphs);
547 heap_free(run->advances);
548 heap_free(run->offsets);
549 run->advances = NULL;
550 run->offsets = NULL;
551 run->clustermap = run->glyphs = NULL;
552 hr = E_OUTOFMEMORY;
553 break;
556 if (hr == S_OK)
557 layout->clusters_count = cluster + 1;
559 IDWriteTextAnalyzer_Release(analyzer);
560 return hr;
563 static HRESULT layout_compute(struct dwrite_textlayout *layout)
565 HRESULT hr;
567 if (!layout->recompute)
568 return S_OK;
570 /* nominal breakpoints are evaluated only once, because string never changes */
571 if (!layout->nominal_breakpoints) {
572 IDWriteTextAnalyzer *analyzer;
573 HRESULT hr;
575 layout->nominal_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
576 if (!layout->nominal_breakpoints)
577 return E_OUTOFMEMORY;
579 hr = get_textanalyzer(&analyzer);
580 if (FAILED(hr))
581 return hr;
583 hr = IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer, &layout->IDWriteTextAnalysisSource_iface,
584 0, layout->len, &layout->IDWriteTextAnalysisSink_iface);
585 IDWriteTextAnalyzer_Release(analyzer);
588 hr = layout_compute_runs(layout);
590 if (TRACE_ON(dwrite)) {
591 struct layout_run *cur;
593 LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
594 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur->descr.textPosition, cur->descr.textPosition+cur->descr.stringLength-1,
595 cur->descr.stringLength, cur->run.bidiLevel);
599 layout->recompute = FALSE;
600 return hr;
603 /* To be used in IDWriteTextLayout methods to validate and fix passed range */
604 static inline BOOL validate_text_range(struct dwrite_textlayout *layout, DWRITE_TEXT_RANGE *r)
606 if (r->startPosition >= layout->len)
607 return FALSE;
609 if (r->startPosition + r->length > layout->len)
610 r->length = layout->len - r->startPosition;
612 return TRUE;
615 static BOOL is_same_layout_attrvalue(struct layout_range const *range, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
617 switch (attr) {
618 case LAYOUT_RANGE_ATTR_WEIGHT:
619 return range->weight == value->u.weight;
620 case LAYOUT_RANGE_ATTR_STYLE:
621 return range->style == value->u.style;
622 case LAYOUT_RANGE_ATTR_STRETCH:
623 return range->stretch == value->u.stretch;
624 case LAYOUT_RANGE_ATTR_FONTSIZE:
625 return range->fontsize == value->u.fontsize;
626 case LAYOUT_RANGE_ATTR_INLINE:
627 return range->object == value->u.object;
628 case LAYOUT_RANGE_ATTR_EFFECT:
629 return range->effect == value->u.effect;
630 case LAYOUT_RANGE_ATTR_UNDERLINE:
631 return range->underline == value->u.underline;
632 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
633 return range->strikethrough == value->u.strikethrough;
634 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
635 return range->pair_kerning == value->u.pair_kerning;
636 case LAYOUT_RANGE_ATTR_FONTCOLL:
637 return range->collection == value->u.collection;
638 case LAYOUT_RANGE_ATTR_LOCALE:
639 return strcmpW(range->locale, value->u.locale) == 0;
640 case LAYOUT_RANGE_ATTR_FONTFAMILY:
641 return strcmpW(range->fontfamily, value->u.fontfamily) == 0;
642 default:
646 return FALSE;
649 static inline BOOL is_same_layout_attributes(struct layout_range const *left, struct layout_range const *right)
651 return left->weight == right->weight &&
652 left->style == right->style &&
653 left->stretch == right->stretch &&
654 left->fontsize == right->fontsize &&
655 left->object == right->object &&
656 left->effect == right->effect &&
657 left->underline == right->underline &&
658 left->strikethrough == right->strikethrough &&
659 left->pair_kerning == right->pair_kerning &&
660 left->collection == right->collection &&
661 !strcmpW(left->locale, right->locale) &&
662 !strcmpW(left->fontfamily, right->fontfamily);
665 static inline BOOL is_same_text_range(const DWRITE_TEXT_RANGE *left, const DWRITE_TEXT_RANGE *right)
667 return left->startPosition == right->startPosition && left->length == right->length;
670 /* Allocates range and inits it with default values from text format. */
671 static struct layout_range *alloc_layout_range(struct dwrite_textlayout *layout, const DWRITE_TEXT_RANGE *r)
673 struct layout_range *range;
675 range = heap_alloc(sizeof(*range));
676 if (!range) return NULL;
678 range->range = *r;
679 range->weight = layout->format.weight;
680 range->style = layout->format.style;
681 range->stretch = layout->format.stretch;
682 range->fontsize = layout->format.fontsize;
683 range->object = NULL;
684 range->effect = NULL;
685 range->underline = FALSE;
686 range->strikethrough = FALSE;
687 range->pair_kerning = FALSE;
689 range->fontfamily = heap_strdupW(layout->format.family_name);
690 if (!range->fontfamily) {
691 heap_free(range);
692 return NULL;
695 range->collection = layout->format.collection;
696 if (range->collection)
697 IDWriteFontCollection_AddRef(range->collection);
698 strcpyW(range->locale, layout->format.locale);
700 return range;
703 static struct layout_range *alloc_layout_range_from(struct layout_range *from, const DWRITE_TEXT_RANGE *r)
705 struct layout_range *range;
707 range = heap_alloc(sizeof(*range));
708 if (!range) return NULL;
710 *range = *from;
711 range->range = *r;
713 range->fontfamily = heap_strdupW(from->fontfamily);
714 if (!range->fontfamily) {
715 heap_free(range);
716 return NULL;
719 /* update refcounts */
720 if (range->object)
721 IDWriteInlineObject_AddRef(range->object);
722 if (range->effect)
723 IUnknown_AddRef(range->effect);
724 if (range->collection)
725 IDWriteFontCollection_AddRef(range->collection);
727 return range;
730 static void free_layout_range(struct layout_range *range)
732 if (!range)
733 return;
734 if (range->object)
735 IDWriteInlineObject_Release(range->object);
736 if (range->effect)
737 IUnknown_Release(range->effect);
738 if (range->collection)
739 IDWriteFontCollection_Release(range->collection);
740 heap_free(range->fontfamily);
741 heap_free(range);
744 static void free_layout_ranges_list(struct dwrite_textlayout *layout)
746 struct layout_range *cur, *cur2;
747 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->ranges, struct layout_range, entry) {
748 list_remove(&cur->entry);
749 free_layout_range(cur);
753 static struct layout_range *find_outer_range(struct dwrite_textlayout *layout, const DWRITE_TEXT_RANGE *range)
755 struct layout_range *cur;
757 LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, entry) {
759 if (cur->range.startPosition > range->startPosition)
760 return NULL;
762 if ((cur->range.startPosition + cur->range.length < range->startPosition + range->length) &&
763 (range->startPosition < cur->range.startPosition + cur->range.length))
764 return NULL;
765 if (cur->range.startPosition + cur->range.length >= range->startPosition + range->length)
766 return cur;
769 return NULL;
772 static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos)
774 struct layout_range *cur;
776 LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, entry) {
777 DWRITE_TEXT_RANGE *r = &cur->range;
778 if (r->startPosition <= pos && pos < r->startPosition + r->length)
779 return cur;
782 return NULL;
785 static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
787 if (*dest == value) return FALSE;
789 if (*dest)
790 IUnknown_Release(*dest);
791 *dest = value;
792 if (*dest)
793 IUnknown_AddRef(*dest);
795 return TRUE;
798 static BOOL set_layout_range_attrval(struct layout_range *dest, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
800 BOOL changed = FALSE;
802 switch (attr) {
803 case LAYOUT_RANGE_ATTR_WEIGHT:
804 changed = dest->weight != value->u.weight;
805 dest->weight = value->u.weight;
806 break;
807 case LAYOUT_RANGE_ATTR_STYLE:
808 changed = dest->style != value->u.style;
809 dest->style = value->u.style;
810 break;
811 case LAYOUT_RANGE_ATTR_STRETCH:
812 changed = dest->stretch != value->u.stretch;
813 dest->stretch = value->u.stretch;
814 break;
815 case LAYOUT_RANGE_ATTR_FONTSIZE:
816 changed = dest->fontsize != value->u.fontsize;
817 dest->fontsize = value->u.fontsize;
818 break;
819 case LAYOUT_RANGE_ATTR_INLINE:
820 changed = set_layout_range_iface_attr((IUnknown**)&dest->object, (IUnknown*)value->u.object);
821 break;
822 case LAYOUT_RANGE_ATTR_EFFECT:
823 changed = set_layout_range_iface_attr((IUnknown**)&dest->effect, (IUnknown*)value->u.effect);
824 break;
825 case LAYOUT_RANGE_ATTR_UNDERLINE:
826 changed = dest->underline != value->u.underline;
827 dest->underline = value->u.underline;
828 break;
829 case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
830 changed = dest->strikethrough != value->u.strikethrough;
831 dest->strikethrough = value->u.strikethrough;
832 break;
833 case LAYOUT_RANGE_ATTR_PAIR_KERNING:
834 changed = dest->pair_kerning != value->u.pair_kerning;
835 dest->pair_kerning = value->u.pair_kerning;
836 break;
837 case LAYOUT_RANGE_ATTR_FONTCOLL:
838 changed = set_layout_range_iface_attr((IUnknown**)&dest->collection, (IUnknown*)value->u.collection);
839 break;
840 case LAYOUT_RANGE_ATTR_LOCALE:
841 changed = strcmpW(dest->locale, value->u.locale) != 0;
842 if (changed)
843 strcpyW(dest->locale, value->u.locale);
844 break;
845 case LAYOUT_RANGE_ATTR_FONTFAMILY:
846 changed = strcmpW(dest->fontfamily, value->u.fontfamily) != 0;
847 if (changed) {
848 heap_free(dest->fontfamily);
849 dest->fontfamily = heap_strdupW(value->u.fontfamily);
851 break;
852 default:
856 return changed;
859 static inline BOOL is_in_layout_range(const DWRITE_TEXT_RANGE *outer, const DWRITE_TEXT_RANGE *inner)
861 return (inner->startPosition >= outer->startPosition) &&
862 (inner->startPosition + inner->length <= outer->startPosition + outer->length);
865 static inline HRESULT return_range(const struct layout_range *range, DWRITE_TEXT_RANGE *r)
867 if (r) *r = range->range;
868 return S_OK;
871 /* Set attribute value for given range, does all needed splitting/merging of existing ranges. */
872 static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
874 struct layout_range *outer, *right, *left, *cur;
875 struct list *ranges = &layout->ranges;
876 BOOL changed = FALSE;
877 DWRITE_TEXT_RANGE r;
879 if (!validate_text_range(layout, &value->range))
880 return S_OK;
882 /* If new range is completely within existing range, split existing range in two */
883 if ((outer = find_outer_range(layout, &value->range))) {
885 /* no need to add same range */
886 if (is_same_layout_attrvalue(outer, attr, value))
887 return S_OK;
889 /* for matching range bounds just replace data */
890 if (is_same_text_range(&outer->range, &value->range)) {
891 changed = set_layout_range_attrval(outer, attr, value);
892 goto done;
895 /* add new range to the left */
896 if (value->range.startPosition == outer->range.startPosition) {
897 left = alloc_layout_range_from(outer, &value->range);
898 if (!left) return E_OUTOFMEMORY;
900 changed = set_layout_range_attrval(left, attr, value);
901 list_add_before(&outer->entry, &left->entry);
902 outer->range.startPosition += value->range.length;
903 outer->range.length -= value->range.length;
904 goto done;
907 /* add new range to the right */
908 if (value->range.startPosition + value->range.length == outer->range.startPosition + outer->range.length) {
909 right = alloc_layout_range_from(outer, &value->range);
910 if (!right) return E_OUTOFMEMORY;
912 changed = set_layout_range_attrval(right, attr, value);
913 list_add_after(&outer->entry, &right->entry);
914 outer->range.length -= value->range.length;
915 goto done;
918 r.startPosition = value->range.startPosition + value->range.length;
919 r.length = outer->range.length + outer->range.startPosition - r.startPosition;
921 /* right part */
922 right = alloc_layout_range_from(outer, &r);
923 /* new range in the middle */
924 cur = alloc_layout_range_from(outer, &value->range);
925 if (!right || !cur) {
926 free_layout_range(right);
927 free_layout_range(cur);
928 return E_OUTOFMEMORY;
931 /* reuse container range as a left part */
932 outer->range.length = value->range.startPosition - outer->range.startPosition;
934 /* new part */
935 set_layout_range_attrval(cur, attr, value);
937 list_add_after(&outer->entry, &cur->entry);
938 list_add_after(&cur->entry, &right->entry);
940 return S_OK;
943 /* Now it's only possible that given range contains some existing ranges, fully or partially.
944 Update all of them. */
945 left = get_layout_range_by_pos(layout, value->range.startPosition);
946 if (left->range.startPosition == value->range.startPosition)
947 changed = set_layout_range_attrval(left, attr, value);
948 else /* need to split */ {
949 r.startPosition = value->range.startPosition;
950 r.length = left->range.length - value->range.startPosition + left->range.startPosition;
951 left->range.length -= r.length;
952 cur = alloc_layout_range_from(left, &r);
953 changed = set_layout_range_attrval(cur, attr, value);
954 list_add_after(&left->entry, &cur->entry);
956 cur = LIST_ENTRY(list_next(ranges, &left->entry), struct layout_range, entry);
958 /* for all existing ranges covered by new one update value */
959 while (is_in_layout_range(&value->range, &cur->range)) {
960 changed = set_layout_range_attrval(cur, attr, value);
961 cur = LIST_ENTRY(list_next(ranges, &cur->entry), struct layout_range, entry);
964 /* it's possible rightmost range intersects */
965 if (cur && (cur->range.startPosition < value->range.startPosition + value->range.length)) {
966 r.startPosition = cur->range.startPosition;
967 r.length = value->range.startPosition + value->range.length - cur->range.startPosition;
968 left = alloc_layout_range_from(cur, &r);
969 changed = set_layout_range_attrval(left, attr, value);
970 cur->range.startPosition += left->range.length;
971 cur->range.length -= left->range.length;
972 list_add_before(&cur->entry, &left->entry);
975 done:
976 if (changed) {
977 struct list *next, *i;
979 layout->recompute = TRUE;
980 i = list_head(ranges);
981 while ((next = list_next(ranges, i))) {
982 struct layout_range *next_range = LIST_ENTRY(next, struct layout_range, entry);
984 cur = LIST_ENTRY(i, struct layout_range, entry);
985 if (is_same_layout_attributes(cur, next_range)) {
986 /* remove similar range */
987 cur->range.length += next_range->range.length;
988 list_remove(next);
989 free_layout_range(next_range);
991 else
992 i = list_next(ranges, i);
996 return S_OK;
999 static inline const WCHAR *get_string_attribute_ptr(struct layout_range *range, enum layout_range_attr_kind kind)
1001 const WCHAR *str;
1003 switch (kind) {
1004 case LAYOUT_RANGE_ATTR_LOCALE:
1005 str = range->locale;
1006 break;
1007 case LAYOUT_RANGE_ATTR_FONTFAMILY:
1008 str = range->fontfamily;
1009 break;
1010 default:
1011 str = NULL;
1014 return str;
1017 static HRESULT get_string_attribute_length(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
1018 UINT32 *length, DWRITE_TEXT_RANGE *r)
1020 struct layout_range *range;
1021 const WCHAR *str;
1023 range = get_layout_range_by_pos(layout, position);
1024 if (!range) {
1025 *length = 0;
1026 return S_OK;
1029 str = get_string_attribute_ptr(range, kind);
1030 *length = strlenW(str);
1031 return return_range(range, r);
1034 static HRESULT get_string_attribute_value(struct dwrite_textlayout *layout, enum layout_range_attr_kind kind, UINT32 position,
1035 WCHAR *ret, UINT32 length, DWRITE_TEXT_RANGE *r)
1037 struct layout_range *range;
1038 const WCHAR *str;
1040 if (length == 0)
1041 return E_INVALIDARG;
1043 ret[0] = 0;
1044 range = get_layout_range_by_pos(layout, position);
1045 if (!range)
1046 return E_INVALIDARG;
1048 str = get_string_attribute_ptr(range, kind);
1049 if (length < strlenW(str) + 1)
1050 return E_NOT_SUFFICIENT_BUFFER;
1052 strcpyW(ret, str);
1053 return return_range(range, r);
1056 static HRESULT WINAPI dwritetextlayout_QueryInterface(IDWriteTextLayout2 *iface, REFIID riid, void **obj)
1058 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1060 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1062 if (IsEqualIID(riid, &IID_IDWriteTextLayout2) ||
1063 IsEqualIID(riid, &IID_IDWriteTextLayout1) ||
1064 IsEqualIID(riid, &IID_IDWriteTextLayout) ||
1065 IsEqualIID(riid, &IID_IDWriteTextFormat) ||
1066 IsEqualIID(riid, &IID_IUnknown))
1068 *obj = iface;
1069 IDWriteTextLayout2_AddRef(iface);
1070 return S_OK;
1073 *obj = NULL;
1075 return E_NOINTERFACE;
1078 static ULONG WINAPI dwritetextlayout_AddRef(IDWriteTextLayout2 *iface)
1080 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1081 ULONG ref = InterlockedIncrement(&This->ref);
1082 TRACE("(%p)->(%d)\n", This, ref);
1083 return ref;
1086 static ULONG WINAPI dwritetextlayout_Release(IDWriteTextLayout2 *iface)
1088 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1089 ULONG ref = InterlockedDecrement(&This->ref);
1091 TRACE("(%p)->(%d)\n", This, ref);
1093 if (!ref) {
1094 free_layout_ranges_list(This);
1095 free_layout_runs(This);
1096 release_format_data(&This->format);
1097 heap_free(This->nominal_breakpoints);
1098 heap_free(This->actual_breakpoints);
1099 heap_free(This->clusters);
1100 heap_free(This->str);
1101 heap_free(This);
1104 return ref;
1107 static HRESULT WINAPI dwritetextlayout_SetTextAlignment(IDWriteTextLayout2 *iface, DWRITE_TEXT_ALIGNMENT alignment)
1109 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1110 FIXME("(%p)->(%d): stub\n", This, alignment);
1111 return E_NOTIMPL;
1114 static HRESULT WINAPI dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout2 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
1116 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1117 FIXME("(%p)->(%d): stub\n", This, alignment);
1118 return E_NOTIMPL;
1121 static HRESULT WINAPI dwritetextlayout_SetWordWrapping(IDWriteTextLayout2 *iface, DWRITE_WORD_WRAPPING wrapping)
1123 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1124 FIXME("(%p)->(%d): stub\n", This, wrapping);
1125 return E_NOTIMPL;
1128 static HRESULT WINAPI dwritetextlayout_SetReadingDirection(IDWriteTextLayout2 *iface, DWRITE_READING_DIRECTION direction)
1130 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1131 FIXME("(%p)->(%d): stub\n", This, direction);
1132 return E_NOTIMPL;
1135 static HRESULT WINAPI dwritetextlayout_SetFlowDirection(IDWriteTextLayout2 *iface, DWRITE_FLOW_DIRECTION direction)
1137 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1138 FIXME("(%p)->(%d): stub\n", This, direction);
1139 return E_NOTIMPL;
1142 static HRESULT WINAPI dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout2 *iface, FLOAT tabstop)
1144 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1145 FIXME("(%p)->(%f): stub\n", This, tabstop);
1146 return E_NOTIMPL;
1149 static HRESULT WINAPI dwritetextlayout_SetTrimming(IDWriteTextLayout2 *iface, DWRITE_TRIMMING const *trimming,
1150 IDWriteInlineObject *trimming_sign)
1152 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1153 FIXME("(%p)->(%p %p): stub\n", This, trimming, trimming_sign);
1154 return E_NOTIMPL;
1157 static HRESULT WINAPI dwritetextlayout_SetLineSpacing(IDWriteTextLayout2 *iface, DWRITE_LINE_SPACING_METHOD spacing,
1158 FLOAT line_spacing, FLOAT baseline)
1160 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1161 FIXME("(%p)->(%d %f %f): stub\n", This, spacing, line_spacing, baseline);
1162 return E_NOTIMPL;
1165 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextlayout_GetTextAlignment(IDWriteTextLayout2 *iface)
1167 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1168 TRACE("(%p)\n", This);
1169 return This->format.textalignment;
1172 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout2 *iface)
1174 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1175 TRACE("(%p)\n", This);
1176 return This->format.paralign;
1179 static DWRITE_WORD_WRAPPING WINAPI dwritetextlayout_GetWordWrapping(IDWriteTextLayout2 *iface)
1181 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1182 FIXME("(%p): stub\n", This);
1183 return This->format.wrapping;
1186 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_GetReadingDirection(IDWriteTextLayout2 *iface)
1188 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1189 TRACE("(%p)\n", This);
1190 return This->format.readingdir;
1193 static DWRITE_FLOW_DIRECTION WINAPI dwritetextlayout_GetFlowDirection(IDWriteTextLayout2 *iface)
1195 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1196 TRACE("(%p)\n", This);
1197 return This->format.flow;
1200 static FLOAT WINAPI dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout2 *iface)
1202 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1203 FIXME("(%p): stub\n", This);
1204 return 0.0;
1207 static HRESULT WINAPI dwritetextlayout_GetTrimming(IDWriteTextLayout2 *iface, DWRITE_TRIMMING *options,
1208 IDWriteInlineObject **trimming_sign)
1210 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1212 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
1214 *options = This->format.trimming;
1215 *trimming_sign = This->format.trimmingsign;
1216 if (*trimming_sign)
1217 IDWriteInlineObject_AddRef(*trimming_sign);
1218 return S_OK;
1221 static HRESULT WINAPI dwritetextlayout_GetLineSpacing(IDWriteTextLayout2 *iface, DWRITE_LINE_SPACING_METHOD *method,
1222 FLOAT *spacing, FLOAT *baseline)
1224 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1226 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
1228 *method = This->format.spacingmethod;
1229 *spacing = This->format.spacing;
1230 *baseline = This->format.baseline;
1231 return S_OK;
1234 static HRESULT WINAPI dwritetextlayout_GetFontCollection(IDWriteTextLayout2 *iface, IDWriteFontCollection **collection)
1236 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1238 TRACE("(%p)->(%p)\n", This, collection);
1240 *collection = This->format.collection;
1241 if (*collection)
1242 IDWriteFontCollection_AddRef(*collection);
1243 return S_OK;
1246 static UINT32 WINAPI dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout2 *iface)
1248 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1249 TRACE("(%p)\n", This);
1250 return This->format.family_len;
1253 static HRESULT WINAPI dwritetextlayout_GetFontFamilyName(IDWriteTextLayout2 *iface, WCHAR *name, UINT32 size)
1255 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1257 TRACE("(%p)->(%p %u)\n", This, name, size);
1259 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
1260 strcpyW(name, This->format.family_name);
1261 return S_OK;
1264 static DWRITE_FONT_WEIGHT WINAPI dwritetextlayout_GetFontWeight(IDWriteTextLayout2 *iface)
1266 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1267 TRACE("(%p)\n", This);
1268 return This->format.weight;
1271 static DWRITE_FONT_STYLE WINAPI dwritetextlayout_GetFontStyle(IDWriteTextLayout2 *iface)
1273 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1274 TRACE("(%p)\n", This);
1275 return This->format.style;
1278 static DWRITE_FONT_STRETCH WINAPI dwritetextlayout_GetFontStretch(IDWriteTextLayout2 *iface)
1280 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1281 TRACE("(%p)\n", This);
1282 return This->format.stretch;
1285 static FLOAT WINAPI dwritetextlayout_GetFontSize(IDWriteTextLayout2 *iface)
1287 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1288 TRACE("(%p)\n", This);
1289 return This->format.fontsize;
1292 static UINT32 WINAPI dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout2 *iface)
1294 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1295 TRACE("(%p)\n", This);
1296 return This->format.locale_len;
1299 static HRESULT WINAPI dwritetextlayout_GetLocaleName(IDWriteTextLayout2 *iface, WCHAR *name, UINT32 size)
1301 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1303 TRACE("(%p)->(%p %u)\n", This, name, size);
1305 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
1306 strcpyW(name, This->format.locale);
1307 return S_OK;
1310 static HRESULT WINAPI dwritetextlayout_SetMaxWidth(IDWriteTextLayout2 *iface, FLOAT maxWidth)
1312 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1313 TRACE("(%p)->(%.1f)\n", This, maxWidth);
1315 if (maxWidth < 0.0)
1316 return E_INVALIDARG;
1318 This->maxwidth = maxWidth;
1319 return S_OK;
1322 static HRESULT WINAPI dwritetextlayout_SetMaxHeight(IDWriteTextLayout2 *iface, FLOAT maxHeight)
1324 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1325 TRACE("(%p)->(%.1f)\n", This, maxHeight);
1327 if (maxHeight < 0.0)
1328 return E_INVALIDARG;
1330 This->maxheight = maxHeight;
1331 return S_OK;
1334 static HRESULT WINAPI dwritetextlayout_SetFontCollection(IDWriteTextLayout2 *iface, IDWriteFontCollection* collection, DWRITE_TEXT_RANGE range)
1336 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1337 struct layout_range_attr_value value;
1339 TRACE("(%p)->(%p %s)\n", This, collection, debugstr_range(&range));
1341 value.range = range;
1342 value.u.collection = collection;
1343 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTCOLL, &value);
1346 static HRESULT WINAPI dwritetextlayout_SetFontFamilyName(IDWriteTextLayout2 *iface, WCHAR const *name, DWRITE_TEXT_RANGE range)
1348 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1349 struct layout_range_attr_value value;
1351 TRACE("(%p)->(%s %s)\n", This, debugstr_w(name), debugstr_range(&range));
1353 if (!name)
1354 return E_INVALIDARG;
1356 value.range = range;
1357 value.u.fontfamily = name;
1358 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTFAMILY, &value);
1361 static HRESULT WINAPI dwritetextlayout_SetFontWeight(IDWriteTextLayout2 *iface, DWRITE_FONT_WEIGHT weight, DWRITE_TEXT_RANGE range)
1363 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1364 struct layout_range_attr_value value;
1366 TRACE("(%p)->(%d %s)\n", This, weight, debugstr_range(&range));
1368 value.range = range;
1369 value.u.weight = weight;
1370 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_WEIGHT, &value);
1373 static HRESULT WINAPI dwritetextlayout_SetFontStyle(IDWriteTextLayout2 *iface, DWRITE_FONT_STYLE style, DWRITE_TEXT_RANGE range)
1375 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1376 struct layout_range_attr_value value;
1378 TRACE("(%p)->(%d %s)\n", This, style, debugstr_range(&range));
1380 value.range = range;
1381 value.u.style = style;
1382 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STYLE, &value);
1385 static HRESULT WINAPI dwritetextlayout_SetFontStretch(IDWriteTextLayout2 *iface, DWRITE_FONT_STRETCH stretch, DWRITE_TEXT_RANGE range)
1387 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1388 struct layout_range_attr_value value;
1390 TRACE("(%p)->(%d %s)\n", This, stretch, debugstr_range(&range));
1392 value.range = range;
1393 value.u.stretch = stretch;
1394 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRETCH, &value);
1397 static HRESULT WINAPI dwritetextlayout_SetFontSize(IDWriteTextLayout2 *iface, FLOAT size, DWRITE_TEXT_RANGE range)
1399 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1400 struct layout_range_attr_value value;
1402 TRACE("(%p)->(%.2f %s)\n", This, size, debugstr_range(&range));
1404 value.range = range;
1405 value.u.fontsize = size;
1406 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_FONTSIZE, &value);
1409 static HRESULT WINAPI dwritetextlayout_SetUnderline(IDWriteTextLayout2 *iface, BOOL underline, DWRITE_TEXT_RANGE range)
1411 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1412 struct layout_range_attr_value value;
1414 TRACE("(%p)->(%d %s)\n", This, underline, debugstr_range(&range));
1416 value.range = range;
1417 value.u.underline = underline;
1418 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_UNDERLINE, &value);
1421 static HRESULT WINAPI dwritetextlayout_SetStrikethrough(IDWriteTextLayout2 *iface, BOOL strikethrough, DWRITE_TEXT_RANGE range)
1423 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1424 struct layout_range_attr_value value;
1426 TRACE("(%p)->(%d %s)\n", This, strikethrough, debugstr_range(&range));
1428 value.range = range;
1429 value.u.underline = strikethrough;
1430 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_STRIKETHROUGH, &value);
1433 static HRESULT WINAPI dwritetextlayout_SetDrawingEffect(IDWriteTextLayout2 *iface, IUnknown* effect, DWRITE_TEXT_RANGE range)
1435 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1436 struct layout_range_attr_value value;
1438 TRACE("(%p)->(%p %s)\n", This, effect, debugstr_range(&range));
1440 value.range = range;
1441 value.u.effect = effect;
1442 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_EFFECT, &value);
1445 static HRESULT WINAPI dwritetextlayout_SetInlineObject(IDWriteTextLayout2 *iface, IDWriteInlineObject *object, DWRITE_TEXT_RANGE range)
1447 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1448 struct layout_range_attr_value value;
1450 TRACE("(%p)->(%p %s)\n", This, object, debugstr_range(&range));
1452 value.range = range;
1453 value.u.object = object;
1454 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_INLINE, &value);
1457 static HRESULT WINAPI dwritetextlayout_SetTypography(IDWriteTextLayout2 *iface, IDWriteTypography* typography, DWRITE_TEXT_RANGE range)
1459 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1460 FIXME("(%p)->(%p %s): stub\n", This, typography, debugstr_range(&range));
1461 return E_NOTIMPL;
1464 static HRESULT WINAPI dwritetextlayout_SetLocaleName(IDWriteTextLayout2 *iface, WCHAR const* locale, DWRITE_TEXT_RANGE range)
1466 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1467 struct layout_range_attr_value value;
1469 TRACE("(%p)->(%s %s)\n", This, debugstr_w(locale), debugstr_range(&range));
1471 if (!locale || strlenW(locale) > LOCALE_NAME_MAX_LENGTH-1)
1472 return E_INVALIDARG;
1474 value.range = range;
1475 value.u.locale = locale;
1476 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_LOCALE, &value);
1479 static FLOAT WINAPI dwritetextlayout_GetMaxWidth(IDWriteTextLayout2 *iface)
1481 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1482 TRACE("(%p)\n", This);
1483 return This->maxwidth;
1486 static FLOAT WINAPI dwritetextlayout_GetMaxHeight(IDWriteTextLayout2 *iface)
1488 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1489 TRACE("(%p)\n", This);
1490 return This->maxheight;
1493 static HRESULT WINAPI dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout2 *iface, UINT32 position,
1494 IDWriteFontCollection** collection, DWRITE_TEXT_RANGE *r)
1496 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1497 struct layout_range *range;
1499 TRACE("(%p)->(%u %p %p)\n", This, position, collection, r);
1501 range = get_layout_range_by_pos(This, position);
1502 *collection = range ? range->collection : NULL;
1503 if (*collection)
1504 IDWriteFontCollection_AddRef(*collection);
1506 return return_range(range, r);
1509 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout2 *iface,
1510 UINT32 position, UINT32 *length, DWRITE_TEXT_RANGE *r)
1512 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1513 TRACE("(%p)->(%d %p %p)\n", This, position, length, r);
1514 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, length, r);
1517 static HRESULT WINAPI dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout2 *iface,
1518 UINT32 position, WCHAR *name, UINT32 length, DWRITE_TEXT_RANGE *r)
1520 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1521 TRACE("(%p)->(%u %p %u %p)\n", This, position, name, length, r);
1522 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_FONTFAMILY, position, name, length, r);
1525 static HRESULT WINAPI dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout2 *iface,
1526 UINT32 position, DWRITE_FONT_WEIGHT *weight, DWRITE_TEXT_RANGE *r)
1528 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1529 struct layout_range *range;
1531 TRACE("(%p)->(%u %p %p)\n", This, position, weight, r);
1533 if (position >= This->len)
1534 return S_OK;
1536 range = get_layout_range_by_pos(This, position);
1537 *weight = range->weight;
1539 return return_range(range, r);
1542 static HRESULT WINAPI dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout2 *iface,
1543 UINT32 position, DWRITE_FONT_STYLE *style, DWRITE_TEXT_RANGE *r)
1545 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1546 struct layout_range *range;
1548 TRACE("(%p)->(%u %p %p)\n", This, position, style, r);
1550 if (position >= This->len)
1551 return S_OK;
1553 range = get_layout_range_by_pos(This, position);
1554 *style = range->style;
1556 return return_range(range, r);
1559 static HRESULT WINAPI dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout2 *iface,
1560 UINT32 position, DWRITE_FONT_STRETCH *stretch, DWRITE_TEXT_RANGE *r)
1562 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1563 struct layout_range *range;
1565 TRACE("(%p)->(%u %p %p)\n", This, position, stretch, r);
1567 if (position >= This->len)
1568 return S_OK;
1570 range = get_layout_range_by_pos(This, position);
1571 *stretch = range->stretch;
1573 return return_range(range, r);
1576 static HRESULT WINAPI dwritetextlayout_layout_GetFontSize(IDWriteTextLayout2 *iface,
1577 UINT32 position, FLOAT *size, DWRITE_TEXT_RANGE *r)
1579 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1580 struct layout_range *range;
1582 TRACE("(%p)->(%u %p %p)\n", This, position, size, r);
1584 if (position >= This->len)
1585 return S_OK;
1587 range = get_layout_range_by_pos(This, position);
1588 *size = range->fontsize;
1590 return return_range(range, r);
1593 static HRESULT WINAPI dwritetextlayout_GetUnderline(IDWriteTextLayout2 *iface,
1594 UINT32 position, BOOL *underline, DWRITE_TEXT_RANGE *r)
1596 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1597 struct layout_range *range;
1599 TRACE("(%p)->(%u %p %p)\n", This, position, underline, r);
1601 if (position >= This->len)
1602 return S_OK;
1604 range = get_layout_range_by_pos(This, position);
1605 *underline = range->underline;
1607 return return_range(range, r);
1610 static HRESULT WINAPI dwritetextlayout_GetStrikethrough(IDWriteTextLayout2 *iface,
1611 UINT32 position, BOOL *strikethrough, DWRITE_TEXT_RANGE *r)
1613 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1614 struct layout_range *range;
1616 TRACE("(%p)->(%u %p %p)\n", This, position, strikethrough, r);
1618 if (position >= This->len)
1619 return S_OK;
1621 range = get_layout_range_by_pos(This, position);
1622 *strikethrough = range->strikethrough;
1624 return return_range(range, r);
1627 static HRESULT WINAPI dwritetextlayout_GetDrawingEffect(IDWriteTextLayout2 *iface,
1628 UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r)
1630 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1631 struct layout_range *range;
1633 TRACE("(%p)->(%u %p %p)\n", This, position, effect, r);
1635 if (position >= This->len)
1636 return S_OK;
1638 range = get_layout_range_by_pos(This, position);
1639 *effect = range->effect;
1640 if (*effect)
1641 IUnknown_AddRef(*effect);
1643 return return_range(range, r);
1646 static HRESULT WINAPI dwritetextlayout_GetInlineObject(IDWriteTextLayout2 *iface,
1647 UINT32 position, IDWriteInlineObject **object, DWRITE_TEXT_RANGE *r)
1649 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1650 struct layout_range *range;
1652 TRACE("(%p)->(%u %p %p)\n", This, position, object, r);
1654 range = get_layout_range_by_pos(This, position);
1655 *object = range ? range->object : NULL;
1656 if (*object)
1657 IDWriteInlineObject_AddRef(*object);
1659 return return_range(range, r);
1662 static HRESULT WINAPI dwritetextlayout_GetTypography(IDWriteTextLayout2 *iface,
1663 UINT32 position, IDWriteTypography** typography, DWRITE_TEXT_RANGE *range)
1665 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1666 FIXME("(%p)->(%u %p %p): stub\n", This, position, typography, range);
1667 return E_NOTIMPL;
1670 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout2 *iface,
1671 UINT32 position, UINT32* length, DWRITE_TEXT_RANGE *r)
1673 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1674 TRACE("(%p)->(%u %p %p)\n", This, position, length, r);
1675 return get_string_attribute_length(This, LAYOUT_RANGE_ATTR_LOCALE, position, length, r);
1678 static HRESULT WINAPI dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout2 *iface,
1679 UINT32 position, WCHAR* locale, UINT32 length, DWRITE_TEXT_RANGE *r)
1681 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1682 TRACE("(%p)->(%u %p %u %p)\n", This, position, locale, length, r);
1683 return get_string_attribute_value(This, LAYOUT_RANGE_ATTR_LOCALE, position, locale, length, r);
1686 static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface,
1687 void *context, IDWriteTextRenderer* renderer, FLOAT originX, FLOAT originY)
1689 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1690 FIXME("(%p)->(%p %p %f %f): stub\n", This, context, renderer, originX, originY);
1691 return E_NOTIMPL;
1694 static HRESULT WINAPI dwritetextlayout_GetLineMetrics(IDWriteTextLayout2 *iface,
1695 DWRITE_LINE_METRICS *metrics, UINT32 max_count, UINT32 *actual_count)
1697 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1698 FIXME("(%p)->(%p %u %p): stub\n", This, metrics, max_count, actual_count);
1699 return E_NOTIMPL;
1702 static HRESULT WINAPI dwritetextlayout_GetMetrics(IDWriteTextLayout2 *iface, DWRITE_TEXT_METRICS *metrics)
1704 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1705 FIXME("(%p)->(%p): stub\n", This, metrics);
1706 return E_NOTIMPL;
1709 static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout2 *iface, DWRITE_OVERHANG_METRICS *overhangs)
1711 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1712 FIXME("(%p)->(%p): stub\n", This, overhangs);
1713 return E_NOTIMPL;
1716 static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout2 *iface,
1717 DWRITE_CLUSTER_METRICS *metrics, UINT32 max_count, UINT32 *count)
1719 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1720 HRESULT hr;
1722 TRACE("(%p)->(%p %u %p)\n", This, metrics, max_count, count);
1724 hr = layout_compute(This);
1725 if (FAILED(hr))
1726 return hr;
1728 if (metrics)
1729 memcpy(metrics, This->clusters, sizeof(DWRITE_CLUSTER_METRICS)*min(max_count, This->clusters_count));
1731 *count = This->clusters_count;
1732 return max_count < This->clusters_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
1735 static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout2 *iface, FLOAT* min_width)
1737 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1738 FIXME("(%p)->(%p): stub\n", This, min_width);
1739 return E_NOTIMPL;
1742 static HRESULT WINAPI dwritetextlayout_HitTestPoint(IDWriteTextLayout2 *iface,
1743 FLOAT pointX, FLOAT pointY, BOOL* is_trailinghit, BOOL* is_inside, DWRITE_HIT_TEST_METRICS *metrics)
1745 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1746 FIXME("(%p)->(%f %f %p %p %p): stub\n", This, pointX, pointY, is_trailinghit, is_inside, metrics);
1747 return E_NOTIMPL;
1750 static HRESULT WINAPI dwritetextlayout_HitTestTextPosition(IDWriteTextLayout2 *iface,
1751 UINT32 textPosition, BOOL is_trailinghit, FLOAT* pointX, FLOAT* pointY, DWRITE_HIT_TEST_METRICS *metrics)
1753 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1754 FIXME("(%p)->(%u %d %p %p %p): stub\n", This, textPosition, is_trailinghit, pointX, pointY, metrics);
1755 return E_NOTIMPL;
1758 static HRESULT WINAPI dwritetextlayout_HitTestTextRange(IDWriteTextLayout2 *iface,
1759 UINT32 textPosition, UINT32 textLength, FLOAT originX, FLOAT originY,
1760 DWRITE_HIT_TEST_METRICS *metrics, UINT32 max_metricscount, UINT32* actual_metricscount)
1762 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1763 FIXME("(%p)->(%u %u %f %f %p %u %p): stub\n", This, textPosition, textLength, originX, originY, metrics,
1764 max_metricscount, actual_metricscount);
1765 return E_NOTIMPL;
1768 static HRESULT WINAPI dwritetextlayout1_SetPairKerning(IDWriteTextLayout2 *iface, BOOL is_pairkerning_enabled,
1769 DWRITE_TEXT_RANGE range)
1771 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1772 struct layout_range_attr_value value;
1774 TRACE("(%p)->(%d %s)\n", This, is_pairkerning_enabled, debugstr_range(&range));
1776 value.range = range;
1777 value.u.pair_kerning = !!is_pairkerning_enabled;
1778 return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_PAIR_KERNING, &value);
1781 static HRESULT WINAPI dwritetextlayout1_GetPairKerning(IDWriteTextLayout2 *iface, UINT32 position, BOOL *is_pairkerning_enabled,
1782 DWRITE_TEXT_RANGE *r)
1784 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1785 struct layout_range *range;
1787 TRACE("(%p)->(%u %p %p)\n", This, position, is_pairkerning_enabled, r);
1789 if (position >= This->len)
1790 return S_OK;
1792 range = get_layout_range_by_pos(This, position);
1793 *is_pairkerning_enabled = range->pair_kerning;
1795 return return_range(range, r);
1798 static HRESULT WINAPI dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout2 *iface, FLOAT leading_spacing, FLOAT trailing_spacing,
1799 FLOAT minimum_advance_width, DWRITE_TEXT_RANGE range)
1801 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1802 FIXME("(%p)->(%f %f %f %s): stub\n", This, leading_spacing, trailing_spacing, minimum_advance_width, debugstr_range(&range));
1803 return E_NOTIMPL;
1806 static HRESULT WINAPI dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout2 *iface, UINT32 position, FLOAT* leading_spacing,
1807 FLOAT* trailing_spacing, FLOAT* minimum_advance_width, DWRITE_TEXT_RANGE *range)
1809 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1810 FIXME("(%p)->(%u %p %p %p %p): stub\n", This, position, leading_spacing, trailing_spacing, minimum_advance_width, range);
1811 return E_NOTIMPL;
1814 static HRESULT WINAPI dwritetextlayout2_GetMetrics(IDWriteTextLayout2 *iface, DWRITE_TEXT_METRICS1 *metrics)
1816 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1817 FIXME("(%p)->(%p): stub\n", This, metrics);
1818 return E_NOTIMPL;
1821 static HRESULT WINAPI dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout2 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
1823 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1824 FIXME("(%p)->(%d): stub\n", This, orientation);
1825 return E_NOTIMPL;
1828 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout2 *iface)
1830 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1831 FIXME("(%p): stub\n", This);
1832 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
1835 static HRESULT WINAPI dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout2 *iface, BOOL lastline_wrapping_enabled)
1837 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1838 FIXME("(%p)->(%d): stub\n", This, lastline_wrapping_enabled);
1839 return E_NOTIMPL;
1842 static BOOL WINAPI dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout2 *iface)
1844 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1845 FIXME("(%p): stub\n", This);
1846 return FALSE;
1849 static HRESULT WINAPI dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout2 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
1851 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1852 FIXME("(%p)->(%d): stub\n", This, alignment);
1853 return E_NOTIMPL;
1856 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout2 *iface)
1858 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1859 FIXME("(%p): stub\n", This);
1860 return DWRITE_OPTICAL_ALIGNMENT_NONE;
1863 static HRESULT WINAPI dwritetextlayout2_SetFontFallback(IDWriteTextLayout2 *iface, IDWriteFontFallback *fallback)
1865 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1866 FIXME("(%p)->(%p): stub\n", This, fallback);
1867 return E_NOTIMPL;
1870 static HRESULT WINAPI dwritetextlayout2_GetFontFallback(IDWriteTextLayout2 *iface, IDWriteFontFallback **fallback)
1872 struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
1873 FIXME("(%p)->(%p): stub\n", This, fallback);
1874 return E_NOTIMPL;
1877 static const IDWriteTextLayout2Vtbl dwritetextlayoutvtbl = {
1878 dwritetextlayout_QueryInterface,
1879 dwritetextlayout_AddRef,
1880 dwritetextlayout_Release,
1881 dwritetextlayout_SetTextAlignment,
1882 dwritetextlayout_SetParagraphAlignment,
1883 dwritetextlayout_SetWordWrapping,
1884 dwritetextlayout_SetReadingDirection,
1885 dwritetextlayout_SetFlowDirection,
1886 dwritetextlayout_SetIncrementalTabStop,
1887 dwritetextlayout_SetTrimming,
1888 dwritetextlayout_SetLineSpacing,
1889 dwritetextlayout_GetTextAlignment,
1890 dwritetextlayout_GetParagraphAlignment,
1891 dwritetextlayout_GetWordWrapping,
1892 dwritetextlayout_GetReadingDirection,
1893 dwritetextlayout_GetFlowDirection,
1894 dwritetextlayout_GetIncrementalTabStop,
1895 dwritetextlayout_GetTrimming,
1896 dwritetextlayout_GetLineSpacing,
1897 dwritetextlayout_GetFontCollection,
1898 dwritetextlayout_GetFontFamilyNameLength,
1899 dwritetextlayout_GetFontFamilyName,
1900 dwritetextlayout_GetFontWeight,
1901 dwritetextlayout_GetFontStyle,
1902 dwritetextlayout_GetFontStretch,
1903 dwritetextlayout_GetFontSize,
1904 dwritetextlayout_GetLocaleNameLength,
1905 dwritetextlayout_GetLocaleName,
1906 dwritetextlayout_SetMaxWidth,
1907 dwritetextlayout_SetMaxHeight,
1908 dwritetextlayout_SetFontCollection,
1909 dwritetextlayout_SetFontFamilyName,
1910 dwritetextlayout_SetFontWeight,
1911 dwritetextlayout_SetFontStyle,
1912 dwritetextlayout_SetFontStretch,
1913 dwritetextlayout_SetFontSize,
1914 dwritetextlayout_SetUnderline,
1915 dwritetextlayout_SetStrikethrough,
1916 dwritetextlayout_SetDrawingEffect,
1917 dwritetextlayout_SetInlineObject,
1918 dwritetextlayout_SetTypography,
1919 dwritetextlayout_SetLocaleName,
1920 dwritetextlayout_GetMaxWidth,
1921 dwritetextlayout_GetMaxHeight,
1922 dwritetextlayout_layout_GetFontCollection,
1923 dwritetextlayout_layout_GetFontFamilyNameLength,
1924 dwritetextlayout_layout_GetFontFamilyName,
1925 dwritetextlayout_layout_GetFontWeight,
1926 dwritetextlayout_layout_GetFontStyle,
1927 dwritetextlayout_layout_GetFontStretch,
1928 dwritetextlayout_layout_GetFontSize,
1929 dwritetextlayout_GetUnderline,
1930 dwritetextlayout_GetStrikethrough,
1931 dwritetextlayout_GetDrawingEffect,
1932 dwritetextlayout_GetInlineObject,
1933 dwritetextlayout_GetTypography,
1934 dwritetextlayout_layout_GetLocaleNameLength,
1935 dwritetextlayout_layout_GetLocaleName,
1936 dwritetextlayout_Draw,
1937 dwritetextlayout_GetLineMetrics,
1938 dwritetextlayout_GetMetrics,
1939 dwritetextlayout_GetOverhangMetrics,
1940 dwritetextlayout_GetClusterMetrics,
1941 dwritetextlayout_DetermineMinWidth,
1942 dwritetextlayout_HitTestPoint,
1943 dwritetextlayout_HitTestTextPosition,
1944 dwritetextlayout_HitTestTextRange,
1945 dwritetextlayout1_SetPairKerning,
1946 dwritetextlayout1_GetPairKerning,
1947 dwritetextlayout1_SetCharacterSpacing,
1948 dwritetextlayout1_GetCharacterSpacing,
1949 dwritetextlayout2_GetMetrics,
1950 dwritetextlayout2_SetVerticalGlyphOrientation,
1951 dwritetextlayout2_GetVerticalGlyphOrientation,
1952 dwritetextlayout2_SetLastLineWrapping,
1953 dwritetextlayout2_GetLastLineWrapping,
1954 dwritetextlayout2_SetOpticalAlignment,
1955 dwritetextlayout2_GetOpticalAlignment,
1956 dwritetextlayout2_SetFontFallback,
1957 dwritetextlayout2_GetFontFallback
1960 static HRESULT WINAPI dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink *iface,
1961 REFIID riid, void **obj)
1963 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) || IsEqualIID(riid, &IID_IUnknown)) {
1964 *obj = iface;
1965 IDWriteTextAnalysisSink_AddRef(iface);
1966 return S_OK;
1969 *obj = NULL;
1970 return E_NOINTERFACE;
1973 static ULONG WINAPI dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink *iface)
1975 return 2;
1978 static ULONG WINAPI dwritetextlayout_sink_Release(IDWriteTextAnalysisSink *iface)
1980 return 1;
1983 static HRESULT WINAPI dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink *iface,
1984 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
1986 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
1987 struct layout_run *run;
1989 TRACE("%u %u script=%d\n", position, length, sa->script);
1991 run = alloc_layout_run();
1992 if (!run)
1993 return E_OUTOFMEMORY;
1995 run->descr.string = &layout->str[position];
1996 run->descr.stringLength = length;
1997 run->descr.textPosition = position;
1998 run->sa = *sa;
1999 list_add_head(&layout->runs, &run->entry);
2000 return S_OK;
2003 static HRESULT WINAPI dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink *iface,
2004 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
2006 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
2008 if (position + length > layout->len)
2009 return E_FAIL;
2011 memcpy(&layout->nominal_breakpoints[position], breakpoints, length*sizeof(DWRITE_LINE_BREAKPOINT));
2012 return S_OK;
2015 static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink *iface, UINT32 position,
2016 UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
2018 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
2019 struct layout_run *cur;
2021 LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
2022 struct layout_run *run, *run2;
2024 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
2025 if (position < cur->descr.textPosition || position > cur->descr.textPosition + cur->descr.stringLength)
2026 continue;
2028 /* full hit - just set run level */
2029 if (cur->descr.textPosition == position && cur->descr.stringLength == length) {
2030 cur->run.bidiLevel = resolvedLevel;
2031 break;
2034 /* current run is fully covered, move to next one */
2035 if (cur->descr.textPosition == position && cur->descr.stringLength < length) {
2036 cur->run.bidiLevel = resolvedLevel;
2037 position += cur->descr.stringLength;
2038 length -= cur->descr.stringLength;
2039 continue;
2042 /* now starting point is in a run, so it splits it */
2043 run = alloc_layout_run();
2044 if (!run)
2045 return E_OUTOFMEMORY;
2047 *run = *cur;
2048 run->descr.textPosition = position;
2049 run->descr.stringLength = cur->descr.stringLength - position + cur->descr.textPosition;
2050 run->descr.string = &layout->str[position];
2051 run->run.bidiLevel = resolvedLevel;
2052 cur->descr.stringLength -= position - cur->descr.textPosition;
2054 list_add_after(&cur->entry, &run->entry);
2056 if (position + length == run->descr.textPosition + run->descr.stringLength)
2057 break;
2059 /* split second time */
2060 run2 = alloc_layout_run();
2061 if (!run2)
2062 return E_OUTOFMEMORY;
2064 *run2 = *cur;
2065 run2->descr.textPosition = run->descr.textPosition + run->descr.stringLength;
2066 run2->descr.stringLength = cur->descr.textPosition + cur->descr.stringLength - position - length;
2067 run2->descr.string = &layout->str[run2->descr.textPosition];
2068 run->descr.stringLength -= run2->descr.stringLength;
2070 list_add_after(&run->entry, &run2->entry);
2071 break;
2074 return S_OK;
2077 static HRESULT WINAPI dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink *iface,
2078 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
2080 return E_NOTIMPL;
2083 static const IDWriteTextAnalysisSinkVtbl dwritetextlayoutsinkvtbl = {
2084 dwritetextlayout_sink_QueryInterface,
2085 dwritetextlayout_sink_AddRef,
2086 dwritetextlayout_sink_Release,
2087 dwritetextlayout_sink_SetScriptAnalysis,
2088 dwritetextlayout_sink_SetLineBreakpoints,
2089 dwritetextlayout_sink_SetBidiLevel,
2090 dwritetextlayout_sink_SetNumberSubstitution
2093 static HRESULT WINAPI dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource *iface,
2094 REFIID riid, void **obj)
2096 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) ||
2097 IsEqualIID(riid, &IID_IUnknown))
2099 *obj = iface;
2100 IDWriteTextAnalysisSource_AddRef(iface);
2101 return S_OK;
2104 *obj = NULL;
2105 return E_NOINTERFACE;
2108 static ULONG WINAPI dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource *iface)
2110 return 2;
2113 static ULONG WINAPI dwritetextlayout_source_Release(IDWriteTextAnalysisSource *iface)
2115 return 1;
2118 static HRESULT WINAPI dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource *iface,
2119 UINT32 position, WCHAR const** text, UINT32* text_len)
2121 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource(iface);
2123 TRACE("(%p)->(%u %p %p)\n", layout, position, text, text_len);
2125 if (position < layout->len) {
2126 *text = &layout->str[position];
2127 *text_len = layout->len - position;
2129 else {
2130 *text = NULL;
2131 *text_len = 0;
2134 return S_OK;
2137 static HRESULT WINAPI dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource *iface,
2138 UINT32 position, WCHAR const** text, UINT32* text_len)
2140 FIXME("%u %p %p: stub\n", position, text, text_len);
2141 return E_NOTIMPL;
2144 static DWRITE_READING_DIRECTION WINAPI dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource *iface)
2146 struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSource(iface);
2147 return IDWriteTextLayout2_GetReadingDirection(&layout->IDWriteTextLayout2_iface);
2150 static HRESULT WINAPI dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource *iface,
2151 UINT32 position, UINT32* text_len, WCHAR const** locale)
2153 FIXME("%u %p %p: stub\n", position, text_len, locale);
2154 return E_NOTIMPL;
2157 static HRESULT WINAPI dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource *iface,
2158 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
2160 FIXME("%u %p %p: stub\n", position, text_len, substitution);
2161 return E_NOTIMPL;
2164 static const IDWriteTextAnalysisSourceVtbl dwritetextlayoutsourcevtbl = {
2165 dwritetextlayout_source_QueryInterface,
2166 dwritetextlayout_source_AddRef,
2167 dwritetextlayout_source_Release,
2168 dwritetextlayout_source_GetTextAtPosition,
2169 dwritetextlayout_source_GetTextBeforePosition,
2170 dwritetextlayout_source_GetParagraphReadingDirection,
2171 dwritetextlayout_source_GetLocaleName,
2172 dwritetextlayout_source_GetNumberSubstitution
2175 static HRESULT layout_format_from_textformat(struct dwrite_textlayout *layout, IDWriteTextFormat *format)
2177 UINT32 len;
2178 HRESULT hr;
2180 layout->format.weight = IDWriteTextFormat_GetFontWeight(format);
2181 layout->format.style = IDWriteTextFormat_GetFontStyle(format);
2182 layout->format.stretch = IDWriteTextFormat_GetFontStretch(format);
2183 layout->format.fontsize= IDWriteTextFormat_GetFontSize(format);
2184 layout->format.textalignment = IDWriteTextFormat_GetTextAlignment(format);
2185 layout->format.paralign = IDWriteTextFormat_GetParagraphAlignment(format);
2186 layout->format.wrapping = IDWriteTextFormat_GetWordWrapping(format);
2187 layout->format.readingdir = IDWriteTextFormat_GetReadingDirection(format);
2188 layout->format.flow = IDWriteTextFormat_GetFlowDirection(format);
2189 hr = IDWriteTextFormat_GetLineSpacing(format, &layout->format.spacingmethod,
2190 &layout->format.spacing, &layout->format.baseline);
2191 if (FAILED(hr))
2192 return hr;
2194 hr = IDWriteTextFormat_GetTrimming(format, &layout->format.trimming, &layout->format.trimmingsign);
2195 if (FAILED(hr))
2196 return hr;
2198 /* locale name and length */
2199 len = IDWriteTextFormat_GetLocaleNameLength(format);
2200 layout->format.locale = heap_alloc((len+1)*sizeof(WCHAR));
2201 if (!layout->format.locale)
2202 return E_OUTOFMEMORY;
2204 hr = IDWriteTextFormat_GetLocaleName(format, layout->format.locale, len+1);
2205 if (FAILED(hr))
2206 return hr;
2207 layout->format.locale_len = len;
2209 /* font family name and length */
2210 len = IDWriteTextFormat_GetFontFamilyNameLength(format);
2211 layout->format.family_name = heap_alloc((len+1)*sizeof(WCHAR));
2212 if (!layout->format.family_name)
2213 return E_OUTOFMEMORY;
2215 hr = IDWriteTextFormat_GetFontFamilyName(format, layout->format.family_name, len+1);
2216 if (FAILED(hr))
2217 return hr;
2218 layout->format.family_len = len;
2220 return IDWriteTextFormat_GetFontCollection(format, &layout->format.collection);
2223 static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, struct dwrite_textlayout *layout)
2225 DWRITE_TEXT_RANGE r = { 0, len };
2226 struct layout_range *range;
2227 HRESULT hr;
2229 layout->IDWriteTextLayout2_iface.lpVtbl = &dwritetextlayoutvtbl;
2230 layout->IDWriteTextAnalysisSink_iface.lpVtbl = &dwritetextlayoutsinkvtbl;
2231 layout->IDWriteTextAnalysisSource_iface.lpVtbl = &dwritetextlayoutsourcevtbl;
2232 layout->ref = 1;
2233 layout->len = len;
2234 layout->maxwidth = maxwidth;
2235 layout->maxheight = maxheight;
2236 layout->recompute = TRUE;
2237 layout->nominal_breakpoints = NULL;
2238 layout->actual_breakpoints = NULL;
2239 layout->clusters_count = 0;
2240 layout->clusters = NULL;
2241 list_init(&layout->runs);
2242 list_init(&layout->ranges);
2243 memset(&layout->format, 0, sizeof(layout->format));
2245 layout->gdicompatible = FALSE;
2246 layout->pixels_per_dip = 0.0;
2247 layout->use_gdi_natural = FALSE;
2248 memset(&layout->transform, 0, sizeof(layout->transform));
2250 layout->str = heap_strdupnW(str, len);
2251 if (len && !layout->str) {
2252 hr = E_OUTOFMEMORY;
2253 goto fail;
2256 hr = layout_format_from_textformat(layout, format);
2257 if (FAILED(hr))
2258 goto fail;
2260 range = alloc_layout_range(layout, &r);
2261 if (!range) {
2262 hr = E_OUTOFMEMORY;
2263 goto fail;
2266 list_add_head(&layout->ranges, &range->entry);
2267 return S_OK;
2269 fail:
2270 IDWriteTextLayout2_Release(&layout->IDWriteTextLayout2_iface);
2271 return hr;
2274 HRESULT create_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, IDWriteTextLayout **ret)
2276 struct dwrite_textlayout *layout;
2277 HRESULT hr;
2279 *ret = NULL;
2281 layout = heap_alloc(sizeof(struct dwrite_textlayout));
2282 if (!layout) return E_OUTOFMEMORY;
2284 hr = init_textlayout(str, len, format, maxwidth, maxheight, layout);
2285 if (hr == S_OK)
2286 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout2_iface;
2288 return hr;
2291 HRESULT create_gdicompat_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight,
2292 FLOAT pixels_per_dip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural, IDWriteTextLayout **ret)
2294 struct dwrite_textlayout *layout;
2295 HRESULT hr;
2297 *ret = NULL;
2299 layout = heap_alloc(sizeof(struct dwrite_textlayout));
2300 if (!layout) return E_OUTOFMEMORY;
2302 hr = init_textlayout(str, len, format, maxwidth, maxheight, layout);
2303 if (hr == S_OK) {
2304 /* set gdi-specific properties */
2305 layout->gdicompatible = TRUE;
2306 layout->pixels_per_dip = pixels_per_dip;
2307 layout->use_gdi_natural = use_gdi_natural;
2308 layout->transform = transform ? *transform : identity;
2310 *ret = (IDWriteTextLayout*)&layout->IDWriteTextLayout2_iface;
2313 return hr;
2316 static HRESULT WINAPI dwritetrimmingsign_QueryInterface(IDWriteInlineObject *iface, REFIID riid, void **obj)
2318 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
2320 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2322 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteInlineObject)) {
2323 *obj = iface;
2324 IDWriteInlineObject_AddRef(iface);
2325 return S_OK;
2328 *obj = NULL;
2329 return E_NOINTERFACE;
2333 static ULONG WINAPI dwritetrimmingsign_AddRef(IDWriteInlineObject *iface)
2335 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
2336 ULONG ref = InterlockedIncrement(&This->ref);
2337 TRACE("(%p)->(%d)\n", This, ref);
2338 return ref;
2341 static ULONG WINAPI dwritetrimmingsign_Release(IDWriteInlineObject *iface)
2343 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
2344 ULONG ref = InterlockedDecrement(&This->ref);
2346 TRACE("(%p)->(%d)\n", This, ref);
2348 if (!ref)
2349 heap_free(This);
2351 return ref;
2354 static HRESULT WINAPI dwritetrimmingsign_Draw(IDWriteInlineObject *iface, void *context, IDWriteTextRenderer *renderer,
2355 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *drawing_effect)
2357 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
2358 FIXME("(%p)->(%p %p %f %f %d %d %p): stub\n", This, context, renderer, originX, originY, is_sideways, is_rtl, drawing_effect);
2359 return E_NOTIMPL;
2362 static HRESULT WINAPI dwritetrimmingsign_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *metrics)
2364 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
2365 FIXME("(%p)->(%p): stub\n", This, metrics);
2366 return E_NOTIMPL;
2369 static HRESULT WINAPI dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
2371 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
2372 FIXME("(%p)->(%p): stub\n", This, overhangs);
2373 return E_NOTIMPL;
2376 static HRESULT WINAPI dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
2377 DWRITE_BREAK_CONDITION *after)
2379 struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
2381 TRACE("(%p)->(%p %p)\n", This, before, after);
2383 *before = *after = DWRITE_BREAK_CONDITION_NEUTRAL;
2384 return S_OK;
2387 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl = {
2388 dwritetrimmingsign_QueryInterface,
2389 dwritetrimmingsign_AddRef,
2390 dwritetrimmingsign_Release,
2391 dwritetrimmingsign_Draw,
2392 dwritetrimmingsign_GetMetrics,
2393 dwritetrimmingsign_GetOverhangMetrics,
2394 dwritetrimmingsign_GetBreakConditions
2397 HRESULT create_trimmingsign(IDWriteInlineObject **sign)
2399 struct dwrite_trimmingsign *This;
2401 *sign = NULL;
2403 This = heap_alloc(sizeof(struct dwrite_trimmingsign));
2404 if (!This) return E_OUTOFMEMORY;
2406 This->IDWriteInlineObject_iface.lpVtbl = &dwritetrimmingsignvtbl;
2407 This->ref = 1;
2409 *sign = &This->IDWriteInlineObject_iface;
2411 return S_OK;
2414 static HRESULT WINAPI dwritetextformat_QueryInterface(IDWriteTextFormat1 *iface, REFIID riid, void **obj)
2416 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2418 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2420 if (IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
2421 IsEqualIID(riid, &IID_IDWriteTextFormat) ||
2422 IsEqualIID(riid, &IID_IUnknown))
2424 *obj = iface;
2425 IDWriteTextFormat1_AddRef(iface);
2426 return S_OK;
2429 *obj = NULL;
2431 return E_NOINTERFACE;
2434 static ULONG WINAPI dwritetextformat_AddRef(IDWriteTextFormat1 *iface)
2436 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2437 ULONG ref = InterlockedIncrement(&This->ref);
2438 TRACE("(%p)->(%d)\n", This, ref);
2439 return ref;
2442 static ULONG WINAPI dwritetextformat_Release(IDWriteTextFormat1 *iface)
2444 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2445 ULONG ref = InterlockedDecrement(&This->ref);
2447 TRACE("(%p)->(%d)\n", This, ref);
2449 if (!ref)
2451 release_format_data(&This->format);
2452 heap_free(This);
2455 return ref;
2458 static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
2460 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2461 TRACE("(%p)->(%d)\n", This, alignment);
2462 This->format.textalignment = alignment;
2463 return S_OK;
2466 static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
2468 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2469 TRACE("(%p)->(%d)\n", This, alignment);
2470 This->format.paralign = alignment;
2471 return S_OK;
2474 static HRESULT WINAPI dwritetextformat_SetWordWrapping(IDWriteTextFormat1 *iface, DWRITE_WORD_WRAPPING wrapping)
2476 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2477 TRACE("(%p)->(%d)\n", This, wrapping);
2478 This->format.wrapping = wrapping;
2479 return S_OK;
2482 static HRESULT WINAPI dwritetextformat_SetReadingDirection(IDWriteTextFormat1 *iface, DWRITE_READING_DIRECTION direction)
2484 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2485 TRACE("(%p)->(%d)\n", This, direction);
2486 This->format.readingdir = direction;
2487 return S_OK;
2490 static HRESULT WINAPI dwritetextformat_SetFlowDirection(IDWriteTextFormat1 *iface, DWRITE_FLOW_DIRECTION direction)
2492 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2493 TRACE("(%p)->(%d)\n", This, direction);
2494 This->format.flow = direction;
2495 return S_OK;
2498 static HRESULT WINAPI dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat1 *iface, FLOAT tabstop)
2500 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2501 FIXME("(%p)->(%f): stub\n", This, tabstop);
2502 return E_NOTIMPL;
2505 static HRESULT WINAPI dwritetextformat_SetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING const *trimming,
2506 IDWriteInlineObject *trimming_sign)
2508 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2509 TRACE("(%p)->(%p %p)\n", This, trimming, trimming_sign);
2511 This->format.trimming = *trimming;
2512 if (This->format.trimmingsign)
2513 IDWriteInlineObject_Release(This->format.trimmingsign);
2514 This->format.trimmingsign = trimming_sign;
2515 if (This->format.trimmingsign)
2516 IDWriteInlineObject_AddRef(This->format.trimmingsign);
2517 return S_OK;
2520 static HRESULT WINAPI dwritetextformat_SetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD method,
2521 FLOAT spacing, FLOAT baseline)
2523 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2524 TRACE("(%p)->(%d %f %f)\n", This, method, spacing, baseline);
2525 This->format.spacingmethod = method;
2526 This->format.spacing = spacing;
2527 This->format.baseline = baseline;
2528 return S_OK;
2531 static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_GetTextAlignment(IDWriteTextFormat1 *iface)
2533 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2534 TRACE("(%p)\n", This);
2535 return This->format.textalignment;
2538 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_GetParagraphAlignment(IDWriteTextFormat1 *iface)
2540 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2541 TRACE("(%p)\n", This);
2542 return This->format.paralign;
2545 static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_GetWordWrapping(IDWriteTextFormat1 *iface)
2547 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2548 TRACE("(%p)\n", This);
2549 return This->format.wrapping;
2552 static DWRITE_READING_DIRECTION WINAPI dwritetextformat_GetReadingDirection(IDWriteTextFormat1 *iface)
2554 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2555 TRACE("(%p)\n", This);
2556 return This->format.readingdir;
2559 static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_GetFlowDirection(IDWriteTextFormat1 *iface)
2561 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2562 TRACE("(%p)\n", This);
2563 return This->format.flow;
2566 static FLOAT WINAPI dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat1 *iface)
2568 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2569 FIXME("(%p): stub\n", This);
2570 return 0.0;
2573 static HRESULT WINAPI dwritetextformat_GetTrimming(IDWriteTextFormat1 *iface, DWRITE_TRIMMING *options,
2574 IDWriteInlineObject **trimming_sign)
2576 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2577 TRACE("(%p)->(%p %p)\n", This, options, trimming_sign);
2579 *options = This->format.trimming;
2580 if ((*trimming_sign = This->format.trimmingsign))
2581 IDWriteInlineObject_AddRef(*trimming_sign);
2583 return S_OK;
2586 static HRESULT WINAPI dwritetextformat_GetLineSpacing(IDWriteTextFormat1 *iface, DWRITE_LINE_SPACING_METHOD *method,
2587 FLOAT *spacing, FLOAT *baseline)
2589 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2590 TRACE("(%p)->(%p %p %p)\n", This, method, spacing, baseline);
2592 *method = This->format.spacingmethod;
2593 *spacing = This->format.spacing;
2594 *baseline = This->format.baseline;
2595 return S_OK;
2598 static HRESULT WINAPI dwritetextformat_GetFontCollection(IDWriteTextFormat1 *iface, IDWriteFontCollection **collection)
2600 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2602 TRACE("(%p)->(%p)\n", This, collection);
2604 *collection = This->format.collection;
2605 IDWriteFontCollection_AddRef(*collection);
2607 return S_OK;
2610 static UINT32 WINAPI dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat1 *iface)
2612 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2613 TRACE("(%p)\n", This);
2614 return This->format.family_len;
2617 static HRESULT WINAPI dwritetextformat_GetFontFamilyName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
2619 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2621 TRACE("(%p)->(%p %u)\n", This, name, size);
2623 if (size <= This->format.family_len) return E_NOT_SUFFICIENT_BUFFER;
2624 strcpyW(name, This->format.family_name);
2625 return S_OK;
2628 static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_GetFontWeight(IDWriteTextFormat1 *iface)
2630 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2631 TRACE("(%p)\n", This);
2632 return This->format.weight;
2635 static DWRITE_FONT_STYLE WINAPI dwritetextformat_GetFontStyle(IDWriteTextFormat1 *iface)
2637 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2638 TRACE("(%p)\n", This);
2639 return This->format.style;
2642 static DWRITE_FONT_STRETCH WINAPI dwritetextformat_GetFontStretch(IDWriteTextFormat1 *iface)
2644 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2645 TRACE("(%p)\n", This);
2646 return This->format.stretch;
2649 static FLOAT WINAPI dwritetextformat_GetFontSize(IDWriteTextFormat1 *iface)
2651 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2652 TRACE("(%p)\n", This);
2653 return This->format.fontsize;
2656 static UINT32 WINAPI dwritetextformat_GetLocaleNameLength(IDWriteTextFormat1 *iface)
2658 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2659 TRACE("(%p)\n", This);
2660 return This->format.locale_len;
2663 static HRESULT WINAPI dwritetextformat_GetLocaleName(IDWriteTextFormat1 *iface, WCHAR *name, UINT32 size)
2665 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2667 TRACE("(%p)->(%p %u)\n", This, name, size);
2669 if (size <= This->format.locale_len) return E_NOT_SUFFICIENT_BUFFER;
2670 strcpyW(name, This->format.locale);
2671 return S_OK;
2674 static HRESULT WINAPI dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat1 *iface, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
2676 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2677 FIXME("(%p)->(%d): stub\n", This, orientation);
2678 return E_NOTIMPL;
2681 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat1 *iface)
2683 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2684 FIXME("(%p): stub\n", This);
2685 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT;
2688 static HRESULT WINAPI dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat1 *iface, BOOL lastline_wrapping_enabled)
2690 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2691 FIXME("(%p)->(%d): stub\n", This, lastline_wrapping_enabled);
2692 return E_NOTIMPL;
2695 static BOOL WINAPI dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat1 *iface)
2697 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2698 FIXME("(%p): stub\n", This);
2699 return FALSE;
2702 static HRESULT WINAPI dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat1 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
2704 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2705 FIXME("(%p)->(%d): stub\n", This, alignment);
2706 return E_NOTIMPL;
2709 static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat1 *iface)
2711 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2712 FIXME("(%p): stub\n", This);
2713 return DWRITE_OPTICAL_ALIGNMENT_NONE;
2716 static HRESULT WINAPI dwritetextformat1_SetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback *fallback)
2718 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2719 FIXME("(%p)->(%p): stub\n", This, fallback);
2720 return E_NOTIMPL;
2723 static HRESULT WINAPI dwritetextformat1_GetFontFallback(IDWriteTextFormat1 *iface, IDWriteFontFallback **fallback)
2725 struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
2726 FIXME("(%p)->(%p): stub\n", This, fallback);
2727 return E_NOTIMPL;
2730 static const IDWriteTextFormat1Vtbl dwritetextformatvtbl = {
2731 dwritetextformat_QueryInterface,
2732 dwritetextformat_AddRef,
2733 dwritetextformat_Release,
2734 dwritetextformat_SetTextAlignment,
2735 dwritetextformat_SetParagraphAlignment,
2736 dwritetextformat_SetWordWrapping,
2737 dwritetextformat_SetReadingDirection,
2738 dwritetextformat_SetFlowDirection,
2739 dwritetextformat_SetIncrementalTabStop,
2740 dwritetextformat_SetTrimming,
2741 dwritetextformat_SetLineSpacing,
2742 dwritetextformat_GetTextAlignment,
2743 dwritetextformat_GetParagraphAlignment,
2744 dwritetextformat_GetWordWrapping,
2745 dwritetextformat_GetReadingDirection,
2746 dwritetextformat_GetFlowDirection,
2747 dwritetextformat_GetIncrementalTabStop,
2748 dwritetextformat_GetTrimming,
2749 dwritetextformat_GetLineSpacing,
2750 dwritetextformat_GetFontCollection,
2751 dwritetextformat_GetFontFamilyNameLength,
2752 dwritetextformat_GetFontFamilyName,
2753 dwritetextformat_GetFontWeight,
2754 dwritetextformat_GetFontStyle,
2755 dwritetextformat_GetFontStretch,
2756 dwritetextformat_GetFontSize,
2757 dwritetextformat_GetLocaleNameLength,
2758 dwritetextformat_GetLocaleName,
2759 dwritetextformat1_SetVerticalGlyphOrientation,
2760 dwritetextformat1_GetVerticalGlyphOrientation,
2761 dwritetextformat1_SetLastLineWrapping,
2762 dwritetextformat1_GetLastLineWrapping,
2763 dwritetextformat1_SetOpticalAlignment,
2764 dwritetextformat1_GetOpticalAlignment,
2765 dwritetextformat1_SetFontFallback,
2766 dwritetextformat1_GetFontFallback
2769 HRESULT create_textformat(const WCHAR *family_name, IDWriteFontCollection *collection, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style,
2770 DWRITE_FONT_STRETCH stretch, FLOAT size, const WCHAR *locale, IDWriteTextFormat **format)
2772 struct dwrite_textformat *This;
2774 *format = NULL;
2776 This = heap_alloc(sizeof(struct dwrite_textformat));
2777 if (!This) return E_OUTOFMEMORY;
2779 This->IDWriteTextFormat1_iface.lpVtbl = &dwritetextformatvtbl;
2780 This->ref = 1;
2781 This->format.family_name = heap_strdupW(family_name);
2782 This->format.family_len = strlenW(family_name);
2783 This->format.locale = heap_strdupW(locale);
2784 This->format.locale_len = strlenW(locale);
2785 This->format.weight = weight;
2786 This->format.style = style;
2787 This->format.fontsize = size;
2788 This->format.stretch = stretch;
2789 This->format.textalignment = DWRITE_TEXT_ALIGNMENT_LEADING;
2790 This->format.paralign = DWRITE_PARAGRAPH_ALIGNMENT_NEAR;
2791 This->format.wrapping = DWRITE_WORD_WRAPPING_WRAP;
2792 This->format.readingdir = DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
2793 This->format.flow = DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM;
2794 This->format.spacingmethod = DWRITE_LINE_SPACING_METHOD_DEFAULT;
2795 This->format.spacing = 0.0;
2796 This->format.baseline = 0.0;
2797 This->format.trimming.granularity = DWRITE_TRIMMING_GRANULARITY_NONE;
2798 This->format.trimming.delimiter = 0;
2799 This->format.trimming.delimiterCount = 0;
2800 This->format.trimmingsign = NULL;
2801 This->format.collection = collection;
2802 IDWriteFontCollection_AddRef(collection);
2804 *format = (IDWriteTextFormat*)&This->IDWriteTextFormat1_iface;
2806 return S_OK;
2809 static HRESULT WINAPI dwritetypography_QueryInterface(IDWriteTypography *iface, REFIID riid, void **obj)
2811 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
2813 TRACE("(%p)->(%s %p)\n", typography, debugstr_guid(riid), obj);
2815 if (IsEqualIID(riid, &IID_IDWriteTypography) || IsEqualIID(riid, &IID_IUnknown)) {
2816 *obj = iface;
2817 IDWriteTypography_AddRef(iface);
2818 return S_OK;
2821 *obj = NULL;
2823 return E_NOINTERFACE;
2826 static ULONG WINAPI dwritetypography_AddRef(IDWriteTypography *iface)
2828 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
2829 ULONG ref = InterlockedIncrement(&typography->ref);
2830 TRACE("(%p)->(%d)\n", typography, ref);
2831 return ref;
2834 static ULONG WINAPI dwritetypography_Release(IDWriteTypography *iface)
2836 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
2837 ULONG ref = InterlockedDecrement(&typography->ref);
2839 TRACE("(%p)->(%d)\n", typography, ref);
2841 if (!ref) {
2842 heap_free(typography->features);
2843 heap_free(typography);
2846 return ref;
2849 static HRESULT WINAPI dwritetypography_AddFontFeature(IDWriteTypography *iface, DWRITE_FONT_FEATURE feature)
2851 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
2853 TRACE("(%p)->(%x %u)\n", typography, feature.nameTag, feature.parameter);
2855 if (typography->count == typography->allocated) {
2856 DWRITE_FONT_FEATURE *ptr = heap_realloc(typography->features, 2*typography->allocated*sizeof(DWRITE_FONT_FEATURE));
2857 if (!ptr)
2858 return E_OUTOFMEMORY;
2860 typography->features = ptr;
2861 typography->allocated *= 2;
2864 typography->features[typography->count++] = feature;
2865 return S_OK;
2868 static UINT32 WINAPI dwritetypography_GetFontFeatureCount(IDWriteTypography *iface)
2870 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
2871 TRACE("(%p)\n", typography);
2872 return typography->count;
2875 static HRESULT WINAPI dwritetypography_GetFontFeature(IDWriteTypography *iface, UINT32 index, DWRITE_FONT_FEATURE *feature)
2877 struct dwrite_typography *typography = impl_from_IDWriteTypography(iface);
2879 TRACE("(%p)->(%u %p)\n", typography, index, feature);
2881 if (index >= typography->count)
2882 return E_INVALIDARG;
2884 *feature = typography->features[index];
2885 return S_OK;
2888 static const IDWriteTypographyVtbl dwritetypographyvtbl = {
2889 dwritetypography_QueryInterface,
2890 dwritetypography_AddRef,
2891 dwritetypography_Release,
2892 dwritetypography_AddFontFeature,
2893 dwritetypography_GetFontFeatureCount,
2894 dwritetypography_GetFontFeature
2897 HRESULT create_typography(IDWriteTypography **ret)
2899 struct dwrite_typography *typography;
2901 *ret = NULL;
2903 typography = heap_alloc(sizeof(*typography));
2904 if (!typography)
2905 return E_OUTOFMEMORY;
2907 typography->IDWriteTypography_iface.lpVtbl = &dwritetypographyvtbl;
2908 typography->ref = 1;
2909 typography->allocated = 2;
2910 typography->count = 0;
2912 typography->features = heap_alloc(typography->allocated*sizeof(DWRITE_FONT_FEATURE));
2913 if (!typography->features) {
2914 heap_free(typography);
2915 return E_OUTOFMEMORY;
2918 *ret = &typography->IDWriteTypography_iface;
2919 return S_OK;