ReactOS 0.4.17-dev-934-g091855f
analyzer.c
Go to the documentation of this file.
1/*
2 * Text analyzer
3 *
4 * Copyright 2011 Aric Stewart for CodeWeavers
5 * Copyright 2012, 2014 Nikolay Sivov for CodeWeavers
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22#define COBJMACROS
23
24#include <math.h>
25
26#include "dwrite_private.h"
27#include "scripts.h"
28
30
31extern const unsigned short wine_linebreak_table[];
32extern const unsigned short wine_scripts_table[];
33extern const unsigned short bidi_direction_table[];
34
35/* Number of characters needed for LOCALE_SNATIVEDIGITS */
36#define NATIVE_DIGITS_LEN 11
37
39{
41 UINT32 scripttags[3]; /* Maximum 2 script tags, 0-terminated. */
43};
44
45#define _OT(a,b,c,d) DWRITE_MAKE_OPENTYPE_TAG(a,b,c,d)
46
47/* NOTE: keep this array synced with script ids from scripts.h */
49 { /* Zzzz */ { 0x7a7a7a5a, 999, 15, 0x0020, 0, 0, 0, 0, 0, 0, 0 } },
50 { /* Zyyy */ { 0x7979795a, 998, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 } },
51 { /* Zinh */ { 0x686e695a, 994, 15, 0x0020, 1, 0, 0, 0, 0, 0, 0 } },
52 { /* Arab */ { 0x62617241, 160, 8, 0x0640, 0, 1, 0, 0, 0, 1, 1 }, { _OT('a','r','a','b') }, TRUE },
53 { /* Armn */ { 0x6e6d7241, 230, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('a','r','m','n') } },
54 { /* Avst */ { 0x74737641, 134, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('a','v','s','t') } },
55 { /* Bali */ { 0x696c6142, 360, 15, 0x0020, 1, 0, 1, 0, 0, 0, 0 }, { _OT('b','a','l','i') } },
56 { /* Bamu */ { 0x756d6142, 435, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('b','a','m','u') } },
57 { /* Batk */ { 0x6b746142, 365, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('b','a','t','k') } },
58 { /* Beng */ { 0x676e6542, 325, 15, 0x0020, 1, 1, 0, 0, 0, 1, 0 }, { _OT('b','n','g','2'), _OT('b','e','n','g') }, TRUE },
59 { /* Bopo */ { 0x6f706f42, 285, 1, 0x0020, 0, 0, 1, 1, 0, 0, 0 }, { _OT('b','o','p','o') } },
60 { /* Brah */ { 0x68617242, 300, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('b','r','a','h') } },
61 { /* Brai */ { 0x69617242, 570, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('b','r','a','i') }, TRUE },
62 { /* Bugi */ { 0x69677542, 367, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('b','u','g','i') } },
63 { /* Buhd */ { 0x64687542, 372, 8, 0x0020, 0, 0, 1, 0, 0, 0, 0 }, { _OT('b','u','h','d') } },
64 { /* Cans */ { 0x736e6143, 440, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('c','a','n','s') }, TRUE },
65 { /* Cari */ { 0x69726143, 201, 1, 0x0020, 0, 0, 1, 0, 0, 0, 0 }, { _OT('c','a','r','i') } },
66 { /* Cham */ { 0x6d616843, 358, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('c','h','a','m') } },
67 { /* Cher */ { 0x72656843, 445, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('c','h','e','r') }, TRUE },
68 { /* Copt */ { 0x74706f43, 204, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('c','o','p','t') } },
69 { /* Xsux */ { 0x78757358, 20, 1, 0x0020, 0, 0, 1, 1, 0, 0, 0 }, { _OT('x','s','u','x') } },
70 { /* Cprt */ { 0x74727043, 403, 1, 0x0020, 0, 0, 1, 0, 0, 0, 0 }, { _OT('c','p','r','t') } },
71 { /* Cyrl */ { 0x6c727943, 220, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('c','y','r','l') } },
72 { /* Dsrt */ { 0x74727344, 250, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('d','s','r','t') }, TRUE },
73 { /* Deva */ { 0x61766544, 315, 15, 0x0020, 1, 1, 0, 0, 0, 1, 0 }, { _OT('d','e','v','2'), _OT('d','e','v','a') }, TRUE },
74 { /* Egyp */ { 0x70796745, 50, 1, 0x0020, 0, 0, 1, 1, 0, 0, 0 }, { _OT('e','g','y','p') } },
75 { /* Ethi */ { 0x69687445, 430, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('e','t','h','i') }, TRUE },
76 { /* Geor */ { 0x726f6547, 240, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('g','e','o','r') } },
77 { /* Glag */ { 0x67616c47, 225, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('g','l','a','g') } },
78 { /* Goth */ { 0x68746f47, 206, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('g','o','t','h') } },
79 { /* Grek */ { 0x6b657247, 200, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('g','r','e','k') } },
80 { /* Gujr */ { 0x726a7547, 320, 15, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('g','j','r','2'), _OT('g','u','j','r') }, TRUE },
81 { /* Guru */ { 0x75727547, 310, 15, 0x0020, 1, 1, 0, 0, 0, 1, 0 }, { _OT('g','u','r','2'), _OT('g','u','r','u') }, TRUE },
82 { /* Hani */ { 0x696e6148, 500, 8, 0x0020, 0, 0, 1, 1, 0, 0, 0 }, { _OT('h','a','n','i') } },
83 { /* Hang */ { 0x676e6148, 286, 8, 0x0020, 1, 1, 1, 1, 0, 0, 0 }, { _OT('h','a','n','g') }, TRUE },
84 { /* Hano */ { 0x6f6e6148, 371, 8, 0x0020, 0, 0, 1, 0, 0, 0, 0 }, { _OT('h','a','n','o') } },
85 { /* Hebr */ { 0x72626548, 125, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('h','e','b','r') }, TRUE },
86 { /* Hira */ { 0x61726948, 410, 8, 0x0020, 0, 0, 1, 1, 0, 0, 0 }, { _OT('k','a','n','a') } },
87 { /* Armi */ { 0x696d7241, 124, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('a','r','m','i') } },
88 { /* Phli */ { 0x696c6850, 131, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('p','h','l','i') } },
89 { /* Prti */ { 0x69747250, 130, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('p','r','t','i') } },
90 { /* Java */ { 0x6176614a, 361, 15, 0x0020, 1, 0, 1, 0, 0, 0, 0 }, { _OT('j','a','v','a') } },
91 { /* Kthi */ { 0x6968744b, 317, 15, 0x0020, 1, 1, 0, 0, 0, 1, 0 }, { _OT('k','t','h','i') } },
92 { /* Knda */ { 0x61646e4b, 345, 15, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('k','n','d','2'), _OT('k','n','d','a') }, TRUE },
93 { /* Kana */ { 0x616e614b, 411, 8, 0x0020, 0, 0, 1, 1, 0, 0, 0 }, { _OT('k','a','n','a') } },
94 { /* Kali */ { 0x696c614b, 357, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('k','a','l','i') } },
95 { /* Khar */ { 0x7261684b, 305, 15, 0x0020, 1, 0, 1, 0, 0, 0, 0 }, { _OT('k','h','a','r') } },
96 { /* Khmr */ { 0x726d684b, 355, 8, 0x0020, 1, 0, 1, 0, 1, 0, 0 }, { _OT('k','h','m','r') }, TRUE },
97 { /* Laoo */ { 0x6f6f614c, 356, 8, 0x0020, 1, 0, 1, 0, 1, 0, 0 }, { _OT('l','a','o',' ') }, TRUE },
98 { /* Latn */ { 0x6e74614c, 215, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('l','a','t','n') } },
99 { /* Lepc */ { 0x6370654c, 335, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('l','e','p','c') } },
100 { /* Limb */ { 0x626d694c, 336, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('l','i','m','b') } },
101 { /* Linb */ { 0x626e694c, 401, 1, 0x0020, 0, 0, 1, 1, 0, 0, 0 }, { _OT('l','i','n','b') } },
102 { /* Lisu */ { 0x7573694c, 399, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('l','i','s','u') } },
103 { /* Lyci */ { 0x6963794c, 202, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('l','y','c','i') } },
104 { /* Lydi */ { 0x6964794c, 116, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('l','y','d','i') } },
105 { /* Mlym */ { 0x6d796c4d, 347, 15, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('m','l','m','2'), _OT('m','l','y','m') }, TRUE },
106 { /* Mand */ { 0x646e614d, 140, 8, 0x0640, 0, 1, 0, 0, 0, 1, 1 }, { _OT('m','a','n','d') } },
107 { /* Mtei */ { 0x6965744d, 337, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('m','t','e','i') } },
108 { /* Mong */ { 0x676e6f4d, 145, 8, 0x0020, 0, 1, 0, 0, 0, 1, 1 }, { _OT('m','o','n','g') }, TRUE },
109 { /* Mymr */ { 0x726d794d, 350, 15, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('m','y','m','r') }, TRUE },
110 { /* Talu */ { 0x756c6154, 354, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('t','a','l','u') }, TRUE },
111 { /* Nkoo */ { 0x6f6f6b4e, 165, 8, 0x0020, 0, 1, 0, 0, 0, 1, 1 }, { _OT('n','k','o',' ') }, TRUE },
112 { /* Ogam */ { 0x6d61674f, 212, 1, 0x1680, 0, 1, 0, 0, 0, 1, 0 }, { _OT('o','g','a','m') }, TRUE },
113 { /* Olck */ { 0x6b636c4f, 261, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('o','l','c','k') } },
114 { /* Ital */ { 0x6c617449, 210, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('i','t','a','l') } },
115 { /* Xpeo */ { 0x6f657058, 30, 1, 0x0020, 0, 1, 1, 1, 0, 0, 0 }, { _OT('x','p','e','o') }, TRUE },
116 { /* Sarb */ { 0x62726153, 105, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('s','a','r','b') } },
117 { /* Orkh */ { 0x686b724f, 175, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('o','r','k','h') } },
118 { /* Orya */ { 0x6179724f, 327, 15, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('o','r','y','2'), _OT('o','r','y','a') }, TRUE },
119 { /* Osma */ { 0x616d734f, 260, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('o','s','m','a') }, TRUE },
120 { /* Phag */ { 0x67616850, 331, 8, 0x0020, 0, 1, 0, 0, 0, 1, 1 }, { _OT('p','h','a','g') }, TRUE },
121 { /* Phnx */ { 0x786e6850, 115, 1, 0x0020, 0, 0, 1, 0, 0, 0, 0 }, { _OT('p','h','n','x') } },
122 { /* Rjng */ { 0x676e6a52, 363, 8, 0x0020, 1, 0, 1, 0, 0, 0, 0 }, { _OT('r','j','n','g') } },
123 { /* Runr */ { 0x726e7552, 211, 1, 0x0020, 0, 0, 1, 0, 0, 0, 0 }, { _OT('r','u','n','r') }, TRUE },
124 { /* Samr */ { 0x726d6153, 123, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('s','a','m','r') } },
125 { /* Saur */ { 0x72756153, 344, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('s','a','u','r') } },
126 { /* Shaw */ { 0x77616853, 281, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('s','h','a','w') } },
127 { /* Sinh */ { 0x686e6953, 348, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('s','i','n','h') }, TRUE },
128 { /* Sund */ { 0x646e7553, 362, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('s','u','n','d') } },
129 { /* Sylo */ { 0x6f6c7953, 316, 8, 0x0020, 1, 1, 0, 0, 0, 1, 0 }, { _OT('s','y','l','o') } },
130 { /* Syrc */ { 0x63727953, 135, 8, 0x0640, 0, 1, 0, 0, 0, 1, 1 }, { _OT('s','y','r','c') }, TRUE },
131 { /* Tglg */ { 0x676c6754, 370, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('t','g','l','g') } },
132 { /* Tagb */ { 0x62676154, 373, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('t','a','g','b') } },
133 { /* Tale */ { 0x656c6154, 353, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('t','a','l','e') }, TRUE },
134 { /* Lana */ { 0x616e614c, 351, 8, 0x0020, 1, 0, 1, 0, 0, 0, 0 }, { _OT('l','a','n','a') } },
135 { /* Tavt */ { 0x74766154, 359, 8, 0x0020, 1, 0, 1, 0, 1, 0, 0 }, { _OT('t','a','v','t') } },
136 { /* Taml */ { 0x6c6d6154, 346, 15, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('t','m','l','2'), _OT('t','a','m','l') }, TRUE },
137 { /* Telu */ { 0x756c6554, 340, 15, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('t','e','l','2'), _OT('t','e','l','u') }, TRUE },
138 { /* Thaa */ { 0x61616854, 170, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('t','h','a','a') }, TRUE },
139 { /* Thai */ { 0x69616854, 352, 8, 0x0020, 1, 0, 1, 0, 1, 0, 0 }, { _OT('t','h','a','i') }, TRUE },
140 { /* Tibt */ { 0x74626954, 330, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('t','i','b','t') }, TRUE },
141 { /* Tfng */ { 0x676e6654, 120, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('t','f','n','g') }, TRUE },
142 { /* Ugar */ { 0x72616755, 40, 1, 0x0020, 0, 0, 1, 1, 0, 0, 0 }, { _OT('u','g','a','r') } },
143 { /* Vaii */ { 0x69696156, 470, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('v','a','i',' ') }, TRUE },
144 { /* Yiii */ { 0x69696959, 460, 1, 0x0020, 0, 0, 1, 1, 0, 0, 0 }, { _OT('y','i',' ',' ') }, TRUE },
145 { /* Cakm */ { 0x6d6b6143, 349, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('c','a','k','m') } },
146 { /* Merc */ { 0x6372654d, 101, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('m','e','r','c') } },
147 { /* Mero */ { 0x6f72654d, 100, 1, 0x0020, 0, 1, 1, 1, 0, 0, 0 }, { _OT('m','e','r','o') } },
148 { /* Plrd */ { 0x64726c50, 282, 8, 0x0020, 1, 0, 1, 0, 0, 0, 0 }, { _OT('p','l','r','d') } },
149 { /* Shrd */ { 0x64726853, 319, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('s','h','r','d') } },
150 { /* Sora */ { 0x61726f53, 398, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('s','o','r','a') } },
151 { /* Takr */ { 0x726b6154, 321, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('t','a','k','r') } },
152 { /* Bass */ { 0x73736142, 259, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('b','a','s','s') } },
153 { /* Aghb */ { 0x62686741, 239, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('a','g','h','b') } },
154 { /* Dupl */ { 0x6c707544, 755, 8, 0x0020, 0, 1, 0, 0, 0, 1, 1 }, { _OT('d','u','p','l') } },
155 { /* Elba */ { 0x61626c45, 226, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('e','l','b','a') } },
156 { /* Gran */ { 0x6e617247, 343, 15, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('g','r','a','n') } },
157 { /* Khoj */ { 0x6a6f684b, 322, 15, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('k','h','o','j') } },
158 { /* Sind */ { 0x646e6953, 318, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('s','i','n','d') } },
159 { /* Lina */ { 0x616e694c, 400, 1, 0x0020, 0, 0, 1, 1, 0, 0, 0 }, { _OT('l','i','n','a') } },
160 { /* Mahj */ { 0x6a68614d, 314, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('m','a','h','j') } },
161 { /* Mani */ { 0x696e614d, 139, 8, 0x0640, 0, 1, 0, 0, 0, 1, 1 }, { _OT('m','a','n','i') } },
162 { /* Mend */ { 0x646e654d, 438, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('m','e','n','d') } },
163 { /* Modi */ { 0x69646f4d, 324, 15, 0x0020, 1, 1, 0, 0, 0, 1, 0 }, { _OT('m','o','d','i') } },
164 { /* Mroo */ { 0x6f6f724d, 199, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('m','r','o','o') } },
165 { /* Nbat */ { 0x7461624e, 159, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('n','b','a','t') } },
166 { /* Narb */ { 0x6272614e, 106, 1, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('n','a','r','b') } },
167 { /* Perm */ { 0x6d726550, 227, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('p','e','r','m') } },
168 { /* Hmng */ { 0x676e6d48, 450, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('h','m','n','g') } },
169 { /* Palm */ { 0x6d6c6150, 126, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('p','a','l','m') } },
170 { /* Pauc */ { 0x63756150, 263, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('p','a','u','c') } },
171 { /* Phlp */ { 0x706c6850, 132, 8, 0x0640, 0, 1, 0, 0, 0, 1, 1 }, { _OT('p','h','l','p') } },
172 { /* Sidd */ { 0x64646953, 302, 8, 0x0020, 1, 0, 1, 1, 0, 0, 0 }, { _OT('s','i','d','d') } },
173 { /* Tirh */ { 0x68726954, 326, 15, 0x0020, 1, 1, 0, 0, 0, 1, 0 }, { _OT('t','i','r','h') } },
174 { /* Wara */ { 0x61726157, 262, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('w','a','r','a') } },
175 { /* Adlm */ { 0x6d6c6441, 166, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('a','d','l','m') } },
176 { /* Ahom */ { 0x6d6f6841, 338, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('a','h','o','m') } },
177 { /* Hluw */ { 0x77756c48, 80, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('h','l','u','w') } },
178 { /* Bhks */ { 0x736b6842, 334, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('b','h','k','s') } },
179 { /* Hatr */ { 0x72746148, 127, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('h','a','t','r') } },
180 { /* Marc */ { 0x6372614d, 332, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('m','a','r','c') } },
181 { /* Mult */ { 0x746c754d, 323, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('m','u','l','t') } },
182 { /* Newa */ { 0x6177654e, 333, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('n','e','w','a') } },
183 { /* Hung */ { 0x676e7548, 176, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('h','u','n','g') } },
184 { /* Osge */ { 0x6567734f, 219, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('o','s','g','e') } },
185 { /* Sgnw */ { 0x776e6753, 95, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('s','g','n','w') } },
186 { /* Tang */ { 0x676e6154, 520, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('t','a','n','g') } },
187 { /* Gonm */ { 0x6d6e6f47, 313, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('g','o','n','m') } },
188 { /* Nshu */ { 0x7568734e, 499, 1, 0x0020, 0, 0, 1, 1, 0, 0, 0 }, { _OT('n','s','h','u') } },
189 { /* Soyo */ { 0x6f796f53, 329, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('s','o','y','o') } },
190 { /* Zanb */ { 0x626e615a, 339, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('z','a','n','b') } },
191 { /* Dogr */ { 0x72676f44, 328, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('d','o','g','r') } },
192 { /* Gong */ { 0x676e6f47, 312, 8, 0x0020, 1, 1, 0, 0, 0, 1, 0 }, { _OT('g','o','n','g') } },
193 { /* Rohg */ { 0x67686f52, 167, 8, 0x0020, 0, 1, 0, 0, 0, 1, 1 }, { _OT('r','o','h','g') } },
194 { /* Maka */ { 0x616b614d, 366, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('m','a','k','a') } },
195 { /* Medf */ { 0x6664654d, 265, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('m','e','d','f') } },
196 { /* Sogo */ { 0x6f676f53, 142, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('s','o','g','o') } },
197 { /* Sogd */ { 0x64676f53, 141, 8, 0x0020, 1, 1, 0, 0, 0, 1, 1 }, { _OT('s','o','g','d') } },
198 { /* Elym */ { 0x6d796c45, 128, 1, 0x0020, 0, 0, 1, 0, 0, 0, 0 }, { _OT('e','l','y','m') } },
199 { /* Hmnp */ { 0x706e6d48, 451, 8, 0x0020, 1, 1, 0, 0, 0, 0, 0 }, { _OT('h','m','n','p') } },
200 { /* Nand */ { 0x646e614e, 311, 8, 0x0020, 1, 1, 0, 0, 0, 1, 0 }, { _OT('n','a','n','d') } },
201 { /* Wcho */ { 0x6f686357, 283, 8, 0x0020, 1, 1, 0, 0, 0, 0, 0 }, { _OT('w','c','h','o') } },
202 { /* Chrs */ { 0x73726843, 109, 8, 0x0020, 0, 1, 0, 0, 0, 1, 1 }, { _OT('c','h','r','s') } },
203 { /* Diak */ { 0x6b616944, 342, 8, 0x0020, 1, 1, 0, 0, 0, 0, 0 }, { _OT('d','i','a','k') } },
204 { /* Kits */ { 0x7374694b, 288, 8, 0x0020, 1, 0, 1, 1, 0, 0, 0 }, { _OT('k','i','t','s') } },
205 { /* Yezi */ { 0x697a6559, 192, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('y','e','z','i') } },
206};
207#undef _OT
208
210{
211 return script < Script_LastId ? debugstr_fourcc(dwritescripts_properties[script].props.isoScriptCode) : "undefined";
212}
213
214static const struct fallback_description
215{
216 const char *ranges;
218 const WCHAR *locale;
219}
221{
222 /* Latin, Combining Diacritical Marks */
223 { "0000-007F, 0080-00FF, 0100-017F, 0180-024F, "
224 "0250-02AF, 02B0-02FF, 0300-036F", L"Tahoma" },
225
226 { "0530-058F, FB10-FB1C", L"Noto Sans Armenian" },
227
228 { "0590-05FF, FB1D-FB4F", L"Noto Sans Hebrew" },
229
230 { "0600-06FF, 0750-077F, "
231 "08A0-08FF, FB50-FDCF, "
232 "FDF0-FDFF, FE70-FEFE", L"Noto Sans Arabic" },
233
234 { "0700-074F", L"Noto Sans Syriac" },
235 { "0780-07BF", L"Noto Sans Thaana" },
236 { "07C0-07FF", L"Noto Sans NKo" },
237 { "0800-083F", L"Noto Sans Samaritan" },
238 { "0840-085F", L"Noto Sans Mandaic" },
239
240 { "0900-097F", L"Noto Sans Devanagari" },
241 { "0980-09FF", L"Noto Sans Bengali" },
242 { "0A00-0A7F", L"Noto Sans Gurmukhi" },
243 { "0A80-0AFF", L"Noto Sans Gujarati" },
244 { "0B00-0B7F", L"Noto Sans Oriya" },
245 { "0B80-0BFF", L"Noto Sans Tamil" },
246 { "0C00-0C7F", L"Noto Sans Telugu" },
247 { "0C80-0CFF", L"Noto Sans Kannada" },
248 { "0D00-0D7F", L"Noto Sans Malayalam" },
249 { "0D80-0DFF", L"Noto Sans Sinhala" },
250
251 { "0E00-0E7F", L"Noto Sans Thai" },
252 { "0E80-0EFF", L"Noto Sans Lao" },
253
254 { "0F00-0FFF", L"Noto Serif Tibetan" },
255
256 { "1000-109F, A9E0-A9FF, AA60-AA7F", L"Noto Sans Myanmar" },
257
258 { "10A0-10FF, 2D00-2D2F", L"Noto Sans Georgian" },
259
260 /* Hangul Jamo - 1100-11FF
261 Hangul Compatibility Jamo - 3130-318F
262 Enc. CJK (Paren Hangul) - 3200-321F
263 Enc. CJK (Circled Hangul) - 3260-327F
264 Hangul Jamo Extended-A - A960-A97F
265 Hangul Syllables - AC00-D7AF
266 Hangul Jamo Extended-B - D7B0-D7FF */
267
268 { "1100-11FF, 3130-318F, "
269 "3200-321F, 3260-327F, "
270 "A960-A97F, AC00-D7FF, "
271 "D7B0-D7FF", L"Noto Sans CJK KR" },
272
273 { "1680-169F", L"Noto Sans Ogham" },
274
275 { "16A0-16FF", L"Noto Sans Runic" },
276
277 { "1700-171F", L"Noto Sans Tagalog" },
278 { "1720-173F", L"Noto Sans Hanunoo" },
279 { "1740-175F", L"Noto Sans Buhid" },
280 { "1760-177F", L"Noto Sans Tagbanwa" },
281
282 { "1800-18AF, 202F, 11660-1167F", L"Noto Sans Mongolian" },
283
284 { "1900-194F", L"Noto Sans Limbu" },
285 { "1950-197F", L"Noto Sans Tai Le" },
286 { "1980-19DF", L"Noto Sans New Tai Lue" },
287 { "1A00-1A1F", L"Noto Sans Buginese" },
288 { "1A20-1AAF", L"Noto Sans Tai Tham" },
289 { "1B00-1B7F", L"Noto Sans Balinese" },
290 { "1B80-1BBF, 1CC0-1CCF", L"Noto Sans Sundanes" },
291 { "1BC0-1BFF", L"Noto Sans Batak" },
292 { "1C00-1C4F", L"Noto Sans Lepcha" },
293 { "1C50-1C7F", L"Noto Sans Ol Chiki" },
294
295 { "2C80-2CFF", L"Noto Sans Coptic" },
296 { "2D30-2D7F", L"Noto Sans Tifinagh" },
297
298 /* CJK Radicals Supplement - 2E80-2EFF */
299
300 { "2E80-2EFF", L"Noto Sans CJK SC", L"zh-Hans" },
301 { "2E80-2EFF", L"Noto Sans CJK TC", L"zh-Hant" },
302 { "2E80-2EFF", L"Noto Sans CJK KR", L"ko" },
303
304 /* CJK Symbols and Punctuation - 3000-303F
305 Hiragana - 3040-309F
306 Katakana - 30A0-30FF
307 Katakana Phonetic Ext. - 31F0-31FF */
308
309 { "3000-30FF, 31F0-31FF", L"Noto Sans CJK SC", L"zh-Hans" },
310 { "3000-30FF, 31F0-31FF", L"Noto Sans CJK TC", L"zh-Hant" },
311 { "3000-30FF, 31F0-31FF", L"Noto Sans CJK KR", L"ko" },
312 { "3000-30FF, 31F0-31FF", L"Noto Sans CJK JP" },
313
314 /* CJK Unified Ext A - 3400-4DBF
315 CJK Unified - 4E00-9FFF */
316
317 { "3400-4DBF, 4E00-9FFF", L"Noto Sans CJK SC", L"zh-Hans" },
318 { "3400-4DBF, 4E00-9FFF", L"Noto Sans CJK TC", L"zh-Hant" },
319 { "3400-4DBF, 4E00-9FFF", L"Noto Sans CJK KR", L"ko" },
320 { "3400-4DBF, 4E00-9FFF", L"Noto Sans CJK JP" },
321
322 { "A000-A4CF", L"Noto Sans Yi" },
323 { "A4D0-A4FF", L"Noto Sans Lisu" },
324 { "A500-A63F", L"Noto Sans Vai" },
325 { "A6A0-A6FF", L"Noto Sans Bamum" },
326 { "A800-A82F", L"Noto Sans Syloti Nagri" },
327 { "A840-A87F", L"Noto Sans PhagsPa" },
328 { "A880-A8DF", L"Noto Sans Saurashtra" },
329 { "A900-A92F", L"Noto Sans Kayah Li" },
330 { "A930-A95F", L"Noto Sans Rejang" },
331 { "A980-A9DF", L"Noto Sans Javanese" },
332 { "AA00-AA5F", L"Noto Sans Cham" },
333
334 /* CJK Compatibility Ideographs - F900-FAFF */
335
336 { "F900-FAFF", L"Noto Sans CJK SC", L"zh-Hans" },
337 { "F900-FAFF", L"Noto Sans CJK TC", L"zh-Hant" },
338 { "F900-FAFF", L"Noto Sans CJK KR", L"ko" },
339 { "F900-FAFF", L"Noto Sans CJK JP" },
340
341 /* Vertical Forms - FE10-FE1F */
342
343 { "FE10-FE1F", L"Noto Sans CJK SC", L"zh-Hans" },
344 { "FE10-FE1F", L"Noto Sans CJK KR", L"ko" },
345 { "FE10-FE1F", L"Noto Sans CJK TC" },
346
347 /* CJK Compatibility Forms - FE30-FE4F
348 Small Form Variants - FE50-FE6F */
349
350 { "FE30-FE6F", L"Noto Sans CJK SC", L"zh-Hans" },
351 { "FE30-FE6F", L"Noto Sans CJK KR", L"ko" },
352 { "FE30-FE6F", L"Noto Sans CJK JP", L"ja" },
353 { "FE30-FE6F", L"Noto Sans CJK TC" },
354
355 /* Halfwidth and Fullwidth Forms */
356 { "FF00-FFEF", L"Noto Sans CJK SC", L"zh-Hans" },
357 { "FF00-FFEF", L"Noto Sans CJK TC", L"zh-Hant" },
358 { "FF00-FFEF", L"Noto Sans CJK KR", L"ko" },
359 { "FF00-FFEF", L"Noto Sans CJK JP" },
361
363{
365
369
371 const WCHAR *text;
375
377};
378
379static inline unsigned int text_source_get_char_length(const struct text_source_context *context)
380{
381 return context->ch > 0xffff ? 2 : 1;
382}
383
385{
386 if ((context->chunk_length - context->cursor) > 1) return;
387
388 context->position += context->cursor;
389 context->cursor = 0;
390 if (FAILED(context->status = IDWriteTextAnalysisSource_GetTextAtPosition(context->source, context->position,
391 &context->text, &context->chunk_length)))
392 {
393 context->end = TRUE;
394 }
395}
396
398{
399 const WCHAR *text;
401
402 /* Make sure to have full pair of surrogates */
404
405 available = context->chunk_length - context->cursor;
406 text = context->text + context->cursor;
407
408 if (available > 1 && IS_HIGH_SURROGATE(*text) && IS_LOW_SURROGATE(*(text + 1)))
409 {
410 context->cursor += 2;
411 context->consumed += 2;
412 context->ch = 0x10000 + ((*text - 0xd800) << 10) + *(text + 1) - 0xdc00;
413 return;
414 }
415
416 context->cursor++;
417 context->consumed++;
418 context->ch = *text;
419}
420
422 UINT32 position, UINT32 length)
423{
424 memset(context, 0, sizeof(*context));
425 context->source = source;
426 context->position = position;
427 context->length = length;
428
429 return IDWriteTextAnalysisSource_GetTextAtPosition(source, position, &context->text, &context->chunk_length);
430}
431
433{
434 if (context->consumed == context->length)
435 {
436 context->ch = 0;
437 context->end = TRUE;
438 }
439 else if (context->cursor < context->chunk_length)
440 {
442 }
443 else
444 {
446 /* Normal end-of-text condition. */
447 if (!context->text || !context->chunk_length)
448 context->end = TRUE;
449 else
451 }
452
453 return context->end;
454}
455
457{
463 float scale;
464};
465
467{
468 struct list entry;
470 struct
471 {
472 size_t *data;
473 size_t count;
474 size_t size;
476};
477
478static void fallback_locale_list_destroy(struct list *locales)
479{
480 struct fallback_locale *cur, *cur2;
481
482 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, locales, struct fallback_locale, entry)
483 {
484 list_remove(&cur->entry);
485 free(cur->ranges.data);
486 free(cur);
487 }
488}
489
491{
492 size_t count = locale->ranges.count;
493
494 /* Append to last range, or start a new one. */
495 if (count && locale->ranges.data[count - 1] == (index - 1))
496 {
497 locale->ranges.data[count - 1] = index;
498 return S_OK;
499 }
500
501 if (!dwrite_array_reserve((void **)&locale->ranges.data, &locale->ranges.size, count + 2,
502 sizeof(*locale->ranges.data)))
503 {
504 return E_OUTOFMEMORY;
505 }
506
507 locale->ranges.data[count] = locale->ranges.data[count + 1] = index;
508 locale->ranges.count += 2;
509
510 return S_OK;
511}
512
513/* TODO: potentially needs improvement to consider partially matching locale names. */
514static struct fallback_locale * font_fallback_get_locale(const struct list *locales,
515 const WCHAR *locale_name)
516{
517 struct fallback_locale *locale, *neutral = NULL;
518
520 {
521 if (!wcsicmp(locale->name, locale_name)) return locale;
522 if (!*locale->name) neutral = locale;
523 }
524
525 return neutral;
526}
527
529{
531 size_t count;
532 struct list locales;
533};
534
536{
543};
544
546{
552};
553
555{
556 .locales = LIST_INIT(system_fallback.locales),
557};
558
560{
561 unsigned int i;
562
563 free(mapping->ranges);
564 for (i = 0; i < mapping->families_count; ++i)
565 free(mapping->families[i]);
566 free(mapping->families);
567 if (mapping->collection)
568 IDWriteFontCollection_Release(mapping->collection);
569}
570
572{
573 size_t i;
574
575 for (i = 0; i < data->count; ++i)
576 release_fallback_mapping(&data->mappings[i]);
577 free(data->mappings);
579}
580
582{
583 size_t i;
584
585 for (i = 0; i < mapping->ranges_count; ++i)
586 {
587 const DWRITE_UNICODE_RANGE *range = &mapping->ranges[i];
588 if (range->first <= ch && range->last >= ch) return TRUE;
589 }
590
591 return FALSE;
592}
593
594static const struct fallback_mapping * find_fallback_mapping(const struct fallback_data *fallback,
595 const struct fallback_locale *locale, UINT32 ch)
596{
597 const struct fallback_mapping *mapping;
598 size_t i, j;
599
600 for (i = 0; i < locale->ranges.count; i += 2)
601 {
602 size_t start = locale->ranges.data[i], end = locale->ranges.data[i + 1];
603 for (j = start; j <= end; ++j)
604 {
605 mapping = &fallback->mappings[j];
607 }
608 }
609
610 mapping = NULL;
611
612 /* Mapping wasn't found for specific locale, try with neutral one. This will only recurse once. */
613 if (*locale->name)
614 {
615 locale = font_fallback_get_locale(&fallback->locales, L"");
617 }
618
619 return mapping;
620}
621
623{
626
630};
631
633{
635}
636
638
640{
642}
643
645{
647}
648
650{
653}
654
656{
658
659 sa.script = get_char_script(c);
661 if ((c <= 0x001f) /* C0 controls */
662 || (c >= 0x007f && c <= 0x009f) /* DELETE, C1 controls */
663 || (c == 0x00ad) /* SOFT HYPHEN */
664 || (c >= 0x200b && c <= 0x200f) /* ZWSP, ZWNJ, ZWJ, LRM, RLM */
665 || (c >= 0x2028 && c <= 0x202e) /* Line/paragraph separators, LRE, RLE, PDF, LRO, RLO */
666 || (c >= 0x2060 && c <= 0x2064) /* WJ, invisible operators */
667 || (c >= 0x2066 && c <= 0x2069) /* LRI, RLI, FSI, PDI */
668 || (c >= 0x206a && c <= 0x206f) /* Deprecated control characters */
669 || (c == 0xfeff) /* ZWBNSP */
670 || (c == 0xfff9) /* Interlinear annotation */
671 || (c == 0xfffa)
672 || (c == 0xfffb)
673 || (c >= 0x1bca0 && c <= 0x1bca3) /* Shorthand format controls */
674 || (c >= 0x1d173 && c <= 0x1d17a) /* Musical symbols: beams and slurs */
675 || (c == 0xe0001) /* Language tag, deprecated */
676 || (c >= 0xe0020 && c <= 0xe007f)) /* Tag components */
677 {
679 }
680 else
681 {
683 }
684
685 return sa;
686}
687
689{
692 HRESULT hr;
693
695
696 sa = get_char_sa(context->ch);
697
698 pos = context->position;
700
702 {
704
705 /* Unknown type is ignored when preceded or followed by another script */
706 switch (sa.script) {
707 case Script_Unknown:
708 sa.script = cur_sa.script;
709 break;
710 case Script_Common:
711 if (cur_sa.script == Script_Unknown)
712 cur_sa.script = sa.script;
713 else if ((cur_sa.script != Script_Common) && sa.shapes == DWRITE_SCRIPT_SHAPES_DEFAULT)
714 sa.script = cur_sa.script;
715 break;
716 default:
717 if ((cur_sa.script == Script_Common && cur_sa.shapes == DWRITE_SCRIPT_SHAPES_DEFAULT) || cur_sa.script == Script_Unknown)
718 cur_sa.script = sa.script;
719 }
720
721 /* this is a length of a sequence to be reported next */
722 if (sa.script == cur_sa.script && sa.shapes == cur_sa.shapes)
724 else
725 {
726 hr = IDWriteTextAnalysisSink_SetScriptAnalysis(sink, pos, length, &sa);
727 if (FAILED(hr)) return hr;
728 pos += length;
730 sa = cur_sa;
731 }
732 }
733
734 /* one char length case or normal completion call */
735 return IDWriteTextAnalysisSink_SetScriptAnalysis(sink, pos, length, &sa);
736}
737
739{
740 unsigned int index;
742};
743
745{
749};
750
755
757 b_BK = 1,
800};
801
803{
804 if (old_condition == DWRITE_BREAK_CONDITION_MAY_NOT_BREAK || old_condition == DWRITE_BREAK_CONDITION_MUST_BREAK)
805 return TRUE;
806
807 if (old_condition == DWRITE_BREAK_CONDITION_CAN_BREAK && new_condition != DWRITE_BREAK_CONDITION_MUST_BREAK)
808 return TRUE;
809
810 return FALSE;
811}
812
813/* "Can break" is a weak condition, stronger "may not break" and "must break" override it. Initially all conditions are
814 set to "can break" and could only be changed once. */
817{
818 unsigned int index = state->breaks[pos].index;
819
821 {
822 if (has_strong_condition(state->breakpoints[index].breakConditionBefore, condition))
823 return;
824 state->breakpoints[index].breakConditionBefore = condition;
825 if (pos)
826 {
827 --pos;
828
829 index = state->breaks[pos].index;
830 if (state->breaks[pos].length > 1) index++;
831
832 state->breakpoints[index].breakConditionAfter = condition;
833 }
834 }
835 else
836 {
837 if (state->breaks[pos].length > 1) index++;
838
839 if (has_strong_condition(state->breakpoints[index].breakConditionAfter, condition))
840 return;
841 state->breakpoints[index].breakConditionAfter = condition;
842
843 if (pos + 1 < state->count)
844 {
845 index = state->breaks[pos + 1].index;
846 state->breakpoints[index].breakConditionBefore = condition;
847 }
848 }
849}
850
852{
854 return c == b_LF || c == b_NL || c == b_CR || c == b_BK;
855}
856
859{
862 struct break_index *breaks;
863 unsigned int count, index;
864 short *break_class;
865 int i = 0, j;
866 HRESULT hr;
867
868 if (FAILED(hr = text_source_context_init(&context, source, position, length))) return hr;
869
870 if (!(breaks = calloc(length, sizeof(*breaks))))
871 return E_OUTOFMEMORY;
872
873 if (!(break_class = calloc(length, sizeof(*break_class))))
874 {
875 free(breaks);
876 return E_OUTOFMEMORY;
877 }
878
879 count = index = 0;
881 {
884 breaks[count].index = index;
885
886 /* LB1 - resolve some classes. TODO: use external algorithms for these classes. */
887 switch (break_class[count])
888 {
889 case b_AI:
890 case b_SA:
891 case b_SG:
892 case b_XX:
893 break_class[count] = b_AL;
894 break;
895 case b_CJ:
896 break_class[count] = b_NS;
897 break;
898 }
899
902 breakpoints[index].isWhitespace = context.ch < 0xffff ? !!iswspace(context.ch) : 0;
903 breakpoints[index].isSoftHyphen = context.ch == 0x00ad /* Unicode Soft Hyphen */;
904 breakpoints[index].padding = 0;
905 ++index;
906
907 if (breaks[count].length > 1)
908 {
909 breakpoints[index] = breakpoints[index - 1];
910 /* Never break in surrogate pairs. */
913 ++index;
914 }
915
916 ++count;
917 }
918
919 state.breakpoints = breakpoints;
920 state.breaks = breaks;
921 state.count = count;
922
923 /* LB2 - never break at the start */
925 /* LB3 - always break at the end. */
927
928 /* LB4 - LB6 - mandatory breaks. */
929 for (i = 0; i < count; i++)
930 {
931 switch (break_class[i])
932 {
933 /* LB4 - LB6 */
934 case b_CR:
935 /* LB5 - don't break CR x LF */
936 if (i < count-1 && break_class[i+1] == b_LF)
937 {
940 break;
941 }
942 case b_LF:
943 case b_NL:
944 case b_BK:
945 /* LB4 - LB5 - always break after hard breaks */
947 /* LB6 - do not break before hard breaks */
949 break;
950 }
951 }
952
953 /* LB7 - LB8 - explicit breaks and non-breaks */
954 for (i = 0; i < count; i++)
955 {
956 switch (break_class[i])
957 {
958 /* LB7 - do not break before spaces or zero-width space */
959 case b_SP:
961 break;
962 case b_ZW:
964
965 /* LB8 - break before character after zero-width space, skip spaces in-between */
966 j = i;
967 while (j < count-1 && break_class[j+1] == b_SP)
968 j++;
969 if (j < count-1 && break_class[j+1] != b_ZW)
971 break;
972 /* LB8a - do not break after ZWJ */
973 case b_ZWJ:
975 break;
976 }
977 }
978
979 /* LB9 - LB10 - combining marks */
980 for (i = 0; i < count; i++)
981 {
982 if (break_class[i] == b_CM || break_class[i] == b_ZWJ)
983 {
984 if (i > 0)
985 {
986 switch (break_class[i-1])
987 {
988 case b_SP:
989 case b_BK:
990 case b_CR:
991 case b_LF:
992 case b_NL:
993 case b_ZW:
994 break_class[i] = b_AL;
995 break;
996 default:
997 {
998 break_class[i] = break_class[i-1];
1000 }
1001 }
1002 }
1003 else break_class[i] = b_AL;
1004 }
1005 }
1006
1007 for (i = 0; i < count; i++)
1008 {
1009 switch (break_class[i])
1010 {
1011 /* LB11 - don't break before and after word joiner */
1012 case b_WJ:
1015 break;
1016 /* LB12 - don't break after glue */
1017 case b_GL:
1019 /* LB12a */
1020 if (i > 0)
1021 {
1022 if (break_class[i-1] != b_SP && break_class[i-1] != b_BA && break_class[i-1] != b_HY)
1024 }
1025 break;
1026 /* LB13 */
1027 case b_CL:
1028 case b_CP:
1029 case b_EX:
1030 case b_IS:
1031 case b_SY:
1033 break;
1034 /* LB14 - do not break after OP, even after spaces */
1035 case b_OP:
1036 j = i;
1037 while (j < count-1 && break_class[j+1] == b_SP)
1038 j++;
1040 break;
1041 /* LB15 - do not break within QU-OP, even with intervening spaces */
1042 case b_QU:
1043 j = i;
1044 while (j < count-1 && break_class[j+1] == b_SP)
1045 j++;
1046 if (j < count - 1 && break_class[j+1] == b_OP)
1048 break;
1049 /* LB16 */
1050 case b_NS:
1051 j = i-1;
1052 while(j > 0 && break_class[j] == b_SP)
1053 j--;
1054 if (break_class[j] == b_CL || break_class[j] == b_CP)
1055 for (j++; j <= i; j++)
1057 break;
1058 /* LB17 - do not break within B2, even with intervening spaces */
1059 case b_B2:
1060 j = i;
1061 while (j < count && break_class[j+1] == b_SP)
1062 j++;
1063 if (j < count - 1 && break_class[j+1] == b_B2)
1065 break;
1066 }
1067 }
1068
1069 for (i = 0; i < count; i++)
1070 {
1071 switch(break_class[i])
1072 {
1073 /* LB18 - break is allowed after space */
1074 case b_SP:
1076 break;
1077 /* LB19 - don't break before or after quotation mark */
1078 case b_QU:
1081 break;
1082 /* LB20 */
1083 case b_CB:
1085 if (i < count - 1 && break_class[i+1] != b_QU)
1087 break;
1088 /* LB21 */
1089 case b_BA:
1090 case b_HY:
1091 case b_NS:
1093 break;
1094 case b_BB:
1095 if (i < count - 1 && break_class[i+1] != b_CB)
1097 break;
1098 /* LB21a, LB21b */
1099 case b_HL:
1100 /* LB21a */
1101 if (i < count-1)
1102 switch (break_class[i+1])
1103 {
1104 case b_HY:
1105 case b_BA:
1107 }
1108 /* LB21b */
1109 if (i > 0 && break_class[i-1] == b_SY)
1111 break;
1112 /* LB22 */
1113 case b_IN:
1115 break;
1116 }
1117
1118 if (i < count-1)
1119 {
1120 /* LB23 - do not break between digits and letters */
1121 if ((break_class[i] == b_AL && break_class[i+1] == b_NU) ||
1122 (break_class[i] == b_HL && break_class[i+1] == b_NU) ||
1123 (break_class[i] == b_NU && break_class[i+1] == b_AL) ||
1124 (break_class[i] == b_NU && break_class[i+1] == b_HL))
1126
1127 /* LB23a - do not break between numeric prefixes and ideographs, or between ideographs and numeric postfixes */
1128 if ((break_class[i] == b_PR && break_class[i+1] == b_ID) ||
1129 (break_class[i] == b_PR && break_class[i+1] == b_EB) ||
1130 (break_class[i] == b_PR && break_class[i+1] == b_EM) ||
1131 (break_class[i] == b_ID && break_class[i+1] == b_PO) ||
1132 (break_class[i] == b_EM && break_class[i+1] == b_PO) ||
1133 (break_class[i] == b_EB && break_class[i+1] == b_PO))
1135
1136 /* LB24 - do not break between numeric prefix/postfix and letters, or letters and prefix/postfix */
1137 if ((break_class[i] == b_PR && break_class[i+1] == b_AL) ||
1138 (break_class[i] == b_PR && break_class[i+1] == b_HL) ||
1139 (break_class[i] == b_PO && break_class[i+1] == b_AL) ||
1140 (break_class[i] == b_PO && break_class[i+1] == b_HL) ||
1141 (break_class[i] == b_AL && break_class[i+1] == b_PR) ||
1142 (break_class[i] == b_HL && break_class[i+1] == b_PR) ||
1143 (break_class[i] == b_AL && break_class[i+1] == b_PO) ||
1144 (break_class[i] == b_HL && break_class[i+1] == b_PO))
1146
1147 /* LB25 */
1148 if ((break_class[i] == b_CL && break_class[i+1] == b_PO) ||
1149 (break_class[i] == b_CP && break_class[i+1] == b_PO) ||
1150 (break_class[i] == b_CL && break_class[i+1] == b_PR) ||
1151 (break_class[i] == b_CP && break_class[i+1] == b_PR) ||
1152 (break_class[i] == b_NU && break_class[i+1] == b_PO) ||
1153 (break_class[i] == b_NU && break_class[i+1] == b_PR) ||
1154 (break_class[i] == b_PO && break_class[i+1] == b_OP) ||
1155 (break_class[i] == b_PO && break_class[i+1] == b_NU) ||
1156 (break_class[i] == b_PR && break_class[i+1] == b_OP) ||
1157 (break_class[i] == b_PR && break_class[i+1] == b_NU) ||
1158 (break_class[i] == b_HY && break_class[i+1] == b_NU) ||
1159 (break_class[i] == b_IS && break_class[i+1] == b_NU) ||
1160 (break_class[i] == b_NU && break_class[i+1] == b_NU) ||
1161 (break_class[i] == b_SY && break_class[i+1] == b_NU))
1163
1164 /* LB26 */
1165 if (break_class[i] == b_JL)
1166 {
1167 switch (break_class[i+1])
1168 {
1169 case b_JL:
1170 case b_JV:
1171 case b_H2:
1172 case b_H3:
1174 }
1175 }
1176 if ((break_class[i] == b_JV || break_class[i] == b_H2) &&
1177 (break_class[i+1] == b_JV || break_class[i+1] == b_JT))
1179 if ((break_class[i] == b_JT || break_class[i] == b_H3) &&
1180 break_class[i+1] == b_JT)
1182
1183 /* LB27 */
1184 switch (break_class[i])
1185 {
1186 case b_JL:
1187 case b_JV:
1188 case b_JT:
1189 case b_H2:
1190 case b_H3:
1191 if (break_class[i+1] == b_IN || break_class[i+1] == b_PO)
1193 }
1194 if (break_class[i] == b_PR)
1195 {
1196 switch (break_class[i+1])
1197 {
1198 case b_JL:
1199 case b_JV:
1200 case b_JT:
1201 case b_H2:
1202 case b_H3:
1204 }
1205 }
1206
1207 /* LB28 */
1208 if ((break_class[i] == b_AL && break_class[i+1] == b_AL) ||
1209 (break_class[i] == b_AL && break_class[i+1] == b_HL) ||
1210 (break_class[i] == b_HL && break_class[i+1] == b_AL) ||
1211 (break_class[i] == b_HL && break_class[i+1] == b_HL))
1213
1214 /* LB29 */
1215 if ((break_class[i] == b_IS && break_class[i+1] == b_AL) ||
1216 (break_class[i] == b_IS && break_class[i+1] == b_HL))
1218
1219 /* LB30 */
1220 if ((break_class[i] == b_AL || break_class[i] == b_HL || break_class[i] == b_NU) &&
1221 break_class[i+1] == b_OP)
1223 if (break_class[i] == b_CP &&
1224 (break_class[i+1] == b_AL || break_class[i+1] == b_HL || break_class[i+1] == b_NU))
1226
1227 /* LB30a - break between two RIs if and only if there are an even number of RIs preceding position of the break */
1228 if (break_class[i] == b_RI && break_class[i+1] == b_RI) {
1229 unsigned int c = 0;
1230
1231 j = i + 1;
1232 while (j > 0 && break_class[--j] == b_RI)
1233 c++;
1234
1235 if ((c & 1) == 0)
1237 }
1238
1239 /* LB30b - do not break between an emoji base and an emoji modifier */
1240 if (break_class[i] == b_EB && break_class[i+1] == b_EM)
1242 }
1243 }
1244
1245 /* LB31 - allow breaks everywhere else. */
1246 for (i = 0; i < count; i++)
1247 {
1250 }
1251
1252 free(break_class);
1253 free(breaks);
1254
1255 return S_OK;
1256}
1257
1259{
1260 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
1261
1262 if (IsEqualIID(riid, &IID_IDWriteTextAnalyzer2) ||
1263 IsEqualIID(riid, &IID_IDWriteTextAnalyzer1) ||
1264 IsEqualIID(riid, &IID_IDWriteTextAnalyzer) ||
1266 {
1267 *obj = iface;
1268 return S_OK;
1269 }
1270
1271 WARN("%s not implemented.\n", debugstr_guid(riid));
1272
1273 *obj = NULL;
1274 return E_NOINTERFACE;
1275}
1276
1278{
1279 return 2;
1280}
1281
1283{
1284 return 1;
1285}
1286
1289{
1291 HRESULT hr;
1292
1293 TRACE("%p, %u, %u, %p.\n", source, position, length, sink);
1294
1295 if (!length)
1296 return S_OK;
1297
1299
1300 return analyze_script(&context, sink);
1301}
1302
1303static inline unsigned int get_bidi_char_length(const struct bidi_char *c)
1304{
1305 return c->ch > 0xffff ? 2 : 1;
1306}
1307
1309{
1311}
1312
1315{
1317 UINT8 baselevel, resolved, explicit;
1318 unsigned int i, chars_count = 0;
1319 struct bidi_char *chars, *ptr;
1320 UINT32 pos, seq_length;
1321 HRESULT hr;
1322
1323 TRACE("%p, %u, %u, %p.\n", source, position, length, sink);
1324
1325 if (!length)
1326 return S_OK;
1327
1328 if (!(chars = calloc(length, sizeof(*chars))))
1329 return E_OUTOFMEMORY;
1330
1331 ptr = chars;
1334 {
1335 ptr->ch = context.ch;
1336 ptr->nominal_bidi_class = ptr->bidi_class = get_char_bidi_class(context.ch);
1337 ptr++;
1338
1339 ++chars_count;
1340 }
1341
1342 /* Resolve levels using utf-32 codepoints, size differences are accounted for
1343 when levels are reported with SetBidiLevel(). */
1344
1345 baselevel = IDWriteTextAnalysisSource_GetParagraphReadingDirection(source);
1346 hr = bidi_computelevels(chars, chars_count, baselevel);
1347 if (FAILED(hr))
1348 goto done;
1349
1350 pos = position;
1351 resolved = chars->resolved;
1352 explicit = chars->explicit;
1353 seq_length = get_bidi_char_length(chars);
1354
1355 for (i = 1, ptr = chars + 1; i < chars_count; ++i, ++ptr)
1356 {
1357 if (ptr->resolved == resolved && ptr->explicit == explicit)
1358 {
1359 seq_length += get_bidi_char_length(ptr);
1360 }
1361 else
1362 {
1363 hr = IDWriteTextAnalysisSink_SetBidiLevel(sink, pos, seq_length, explicit, resolved);
1364 if (FAILED(hr))
1365 goto done;
1366
1367 pos += seq_length;
1368 seq_length = get_bidi_char_length(ptr);
1369 resolved = ptr->resolved;
1370 explicit = ptr->explicit;
1371 }
1372 }
1373
1374 /* one char length case or normal completion call */
1375 hr = IDWriteTextAnalysisSink_SetBidiLevel(sink, pos, seq_length, explicit, resolved);
1376
1377done:
1378 free(chars);
1379
1380 return hr;
1381}
1382
1385{
1386 static int once;
1387
1388 if (!once++)
1389 FIXME("(%p %u %u %p): stub\n", source, position, length, sink);
1390 return S_OK;
1391}
1392
1395{
1396 DWRITE_LINE_BREAKPOINT *breakpoints;
1397 HRESULT hr;
1398
1399 TRACE("%p, %u, %u, %p.\n", source, position, length, sink);
1400
1401 if (!length)
1402 return S_OK;
1403
1404 if (!(breakpoints = calloc(length, sizeof(*breakpoints))))
1405 return E_OUTOFMEMORY;
1406
1407 if (SUCCEEDED(hr = analyze_linebreaks(source, position, length, breakpoints)))
1408 hr = IDWriteTextAnalysisSink_SetLineBreakpoints(sink, position, length, breakpoints);
1409
1410 free(breakpoints);
1411
1412 return hr;
1413}
1414
1416{
1417 UINT32 language = DWRITE_MAKE_OPENTYPE_TAG('d','f','l','t');
1418
1419 if (locale) {
1420 WCHAR tag[5];
1422 language = DWRITE_MAKE_OPENTYPE_TAG(tag[0],tag[1],tag[2],tag[3]);
1423 }
1424
1425 return language;
1426}
1427
1429{
1432 WCHAR isolang[9];
1433 DWORD lctype;
1434
1435 digits[0] = 0;
1436
1437 if (!numbersubst)
1438 return;
1439
1440 lctype = numbersubst->ignore_user_override ? LOCALE_NOUSEROVERRIDE : 0;
1441
1443 DWORD value;
1444
1446 if (GetLocaleInfoEx(numbersubst->locale, lctype | LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER, (WCHAR *)&value, 2)) {
1447 switch (value)
1448 {
1449 case 0:
1451 break;
1452 case 2:
1454 break;
1455 case 1:
1456 default:
1457 if (value != 1)
1458 WARN("Unknown IDIGITSUBSTITUTION value %lu, locale %s.\n", value, debugstr_w(numbersubst->locale));
1459 }
1460 }
1461 else
1462 WARN("Failed to get IDIGITSUBSTITUTION for locale %s\n", debugstr_w(numbersubst->locale));
1463 }
1464 else
1465 method = numbersubst->method;
1466
1467 switch (method)
1468 {
1471 break;
1474 if (GetLocaleInfoEx(numbersubst->locale, LOCALE_SISO639LANGNAME, isolang, ARRAY_SIZE(isolang)))
1475 {
1476 static const WCHAR arabicW[] = {0x640,0x641,0x642,0x643,0x644,0x645,0x646,0x647,0x648,0x649,0};
1477
1478 /* For some Arabic locales Latin digits are returned for SNATIVEDIGITS */
1479 if (!wcscmp(L"ar", isolang))
1480 {
1481 wcscpy(digits, arabicW);
1482 break;
1483 }
1484 }
1486 break;
1487 default:
1488 ;
1489 }
1490
1492 WARN("Failed to get number substitutes for locale %s, method %d\n", debugstr_w(numbersubst->locale), method);
1494 }
1495
1497 digits[0] = 0;
1498}
1499
1501 UINT32 const *feature_range_lengths, UINT32 feature_ranges)
1502{
1503 UINT32 i, j, start;
1504
1505 if (!TRACE_ON(dwrite) || !features)
1506 return;
1507
1508 for (i = 0, start = 0; i < feature_ranges; start += feature_range_lengths[i++]) {
1509 TRACE("feature range [%u,%u)\n", start, start + feature_range_lengths[i]);
1510 for (j = 0; j < features[i]->featureCount; j++)
1511 TRACE("feature %s, parameter %u\n", debugstr_fourcc(features[i]->features[j].nameTag),
1512 features[i]->features[j].parameter);
1513 }
1514}
1515
1517 WCHAR const* text, UINT32 length, IDWriteFontFace* fontface, BOOL is_sideways,
1518 BOOL is_rtl, DWRITE_SCRIPT_ANALYSIS const* analysis, WCHAR const* locale,
1519 IDWriteNumberSubstitution* substitution, DWRITE_TYPOGRAPHIC_FEATURES const** features,
1520 UINT32 const* feature_range_lengths, UINT32 feature_ranges, UINT32 max_glyph_count,
1521 UINT16* clustermap, DWRITE_SHAPING_TEXT_PROPERTIES* text_props, UINT16 *glyphs,
1522 DWRITE_SHAPING_GLYPH_PROPERTIES* glyph_props, UINT32* actual_glyph_count)
1523{
1524 const struct dwritescript_properties *scriptprops;
1525 struct scriptshaping_context context = { 0 };
1526 struct dwrite_fontface *font_obj;
1528 unsigned int glyph_count;
1529 HRESULT hr;
1530
1531 TRACE("%s:%u, %p, %d, %d, %s, %s, %p, %p, %p, %u, %u, %p, %p, %p, %p, %p.\n", debugstr_wn(text, length),
1532 length, fontface, is_sideways, is_rtl, debugstr_sa_script(analysis->script), debugstr_w(locale), substitution,
1533 features, feature_range_lengths, feature_ranges, max_glyph_count, clustermap, text_props, glyphs,
1534 glyph_props, actual_glyph_count);
1535
1536 analyzer_dump_user_features(features, feature_range_lengths, feature_ranges);
1537
1538 get_number_substitutes(substitution, is_rtl, digits);
1539 font_obj = unsafe_impl_from_IDWriteFontFace(fontface);
1540 glyph_count = max(max_glyph_count, length);
1541
1542 context.cache = fontface_get_shaping_cache(font_obj);
1543 context.script = analysis->script > Script_LastId ? Script_Unknown : analysis->script;
1544 context.text = text;
1545 context.length = length;
1546 context.is_rtl = is_rtl;
1547 context.is_sideways = is_sideways;
1548 context.u.subst.glyphs = calloc(glyph_count, sizeof(*glyphs));
1549 context.u.subst.glyph_props = calloc(glyph_count, sizeof(*glyph_props));
1550 context.u.subst.text_props = text_props;
1551 context.u.subst.clustermap = clustermap;
1552 context.u.subst.max_glyph_count = max_glyph_count;
1553 context.u.subst.capacity = glyph_count;
1554 context.u.subst.digits = digits;
1555 context.language_tag = get_opentype_language(locale);
1556 context.user_features.features = features;
1557 context.user_features.range_lengths = feature_range_lengths;
1558 context.user_features.range_count = feature_ranges;
1559 context.glyph_infos = calloc(glyph_count, sizeof(*context.glyph_infos));
1560 context.table = &context.cache->gsub;
1561
1562 *actual_glyph_count = 0;
1563
1564 if (!context.u.subst.glyphs || !context.u.subst.glyph_props || !context.glyph_infos)
1565 {
1566 hr = E_OUTOFMEMORY;
1567 goto failed;
1568 }
1569
1570 scriptprops = &dwritescripts_properties[context.script];
1571 hr = shape_get_glyphs(&context, scriptprops->scripttags);
1572 if (SUCCEEDED(hr))
1573 {
1574 *actual_glyph_count = context.glyph_count;
1575 memcpy(glyphs, context.u.subst.glyphs, context.glyph_count * sizeof(*glyphs));
1576 memcpy(glyph_props, context.u.subst.glyph_props, context.glyph_count * sizeof(*glyph_props));
1577 }
1578
1579failed:
1580 free(context.u.subst.glyph_props);
1581 free(context.u.subst.glyphs);
1582 free(context.glyph_infos);
1583
1584 return hr;
1585}
1586
1588 WCHAR const* text, UINT16 const* clustermap, DWRITE_SHAPING_TEXT_PROPERTIES *text_props,
1589 UINT32 text_len, UINT16 const* glyphs, DWRITE_SHAPING_GLYPH_PROPERTIES const* glyph_props,
1590 UINT32 glyph_count, IDWriteFontFace *fontface, float emSize, BOOL is_sideways, BOOL is_rtl,
1591 DWRITE_SCRIPT_ANALYSIS const* analysis, WCHAR const* locale, DWRITE_TYPOGRAPHIC_FEATURES const** features,
1592 UINT32 const* feature_range_lengths, UINT32 feature_ranges, float *advances, DWRITE_GLYPH_OFFSET *offsets)
1593{
1594 const struct dwritescript_properties *scriptprops;
1595 struct scriptshaping_context context = { 0 };
1596 struct dwrite_fontface *font_obj;
1597 unsigned int i;
1598 HRESULT hr;
1599
1600 TRACE("%s, %p, %p, %u, %p, %p, %u, %p, %.2f, %d, %d, %s, %s, %p, %p, %u, %p, %p.\n", debugstr_wn(text, text_len),
1601 clustermap, text_props, text_len, glyphs, glyph_props, glyph_count, fontface, emSize, is_sideways,
1602 is_rtl, debugstr_sa_script(analysis->script), debugstr_w(locale), features, feature_range_lengths,
1603 feature_ranges, advances, offsets);
1604
1605 analyzer_dump_user_features(features, feature_range_lengths, feature_ranges);
1606
1607 if (glyph_count == 0)
1608 return S_OK;
1609
1610 font_obj = unsafe_impl_from_IDWriteFontFace(fontface);
1611
1612 for (i = 0; i < glyph_count; ++i)
1613 {
1614 if (glyph_props[i].isZeroWidthSpace)
1615 advances[i] = 0.0f;
1616 else
1617 advances[i] = fontface_get_scaled_design_advance(font_obj, DWRITE_MEASURING_MODE_NATURAL, emSize, 1.0f,
1618 NULL, glyphs[i], is_sideways);
1619 offsets[i].advanceOffset = 0.0f;
1620 offsets[i].ascenderOffset = 0.0f;
1621 }
1622
1623 context.cache = fontface_get_shaping_cache(font_obj);
1624 context.script = analysis->script > Script_LastId ? Script_Unknown : analysis->script;
1625 context.text = text;
1626 context.length = text_len;
1627 context.is_rtl = is_rtl;
1628 context.is_sideways = is_sideways;
1629 context.u.pos.glyphs = glyphs;
1630 context.u.pos.glyph_props = glyph_props;
1631 context.u.pos.text_props = text_props;
1632 context.u.pos.clustermap = clustermap;
1633 context.glyph_count = glyph_count;
1634 context.emsize = emSize;
1635 context.measuring_mode = DWRITE_MEASURING_MODE_NATURAL;
1636 context.advances = advances;
1637 context.offsets = offsets;
1638 context.language_tag = get_opentype_language(locale);
1639 context.user_features.features = features;
1640 context.user_features.range_lengths = feature_range_lengths;
1641 context.user_features.range_count = feature_ranges;
1642 context.glyph_infos = calloc(glyph_count, sizeof(*context.glyph_infos));
1643 context.table = &context.cache->gpos;
1644
1645 if (!context.glyph_infos)
1646 {
1647 hr = E_OUTOFMEMORY;
1648 goto failed;
1649 }
1650
1651 scriptprops = &dwritescripts_properties[context.script];
1652 hr = shape_get_positions(&context, scriptprops->scripttags);
1653
1654failed:
1655 free(context.glyph_infos);
1656
1657 return hr;
1658}
1659
1661 WCHAR const* text, UINT16 const* clustermap, DWRITE_SHAPING_TEXT_PROPERTIES *text_props,
1662 UINT32 text_len, UINT16 const* glyphs, DWRITE_SHAPING_GLYPH_PROPERTIES const* glyph_props,
1663 UINT32 glyph_count, IDWriteFontFace *fontface, float emSize, float ppdip,
1664 DWRITE_MATRIX const* transform, BOOL use_gdi_natural, BOOL is_sideways, BOOL is_rtl,
1665 DWRITE_SCRIPT_ANALYSIS const* analysis, WCHAR const* locale, DWRITE_TYPOGRAPHIC_FEATURES const** features,
1666 UINT32 const* feature_range_lengths, UINT32 feature_ranges, float *advances, DWRITE_GLYPH_OFFSET *offsets)
1667{
1668 const struct dwritescript_properties *scriptprops;
1669 struct scriptshaping_context context = { 0 };
1671 struct dwrite_fontface *font_obj;
1672 unsigned int i;
1673 HRESULT hr;
1674
1675 TRACE("%s, %p, %p, %u, %p, %p, %u, %p, %.2f, %.2f, %p, %d, %d, %d, %s, %s, %p, %p, %u, %p, %p.\n",
1676 debugstr_wn(text, text_len), clustermap, text_props, text_len, glyphs, glyph_props, glyph_count, fontface,
1677 emSize, ppdip, transform, use_gdi_natural, is_sideways, is_rtl, debugstr_sa_script(analysis->script),
1678 debugstr_w(locale), features, feature_range_lengths, feature_ranges, advances, offsets);
1679
1680 analyzer_dump_user_features(features, feature_range_lengths, feature_ranges);
1681
1682 if (glyph_count == 0)
1683 return S_OK;
1684
1685 font_obj = unsafe_impl_from_IDWriteFontFace(fontface);
1686
1687 measuring_mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
1688
1689 for (i = 0; i < glyph_count; ++i)
1690 {
1691 if (glyph_props[i].isZeroWidthSpace)
1692 advances[i] = 0.0f;
1693 else
1694 advances[i] = fontface_get_scaled_design_advance(font_obj, measuring_mode, emSize, ppdip,
1695 transform, glyphs[i], is_sideways);
1696 offsets[i].advanceOffset = 0.0f;
1697 offsets[i].ascenderOffset = 0.0f;
1698 }
1699
1700 context.cache = fontface_get_shaping_cache(font_obj);
1701 context.script = analysis->script > Script_LastId ? Script_Unknown : analysis->script;
1702 context.text = text;
1703 context.length = text_len;
1704 context.is_rtl = is_rtl;
1705 context.is_sideways = is_sideways;
1706 context.u.pos.glyphs = glyphs;
1707 context.u.pos.glyph_props = glyph_props;
1708 context.u.pos.text_props = text_props;
1709 context.u.pos.clustermap = clustermap;
1710 context.glyph_count = glyph_count;
1711 context.emsize = emSize * ppdip;
1712 context.measuring_mode = measuring_mode;
1713 context.advances = advances;
1714 context.offsets = offsets;
1715 context.language_tag = get_opentype_language(locale);
1716 context.user_features.features = features;
1717 context.user_features.range_lengths = feature_range_lengths;
1718 context.user_features.range_count = feature_ranges;
1719 context.glyph_infos = calloc(glyph_count, sizeof(*context.glyph_infos));
1720 context.table = &context.cache->gpos;
1721
1722 if (!context.glyph_infos)
1723 {
1724 hr = E_OUTOFMEMORY;
1725 goto failed;
1726 }
1727
1728 scriptprops = &dwritescripts_properties[context.script];
1729 hr = shape_get_positions(&context, scriptprops->scripttags);
1730
1731failed:
1732 free(context.glyph_infos);
1733
1734 return hr;
1735}
1736
1737static HRESULT apply_cluster_spacing(float leading_spacing, float trailing_spacing, float min_advance_width,
1738 unsigned int start, unsigned int end, float const *advances, DWRITE_GLYPH_OFFSET const *offsets,
1739 DWRITE_SHAPING_GLYPH_PROPERTIES const *glyph_props, float *modified_advances,
1740 DWRITE_GLYPH_OFFSET *modified_offsets)
1741{
1742 BOOL reduced = leading_spacing < 0.0f || trailing_spacing < 0.0f;
1743 unsigned int first_spacing, last_spacing, i;
1744 float advance, origin = 0.0f, *deltas;
1745 BOOL is_spacing_cluster = FALSE;
1746
1747 if (modified_advances != advances)
1748 memcpy(&modified_advances[start], &advances[start], (end - start + 1) * sizeof(*advances));
1749 if (modified_offsets != offsets)
1750 memcpy(&modified_offsets[start], &offsets[start], (end - start + 1) * sizeof(*offsets));
1751
1752 for (first_spacing = start; first_spacing <= end; ++first_spacing)
1753 {
1754 if ((is_spacing_cluster = !glyph_props[first_spacing].isZeroWidthSpace))
1755 break;
1756 }
1757
1758 /* Nothing to adjust if there is no spacing glyphs. */
1759 if (!is_spacing_cluster)
1760 return S_OK;
1761
1762 for (last_spacing = end; last_spacing >= start; --last_spacing)
1763 {
1764 if (!glyph_props[last_spacing].isZeroWidthSpace)
1765 break;
1766 }
1767
1768 if (!(deltas = calloc(end - start + 1, sizeof(*deltas))))
1769 return E_OUTOFMEMORY;
1770
1771 /* Cluster advance, note that properties are ignored. */
1772 origin = offsets[start].advanceOffset;
1773 for (i = start, advance = 0.0f; i <= end; ++i)
1774 {
1775 float cur = advance + offsets[i].advanceOffset;
1776
1777 deltas[i - start] = cur - origin;
1778
1779 advance += advances[i];
1780 origin = cur;
1781 }
1782
1783 /* Negative spacing. */
1784 if (leading_spacing < 0.0f)
1785 {
1786 advance += leading_spacing;
1787 modified_advances[first_spacing] += leading_spacing;
1788 modified_offsets[first_spacing].advanceOffset += leading_spacing;
1789 }
1790
1791 if (trailing_spacing < 0.0f)
1792 {
1793 advance += trailing_spacing;
1794 modified_advances[last_spacing] += trailing_spacing;
1795 }
1796
1797 /* Minimal advance. */
1798 advance = min_advance_width - advance;
1799 if (advance > 0.0f) {
1800 /* Additional spacing is only applied to leading and trailing spacing glyphs. */
1801 float half = advance / 2.0f;
1802
1803 if (!reduced)
1804 {
1805 modified_advances[first_spacing] += half;
1806 modified_advances[last_spacing] += half;
1807 modified_offsets[first_spacing].advanceOffset += half;
1808 }
1809 else if (leading_spacing < 0.0f && trailing_spacing < 0.0f)
1810 {
1811 modified_advances[first_spacing] += half;
1812 modified_advances[last_spacing] += half;
1813 modified_offsets[first_spacing].advanceOffset += half;
1814 }
1815 else if (leading_spacing < 0.0f)
1816 {
1817 modified_advances[first_spacing] += advance;
1818 modified_offsets[first_spacing].advanceOffset += advance;
1819 }
1820 else
1821 modified_advances[last_spacing] += advance;
1822 }
1823
1824 /* Positive spacing. */
1825 if (leading_spacing > 0.0f)
1826 {
1827 modified_advances[first_spacing] += leading_spacing;
1828 modified_offsets[first_spacing].advanceOffset += leading_spacing;
1829 }
1830
1831 if (trailing_spacing > 0.0f)
1832 modified_advances[last_spacing] += trailing_spacing;
1833
1834 /* Update offsets to preserve original relative positions within cluster. */
1835 for (i = first_spacing; i > start; --i)
1836 {
1837 unsigned int cur = i - 1;
1838 modified_offsets[cur].advanceOffset = modified_advances[cur] + modified_offsets[i].advanceOffset -
1839 deltas[i - start];
1840 }
1841
1842 for (i = first_spacing + 1; i <= end; ++i)
1843 {
1844 modified_offsets[i].advanceOffset = deltas[i - start] + modified_offsets[i - 1].advanceOffset -
1845 modified_advances[i - 1];
1846 }
1847
1848 free(deltas);
1849
1850 return S_OK;
1851}
1852
1853static inline UINT32 get_cluster_length(UINT16 const *clustermap, UINT32 start, UINT32 text_len)
1854{
1855 UINT16 g = clustermap[start];
1856 UINT32 length = 1;
1857
1858 while (start < (text_len - 1) && clustermap[++start] == g)
1859 length++;
1860 return length;
1861}
1862
1863/* Applies spacing adjustments to clusters.
1864
1865 Adjustments are applied in the following order:
1866
1867 1. Negative adjustments
1868
1869 Leading and trailing spacing could be negative, at this step
1870 only negative ones are actually applied. Leading spacing is only
1871 applied to leading glyph, trailing - to trailing glyph.
1872
1873 2. Minimum advance width
1874
1875 Advances could only be reduced at this point or unchanged. In any
1876 case it's checked if cluster advance width is less than minimum width.
1877 If it's the case advance width is incremented up to minimum value.
1878
1879 Important part is the direction in which this increment is applied;
1880 it depends on direction from which total cluster advance was trimmed
1881 at step 1. So it could be incremented from leading, trailing, or both
1882 sides. When applied to both sides, each side gets half of difference
1883 that brings advance to minimum width.
1884
1885 3. Positive adjustments
1886
1887 After minimum width rule was applied, positive spacing is applied in the same
1888 way as negative one on step 1.
1889
1890 Glyph offset for leading glyph is adjusted too in a way that glyph origin
1891 keeps its position in coordinate system where initial advance width is counted
1892 from 0.
1893
1894 Glyph properties
1895
1896 It's known that isZeroWidthSpace property keeps initial advance from changing.
1897
1898*/
1900 FLOAT leading_spacing, FLOAT trailing_spacing, FLOAT min_advance_width, UINT32 len,
1901 UINT32 glyph_count, UINT16 const *clustermap, FLOAT const *advances, DWRITE_GLYPH_OFFSET const *offsets,
1902 DWRITE_SHAPING_GLYPH_PROPERTIES const *props, FLOAT *modified_advances, DWRITE_GLYPH_OFFSET *modified_offsets)
1903{
1904 unsigned int i;
1905
1906 TRACE("%.2f, %.2f, %.2f, %u, %u, %p, %p, %p, %p, %p, %p.\n", leading_spacing, trailing_spacing, min_advance_width,
1907 len, glyph_count, clustermap, advances, offsets, props, modified_advances, modified_offsets);
1908
1909 if (min_advance_width < 0.0f) {
1910 if (modified_advances != advances)
1911 memset(modified_advances, 0, glyph_count*sizeof(*modified_advances));
1912 return E_INVALIDARG;
1913 }
1914
1915 for (i = 0; i < len;)
1916 {
1917 unsigned int length = get_cluster_length(clustermap, i, len);
1918 unsigned int start, end;
1919
1920 start = clustermap[i];
1921 end = i + length < len ? clustermap[i + length] : glyph_count;
1922
1923 apply_cluster_spacing(leading_spacing, trailing_spacing, min_advance_width, start, end - 1, advances,
1924 offsets, props, modified_advances, modified_offsets);
1925
1926 i += length;
1927 }
1928
1929 return S_OK;
1930}
1931
1933 DWRITE_BASELINE baseline, BOOL vertical, BOOL is_simulation_allowed, DWRITE_SCRIPT_ANALYSIS sa,
1934 const WCHAR *localeName, INT32 *baseline_coord, BOOL *exists)
1935{
1936 struct dwrite_fontface *font_obj;
1938
1939 TRACE("%p, %d, %d, %u, %s, %p, %p.\n", fontface, vertical, is_simulation_allowed, sa.script, debugstr_w(localeName),
1940 baseline_coord, exists);
1941
1942 *exists = FALSE;
1943 *baseline_coord = 0;
1944
1947
1948 if ((unsigned int)baseline > DWRITE_BASELINE_MAXIMUM)
1949 return E_INVALIDARG;
1950
1951 /* TODO: fetch BASE table data if available. */
1952
1953 if (!*exists && is_simulation_allowed)
1954 {
1955 font_obj = unsafe_impl_from_IDWriteFontFace(fontface);
1956 metrics = &font_obj->metrics;
1957
1958 switch (baseline)
1959 {
1961 *baseline_coord = vertical ? metrics->descent : 0;
1962 break;
1964 *baseline_coord = vertical ? (metrics->ascent + metrics->descent) / 2 :
1965 -(metrics->ascent - metrics->descent) / 2;
1966 break;
1968 *baseline_coord = vertical ? (metrics->ascent + metrics->descent) / 2 :
1969 -(metrics->ascent + metrics->descent) / 2;
1970 break;
1972 /* FIXME: this one isn't accurate, but close. */
1973 *baseline_coord = vertical ? metrics->capHeight * 6 / 7 + metrics->descent : metrics->capHeight * 6 / 7;
1974 break;
1977 *baseline_coord = vertical ? 0 : metrics->descent;
1978 break;
1981 *baseline_coord = vertical ? metrics->ascent + metrics->descent : -metrics->ascent;
1982 break;
1983 default:
1984 ;
1985 }
1986 }
1987
1988 return S_OK;
1989}
1990
1993{
1994 FIXME("(%p %u %u %p): stub\n", source, text_pos, len, sink);
1995 return E_NOTIMPL;
1996}
1997
2000{
2001 TRACE("%d, %d, %p.\n", angle, is_sideways, transform);
2002
2003 return IDWriteTextAnalyzer2_GetGlyphOrientationTransform(iface, angle, is_sideways, 0.0, 0.0, transform);
2004}
2005
2008{
2009 TRACE("%u, %p.\n", sa.script, props);
2010
2011 if (sa.script > Script_LastId)
2012 return E_INVALIDARG;
2013
2014 *props = dwritescripts_properties[sa.script].props;
2015 return S_OK;
2016}
2017
2019{
2021 /* LRM, RLM, LRE, RLE, PDF, LRO, RLO */
2022 c == 0x200e || c == 0x200f || (c >= 0x202a && c <= 0x202e))
2023 return FALSE;
2024 else {
2026 return !dwritescripts_properties[script].is_complex;
2027 }
2028}
2029
2031 UINT32 len, IDWriteFontFace *face, BOOL *is_simple, UINT32 *len_read, UINT16 *indices)
2032{
2033 HRESULT hr = S_OK;
2034 int i;
2035
2036 TRACE("%s:%u, %p, %p, %p, %p.\n", debugstr_wn(text, len), len, face, is_simple, len_read, indices);
2037
2038 *is_simple = FALSE;
2039 *len_read = 0;
2040
2041 if (!face)
2042 return E_INVALIDARG;
2043
2044 if (len == 0) {
2045 *is_simple = TRUE;
2046 return S_OK;
2047 }
2048
2049 *is_simple = text[0] && is_char_from_simple_script(text[0]);
2050 for (i = 1; i < len && text[i]; i++) {
2052 if (!*is_simple)
2053 break;
2054 }
2055 else
2056 *is_simple = FALSE;
2057 }
2058
2059 *len_read = i;
2060
2061 /* fetch indices */
2062 if (*is_simple && indices)
2063 {
2064 UINT32 *codepoints;
2065
2066 if (!(codepoints = calloc(*len_read, sizeof(*codepoints))))
2067 return E_OUTOFMEMORY;
2068
2069 for (i = 0; i < *len_read; i++)
2070 codepoints[i] = text[i];
2071
2072 hr = IDWriteFontFace_GetGlyphIndices(face, codepoints, *len_read, indices);
2073 free(codepoints);
2074 }
2075
2076 return hr;
2077}
2078
2080 IDWriteFontFace *face, FLOAT font_em_size, DWRITE_SCRIPT_ANALYSIS sa, UINT32 length, UINT32 glyph_count,
2081 const WCHAR *text, const UINT16 *clustermap, const DWRITE_SHAPING_GLYPH_PROPERTIES *prop, DWRITE_JUSTIFICATION_OPPORTUNITY *jo)
2082{
2083 FIXME("(%p %.2f %u %u %u %s %p %p %p): stub\n", face, font_em_size, sa.script, length, glyph_count,
2084 debugstr_wn(text, length), clustermap, prop, jo);
2085 return E_NOTIMPL;
2086}
2087
2089 FLOAT width, UINT32 glyph_count, const DWRITE_JUSTIFICATION_OPPORTUNITY *jo, const FLOAT *advances,
2090 const DWRITE_GLYPH_OFFSET *offsets, FLOAT *justifiedadvances, DWRITE_GLYPH_OFFSET *justifiedoffsets)
2091{
2092 FIXME("(%.2f %u %p %p %p %p %p): stub\n", width, glyph_count, jo, advances, offsets, justifiedadvances,
2093 justifiedoffsets);
2094 return E_NOTIMPL;
2095}
2096
2099 UINT32 glyph_count, UINT32 max_glyphcount, const UINT16 *clustermap, const UINT16 *indices,
2100 const FLOAT *advances, const FLOAT *justifiedadvances, const DWRITE_GLYPH_OFFSET *justifiedoffsets,
2101 const DWRITE_SHAPING_GLYPH_PROPERTIES *prop, UINT32 *actual_count, UINT16 *modified_clustermap,
2102 UINT16 *modified_indices, FLOAT *modified_advances, DWRITE_GLYPH_OFFSET *modified_offsets)
2103{
2104 FIXME("(%p %.2f %u %u %u %u %p %p %p %p %p %p %p %p %p %p %p): stub\n", face, font_em_size, sa.script,
2105 length, glyph_count, max_glyphcount, clustermap, indices, advances, justifiedadvances, justifiedoffsets,
2106 prop, actual_count, modified_clustermap, modified_indices, modified_advances, modified_offsets);
2107 return E_NOTIMPL;
2108}
2109
2111 DWRITE_GLYPH_ORIENTATION_ANGLE angle, BOOL is_sideways, FLOAT originX, FLOAT originY, DWRITE_MATRIX *m)
2112{
2113 static const DWRITE_MATRIX transforms[] = {
2114 { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f },
2115 { 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f },
2116 { -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f },
2117 { 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f }
2118 };
2119
2120 TRACE("%d, %d, %.2f, %.2f, %p.\n", angle, is_sideways, originX, originY, m);
2121
2123 memset(m, 0, sizeof(*m));
2124 return E_INVALIDARG;
2125 }
2126
2127 /* for sideways case simply rotate 90 degrees more */
2128 if (is_sideways) {
2129 switch (angle) {
2132 break;
2135 break;
2138 break;
2141 break;
2142 default:
2143 ;
2144 }
2145 }
2146
2147 *m = transforms[angle];
2148
2149 /* shift components represent transform necessary to get from original point to
2150 rotated one in new coordinate system */
2151 if ((originX != 0.0f || originY != 0.0f) && angle != DWRITE_GLYPH_ORIENTATION_ANGLE_0_DEGREES) {
2152 m->dx = originX - (m->m11 * originX + m->m21 * originY);
2153 m->dy = originY - (m->m12 * originX + m->m22 * originY);
2154 }
2155
2156 return S_OK;
2157}
2158
2161 UINT32 max_tagcount, UINT32 *actual_tagcount, DWRITE_FONT_FEATURE_TAG *tags)
2162{
2163 struct scriptshaping_context context = { 0 };
2164 const struct dwritescript_properties *props;
2165 struct dwrite_fontface *font_obj;
2166
2167 TRACE("%p, %p, %u, %s, %u, %p, %p.\n", iface, fontface, sa.script, debugstr_w(locale), max_tagcount,
2168 actual_tagcount, tags);
2169
2170 if (sa.script > Script_LastId)
2171 return E_INVALIDARG;
2172
2173 font_obj = unsafe_impl_from_IDWriteFontFace(fontface);
2174
2175 context.cache = fontface_get_shaping_cache(font_obj);
2176 context.language_tag = get_opentype_language(locale);
2178
2179 return shape_get_typographic_features(&context, props->scripttags, max_tagcount, actual_tagcount, tags);
2180};
2181
2184 UINT32 glyph_count, const UINT16 *glyphs, UINT8 *feature_applies)
2185{
2186 struct scriptshaping_context context = { 0 };
2187 const struct dwritescript_properties *props;
2188 struct dwrite_fontface *font_obj;
2189 HRESULT hr;
2190
2191 TRACE("%p, %p, %u, %s, %s, %u, %p, %p.\n", iface, fontface, sa.script, debugstr_w(locale), debugstr_fourcc(feature),
2192 glyph_count, glyphs, feature_applies);
2193
2194 if (sa.script > Script_LastId)
2195 return E_INVALIDARG;
2196
2197 font_obj = unsafe_impl_from_IDWriteFontFace(fontface);
2198
2199 context.cache = fontface_get_shaping_cache(font_obj);
2200 context.language_tag = get_opentype_language(locale);
2201 if (!(context.glyph_infos = calloc(glyph_count, sizeof(*context.glyph_infos))))
2202 return E_OUTOFMEMORY;
2203
2205
2206 hr = shape_check_typographic_feature(&context, props->scripttags, feature, glyph_count, glyphs, feature_applies);
2207
2208 free(context.glyph_infos);
2209
2210 return hr;
2211}
2212
2213static const IDWriteTextAnalyzer2Vtbl textanalyzervtbl =
2214{
2237};
2238
2240
2242{
2243 return &textanalyzer;
2244}
2245
2247{
2248 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2249
2250 if (IsEqualIID(riid, &IID_IDWriteNumberSubstitution) ||
2252 {
2253 *obj = iface;
2254 IDWriteNumberSubstitution_AddRef(iface);
2255 return S_OK;
2256 }
2257
2258 WARN("%s not implemented.\n", debugstr_guid(riid));
2259
2260 *obj = NULL;
2261
2262 return E_NOINTERFACE;
2263}
2264
2266{
2269
2270 TRACE("%p, refcount %ld.\n", iface, refcount);
2271
2272 return refcount;
2273}
2274
2276{
2279
2280 TRACE("%p, refcount %ld.\n", iface, refcount);
2281
2282 if (!refcount)
2283 {
2284 free(object->locale);
2285 free(object);
2286 }
2287
2288 return refcount;
2289}
2290
2291static const IDWriteNumberSubstitutionVtbl numbersubstitutionvtbl =
2292{
2296};
2297
2299{
2300 if (!iface || iface->lpVtbl != &numbersubstitutionvtbl)
2301 return NULL;
2303}
2304
2307{
2308 struct dwrite_numbersubstitution *substitution;
2309
2310 *ret = NULL;
2311
2313 return E_INVALIDARG;
2314
2316 return E_INVALIDARG;
2317
2318 if (!(substitution = calloc(1, sizeof(*substitution))))
2319 return E_OUTOFMEMORY;
2320
2322 substitution->refcount = 1;
2324 substitution->method = method;
2325 substitution->locale = wcsdup(locale);
2326 if (locale && !substitution->locale)
2327 {
2328 free(substitution);
2329 return E_OUTOFMEMORY;
2330 }
2331
2332 *ret = &substitution->IDWriteNumberSubstitution_iface;
2333 return S_OK;
2334}
2335
2336/* IDWriteFontFallback */
2338{
2339 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2340
2341 if (IsEqualIID(riid, &IID_IDWriteFontFallback1) ||
2342 IsEqualIID(riid, &IID_IDWriteFontFallback) ||
2344 {
2345 *obj = iface;
2346 IDWriteFontFallback1_AddRef(iface);
2347 return S_OK;
2348 }
2349
2350 WARN("%s not implemented.\n", debugstr_guid(riid));
2351
2352 *obj = NULL;
2353 return E_NOINTERFACE;
2354}
2355
2357{
2358 struct dwrite_fontfallback *fallback = impl_from_IDWriteFontFallback1(iface);
2359
2360 TRACE("%p.\n", iface);
2361
2362 return IDWriteFactory7_AddRef(fallback->factory);
2363}
2364
2366{
2367 struct dwrite_fontfallback *fallback = impl_from_IDWriteFontFallback1(iface);
2368
2369 TRACE("%p.\n", fallback);
2370
2371 return IDWriteFactory7_Release(fallback->factory);
2372}
2373
2375{
2376 /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */
2377 if (context->ch >= 0x180b && context->ch <= 0x180d) return TRUE;
2378 /* VARIATION SELECTOR-1..16 */
2379 if (context->ch >= 0xfe00 && context->ch <= 0xfe0f) return TRUE;
2380 /* VARIATION SELECTOR-17..256 */
2381 if (context->ch >= 0xe0100 && context->ch <= 0xe01ef) return TRUE;
2382 return FALSE;
2383}
2384
2386 UINT32 position, UINT32 length)
2387{
2389 UINT32 mapped = 0;
2390
2393 {
2394 /* Ignore selectors that are not leading. */
2395 if (!mapped || !fallback_is_uvs(&context))
2396 {
2397 if (!IDWriteFont3_HasCharacter(font, context.ch)) break;
2398 }
2400 }
2401
2402 return mapped;
2403}
2404
2407 DWRITE_FONT_STRETCH stretch, IDWriteFont **ret_font, UINT32 *ret_length, float *scale)
2408{
2409 const struct fallback_mapping *mapping = NULL;
2411 const struct fallback_data *data;
2412 const WCHAR *locale_name = NULL;
2413 struct fallback_locale *locale;
2414 UINT32 i, length = 0, mapped;
2416 HRESULT hr;
2417
2418 /* ~0u is a marker for system fallback data */
2419 data = fallback->data.count == ~0u ? &system_fallback : &fallback->data;
2420
2421 /* We will try to map as much of given input as GetLocaleName() says. It's assumed that returned length covers
2422 whole span of characters set with that locale, so callback is only used once. */
2423 if (FAILED(hr = IDWriteTextAnalysisSource_GetLocaleName(source, position, &length, &locale_name)))
2424 return hr;
2425
2426 length = length ? min(length, text_length) : text_length;
2427 if (!locale_name) locale_name = L"";
2428
2429 /* Lookup locale entry once, if specific locale is missing neutral one will be returned. */
2431
2432 if (FAILED(hr = text_source_context_init(&context, source, position, length))) return hr;
2433
2434 /* Find a mapping for given locale. */
2439 {
2440 if (find_fallback_mapping(data, locale, context.ch) != mapping) break;
2442 }
2443
2444 if (!mapping)
2445 {
2446 *ret_font = NULL;
2447 *ret_length = mapped;
2448
2449 return S_OK;
2450 }
2451
2452 /* Go through families in the mapping, use first family that supports some of the input. */
2453 for (i = 0; i < mapping->families_count; ++i)
2454 {
2455 if (SUCCEEDED(create_matching_font(mapping->collection ? mapping->collection : fallback->systemcollection,
2456 mapping->families[i], weight, style, stretch, &IID_IDWriteFont3, (void **)&font)))
2457 {
2458 if (!(mapped = fallback_font_get_supported_length(font, source, position, mapped)))
2459 {
2460 IDWriteFont3_Release(font);
2461 continue;
2462 }
2463
2464 *ret_font = (IDWriteFont *)font;
2465 *ret_length = mapped;
2466 *scale = mapping->scale;
2467
2468 return S_OK;
2469 }
2470 }
2471
2472 /* Mapping was found, but either font couldn't be created or there's no font that supports given input. */
2473 *ret_font = NULL;
2474 *ret_length = length;
2475
2476 return S_OK;
2477}
2478
2481{
2482 IDWriteFontFamily *family;
2483 BOOL exists = FALSE;
2485 HRESULT hr;
2486 UINT32 i;
2487
2488 *obj = NULL;
2489
2490 hr = IDWriteFontCollection_FindFamilyName(collection, name, &i, &exists);
2491 if (FAILED(hr))
2492 return hr;
2493
2494 if (!exists)
2495 return E_FAIL;
2496
2497 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
2498 if (FAILED(hr))
2499 return hr;
2500
2501 hr = IDWriteFontFamily_GetFirstMatchingFont(family, weight, stretch, style, &font);
2502 IDWriteFontFamily_Release(family);
2503
2504 if (SUCCEEDED(hr))
2505 {
2506 hr = IDWriteFont_QueryInterface(font, riid, obj);
2507 IDWriteFont_Release(font);
2508 }
2509
2510 return hr;
2511}
2512
2514 UINT32 position, UINT32 length, IDWriteFontCollection *basecollection, const WCHAR *basefamily,
2516 IDWriteFont **ret_font, float *scale)
2517{
2518 struct dwrite_fontfallback *fallback = impl_from_IDWriteFontFallback1(iface);
2520
2521 TRACE("%p, %p, %u, %u, %p, %s, %u, %u, %u, %p, %p, %p.\n", iface, source, position, length,
2522 basecollection, debugstr_w(basefamily), weight, style, stretch, mapped_length, ret_font, scale);
2523
2524 *mapped_length = 0;
2525 *ret_font = NULL;
2526 *scale = 1.0f;
2527
2528 if (!source)
2529 return E_INVALIDARG;
2530
2531 if (!length)
2532 return S_OK;
2533
2534 if (!basecollection)
2535 basecollection = fallback->systemcollection;
2536
2537 if (basefamily && *basefamily)
2538 {
2539 if (SUCCEEDED(create_matching_font(basecollection, basefamily, weight, style, stretch,
2540 &IID_IDWriteFont, (void **)&font)))
2541 {
2542 if ((*mapped_length = fallback_font_get_supported_length(font, source, position, length)))
2543 {
2544 *ret_font = (IDWriteFont *)font;
2545 *scale = 1.0f;
2546 return S_OK;
2547 }
2548 IDWriteFont3_Release(font);
2549 }
2550 }
2551
2552 return fallback_map_characters(fallback, source, position, length, weight, style, stretch, ret_font, mapped_length, scale);
2553}
2554
2556 UINT32 position, UINT32 length, IDWriteFontCollection *basecollection, const WCHAR *basefamily,
2557 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 values_count, UINT32 *mapped_length, FLOAT *scale,
2558 IDWriteFontFace5 **ret_fontface)
2559{
2560 FIXME("%p, %p, %u, %u, %p, %s, %p, %u, %p, %p, %p.\n", iface, source, position, length, basecollection,
2561 debugstr_w(basefamily), axis_values, values_count, mapped_length, scale, ret_fontface);
2562
2563 return E_NOTIMPL;
2564}
2565
2566static const IDWriteFontFallback1Vtbl fontfallbackvtbl =
2567{
2573};
2574
2576{
2577 struct dwrite_fontfallback *fallback = impl_from_IDWriteFontFallback1(iface);
2578 IDWriteFontCollection_Release(fallback->systemcollection);
2579 free(fallback);
2580}
2581
2583{
2584 struct dwrite_fontfallback *fallback = impl_from_IDWriteFontFallback1(iface);
2586
2587 TRACE("%p, refcount %lu.\n", iface, refcount);
2588
2589 return refcount;
2590}
2591
2593{
2594 struct dwrite_fontfallback *fallback = impl_from_IDWriteFontFallback1(iface);
2596
2597 TRACE("%p, refcount %lu.\n", iface, refcount);
2598
2599 if (!refcount)
2600 {
2601 IDWriteFactory7_Release(fallback->factory);
2602 if (fallback->systemcollection)
2603 IDWriteFontCollection_Release(fallback->systemcollection);
2604 release_fallback_data(&fallback->data);
2605 free(fallback);
2606 }
2607
2608 return refcount;
2609}
2610
2611static const IDWriteFontFallback1Vtbl customfontfallbackvtbl =
2612{
2618};
2619
2621{
2622 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2623
2624 if (IsEqualIID(riid, &IID_IDWriteFontFallbackBuilder) || IsEqualIID(riid, &IID_IUnknown)) {
2625 *obj = iface;
2626 IDWriteFontFallbackBuilder_AddRef(iface);
2627 return S_OK;
2628 }
2629
2630 WARN("%s not implemented.\n", debugstr_guid(riid));
2631
2632 *obj = NULL;
2633 return E_NOINTERFACE;
2634}
2635
2637{
2639 ULONG refcount = InterlockedIncrement(&fallbackbuilder->refcount);
2640
2641 TRACE("%p, refcount %ld.\n", iface, refcount);
2642
2643 return refcount;
2644}
2645
2647{
2650
2651 TRACE("%p, refcount %ld.\n", iface, refcount);
2652
2653 if (!refcount)
2654 {
2655 IDWriteFactory7_Release(builder->factory);
2656 release_fallback_data(&builder->data);
2657 free(builder);
2658 }
2659
2660 return refcount;
2661}
2662
2664 const WCHAR *locale_name)
2665{
2666 struct fallback_locale *locale;
2667
2668 if (!locale_name) locale_name = L"";
2669 if ((locale = font_fallback_get_locale(&builder->data.locales, locale_name))) return locale;
2670 if (!(locale = calloc(1, sizeof(*locale)))) return NULL;
2672 list_add_tail(&builder->data.locales, &locale->entry);
2673 return locale;
2674}
2675
2677 const DWRITE_UNICODE_RANGE *ranges, UINT32 ranges_count, WCHAR const **families, UINT32 families_count,
2678 IDWriteFontCollection *collection, WCHAR const *locale_name, WCHAR const *base_family, float scale)
2679{
2681 struct fallback_mapping *mapping;
2682 struct fallback_locale *locale;
2683 unsigned int i, j, m, count;
2684
2685 TRACE("%p, %p, %u, %p, %u, %p, %s, %s, %f.\n", iface, ranges, ranges_count, families, families_count,
2687
2688 if (!ranges || !ranges_count || !families || !families_count || scale < 0.0f)
2689 return E_INVALIDARG;
2690
2691 if (base_family)
2692 FIXME("base family ignored.\n");
2693
2694 if (!dwrite_array_reserve((void **)&builder->data.mappings, &builder->mappings_size,
2695 builder->data.count + 1, sizeof(*builder->data.mappings)))
2696 {
2697 return E_OUTOFMEMORY;
2698 }
2699
2700 mapping = &builder->data.mappings[builder->data.count];
2701 memset(mapping, 0, sizeof(*mapping));
2702
2703 /* Append new mapping, link to its locale node. */
2704
2706 return E_FAIL;
2707
2708 if (!(mapping->ranges = calloc(ranges_count, sizeof(*mapping->ranges))))
2709 goto failed;
2710
2711 /* Filter ranges that won't be usable. */
2712 for (i = 0, count = 0; i < ranges_count; ++i)
2713 {
2714 if (ranges[i].first > ranges[i].last) continue;
2715 if (ranges[i].first > 0x10ffff) continue;
2716 mapping->ranges[count].first = ranges[i].first;
2717 mapping->ranges[count].last = min(ranges[i].last, 0x10ffff);
2718 count++;
2719 }
2720 if (!count)
2721 {
2723 return S_OK;
2724 }
2725
2726 mapping->ranges_count = count;
2727
2728 if (!(mapping->families = calloc(families_count, sizeof(*mapping->families))))
2729 goto failed;
2730 mapping->families_count = families_count;
2731 for (i = 0; i < families_count; i++)
2732 if (!(mapping->families[i] = wcsdup(families[i]))) goto failed;
2733 mapping->scale = scale;
2734
2735 if (FAILED(fallback_locale_add_mapping(locale, builder->data.count))) goto failed;
2736
2737 /* Mappings with explicit collections take priority, for that reduce existing mappings ranges
2738 by newly added ranges. */
2739
2740 mapping->collection = collection;
2741 if (mapping->collection)
2742 {
2743 IDWriteFontCollection_AddRef(mapping->collection);
2744
2745 for (m = 0; m < builder->data.count; ++m)
2746 {
2747 struct fallback_mapping *c = &builder->data.mappings[m];
2748 if (c->collection) continue;
2749 for (i = 0; i < count; ++i)
2750 {
2751 const DWRITE_UNICODE_RANGE *new_range = &mapping->ranges[i];
2752
2753 for (j = 0; j < c->ranges_count; ++j)
2754 {
2755 DWRITE_UNICODE_RANGE *range = &c->ranges[j];
2756
2757 /* In case existing ranges intersect, disable or reduce them */
2758 if (range->first >= new_range->first && range->last <= new_range->last)
2759 {
2760 range->first = range->last = ~0u;
2761 }
2762 else if (range->first >= new_range->first && range->first <= new_range->last)
2763 {
2764 range->first = new_range->last;
2765 }
2766 else if (range->last >= new_range->first && range->last <= new_range->last)
2767 {
2768 range->last = new_range->first;
2769 }
2770 }
2771 }
2772 }
2773 }
2774
2775 builder->data.count++;
2776 return S_OK;
2777
2778failed:
2780 return E_OUTOFMEMORY;
2781}
2782
2784{
2785 FIXME("%p, %p stub.\n", iface, fallback);
2786
2787 return E_NOTIMPL;
2788}
2789
2791 struct fallback_data *data)
2792{
2793 struct fallback_locale *iter, *locale;
2794 size_t i, j;
2795
2796 /* Duplicate locales list. */
2797 list_init(&data->locales);
2798 LIST_FOR_EACH_ENTRY(iter, &builder->data.locales, struct fallback_locale, entry)
2799 {
2800 if (!(locale = calloc(1, sizeof(*locale)))) goto failed;
2801 wcscpy(locale->name, iter->name);
2802 locale->ranges.count = iter->ranges.count;
2803 locale->ranges.size = iter->ranges.count;
2804 if (!(locale->ranges.data = malloc(iter->ranges.count * sizeof(*iter->ranges.data))))
2805 {
2806 free(locale);
2807 goto failed;
2808 }
2809 memcpy(locale->ranges.data, iter->ranges.data, iter->ranges.count * sizeof(*iter->ranges.data));
2810 list_add_tail(&data->locales, &locale->entry);
2811 }
2812
2813 /* Duplicate mappings. */
2814 if (!(data->mappings = calloc(builder->data.count, sizeof(*data->mappings))))
2815 goto failed;
2816
2817 data->count = builder->data.count;
2818 for (i = 0; i < data->count; ++i)
2819 {
2820 struct fallback_mapping *src = &builder->data.mappings[i];
2821 struct fallback_mapping *dst = &data->mappings[i];
2822
2823 if (!(dst->ranges = calloc(src->ranges_count, sizeof(*src->ranges)))) goto failed;
2824 memcpy(dst->ranges, src->ranges, src->ranges_count * sizeof(*src->ranges));
2825 dst->ranges_count = src->ranges_count;
2826
2827 if (!(dst->families = calloc(src->families_count, sizeof(*src->families)))) goto failed;
2828 dst->families_count = src->families_count;
2829 for (j = 0; j < src->families_count; ++j)
2830 {
2831 if (!(dst->families[j] = wcsdup(src->families[j]))) goto failed;
2832 }
2833
2834 dst->collection = src->collection;
2835 if (dst->collection)
2836 IDWriteFontCollection_AddRef(dst->collection);
2837 dst->scale = src->scale;
2838 }
2839
2840 return S_OK;
2841
2842failed:
2843
2844 return E_OUTOFMEMORY;
2845}
2846
2848{
2849 struct dwrite_fontfallback *fallback;
2850 HRESULT hr;
2851
2852 if (!(fallback = calloc(1, sizeof(*fallback))))
2853 return E_OUTOFMEMORY;
2854
2856 fallback->refcount = 1;
2857 fallback->factory = builder->factory;
2858 IDWriteFactory7_AddRef(fallback->factory);
2859 if (FAILED(hr = IDWriteFactory_GetSystemFontCollection((IDWriteFactory *)fallback->factory,
2860 &fallback->systemcollection, FALSE)))
2861 {
2862 goto done;
2863 }
2864
2865 if (FAILED(hr = fallbackbuilder_init_fallback_data(builder, &fallback->data)))
2866 {
2867 goto done;
2868 }
2869
2870 *ret = fallback;
2871
2872 return S_OK;
2873
2874done:
2875
2876 IDWriteFontFallback1_Release(&fallback->IDWriteFontFallback1_iface);
2877 return hr;
2878}
2879
2882{
2884 struct dwrite_fontfallback *fallback;
2885 HRESULT hr;
2886
2887 TRACE("%p, %p.\n", iface, ret);
2888
2889 *ret = NULL;
2890
2891 if (SUCCEEDED(hr = fallbackbuilder_create_fallback(builder, &fallback)))
2892 {
2894 }
2895
2896 return hr;
2897}
2898
2899static const IDWriteFontFallbackBuilderVtbl fontfallbackbuildervtbl =
2900{
2907};
2908
2910{
2911 struct dwrite_fontfallback_builder *builder;
2912
2913 *ret = NULL;
2914
2915 if (!(builder = calloc(1, sizeof(*builder))))
2916 return E_OUTOFMEMORY;
2917
2919 builder->refcount = 1;
2920 builder->factory = factory;
2921 IDWriteFactory7_AddRef(builder->factory);
2922 list_init(&builder->data.locales);
2923
2924 *ret = builder;
2925
2926 return S_OK;
2927}
2928
2930{
2931 struct dwrite_fontfallback_builder *builder;
2932 HRESULT hr;
2933
2934 *ret = NULL;
2935
2938
2939 return hr;
2940}
2941
2943 unsigned int max_count, unsigned int *ret)
2944{
2945 unsigned int count = 0;
2946 char *end;
2947
2948 while (*str && count < max_count)
2949 {
2950 ranges[count].first = ranges[count].last = strtoul(str, &end, 16);
2951 if (*end == '-')
2952 {
2953 str = end + 1;
2954 ranges[count].last = strtoul(str, &end, 16);
2955 }
2956 str = end;
2957 if (*str == ',') str++;
2958 count++;
2959 }
2960
2961 *ret = count;
2962}
2963
2964static void system_fallback_parse_families(WCHAR *str, WCHAR **families, unsigned int max_count,
2965 unsigned int *ret)
2966{
2967 unsigned int count = 0;
2968 WCHAR *family, *ctx;
2969
2970 family = wcstok_s(str, L",", &ctx);
2971 while (family && count < max_count)
2972 {
2973 while (*family == ' ') family++;
2974 families[count++] = family;
2975 family = wcstok_s(NULL, L",", &ctx);
2976 }
2977
2978 *ret = count;
2979}
2980
2982
2983/* Particular factory instance used for initialization is not important, it won't be referenced by
2984 created fallback data. */
2986{
2987 struct dwrite_fontfallback_builder *builder;
2988 IDWriteFontFallbackBuilder *builder_iface;
2989 unsigned int range_count, families_count;
2991 DWRITE_UNICODE_RANGE ranges[16];
2992 WCHAR *families[4], *str;
2993 HRESULT hr;
2994 size_t i;
2995
2997 builder_iface = &builder->IDWriteFontFallbackBuilder_iface;
2998
2999 for (i = 0; i < ARRAY_SIZE(system_fallback_config); ++i)
3000 {
3002
3003 system_fallback_parse_ranges(entry->ranges, ranges, ARRAY_SIZE(ranges), &range_count);
3004
3005 /* TODO: reuse the buffer */
3006 str = wcsdup(entry->families);
3008
3009 if (FAILED(hr = IDWriteFontFallbackBuilder_AddMapping(builder_iface, ranges, range_count,
3010 (const WCHAR **)families, families_count, NULL, entry->locale, NULL, 1.0f)))
3011 {
3012 WARN("Failed to add mapping, hr %#lx.\n", hr);
3013 }
3014
3015 free(str);
3016 }
3017
3019 IDWriteFontFallbackBuilder_Release(builder_iface);
3020
3021 return hr == S_OK;
3022}
3023
3025{
3027}
3028
3030{
3031 struct dwrite_fontfallback *fallback;
3032
3033 *ret = NULL;
3034
3036 {
3037 WARN("Failed to initialize system fallback data.\n");
3038 return E_FAIL;
3039 }
3040
3041 if (!(fallback = calloc(1, sizeof(*fallback))))
3042 return E_OUTOFMEMORY;
3043
3044 fallback->IDWriteFontFallback1_iface.lpVtbl = &fontfallbackvtbl;
3045 fallback->factory = factory;
3046 fallback->data.count = ~0u;
3047 IDWriteFactory_GetSystemFontCollection((IDWriteFactory *)fallback->factory, &fallback->systemcollection, FALSE);
3048
3049 *ret = &fallback->IDWriteFontFallback1_iface;
3050
3051 return S_OK;
3052}
INT WINAPI GetLocaleInfoEx(LPCWSTR locale, LCTYPE info, LPWSTR buffer, INT len)
BOOL WINAPI IsValidLocaleName(LPCWSTR lpLocaleName)
_STLP_MOVE_TO_STD_NAMESPACE void _STLP_CALL advance(_InputIterator &__i, _Distance __n)
unsigned short UINT16
Definition: actypes.h:129
unsigned char UINT8
Definition: actypes.h:128
static struct sockaddr_in sa
Definition: adnsresfilter.c:69
static unsigned int get_bidi_char_length(const struct bidi_char *c)
Definition: analyzer.c:1303
static UINT32 fallback_font_get_supported_length(IDWriteFont3 *font, IDWriteTextAnalysisSource *source, UINT32 position, UINT32 length)
Definition: analyzer.c:2385
static HRESULT WINAPI dwritetextanalyzer1_GetJustificationOpportunities(IDWriteTextAnalyzer2 *iface, IDWriteFontFace *face, FLOAT font_em_size, DWRITE_SCRIPT_ANALYSIS sa, UINT32 length, UINT32 glyph_count, const WCHAR *text, const UINT16 *clustermap, const DWRITE_SHAPING_GLYPH_PROPERTIES *prop, DWRITE_JUSTIFICATION_OPPORTUNITY *jo)
Definition: analyzer.c:2079
static BOOL WINAPI dwrite_system_fallback_initonce(INIT_ONCE *once, void *param, void **context)
Definition: analyzer.c:2985
static UINT8 get_char_bidi_class(UINT32 ch)
Definition: analyzer.c:1308
static ULONG WINAPI dwritenumbersubstitution_AddRef(IDWriteNumberSubstitution *iface)
Definition: analyzer.c:2265
static const IDWriteNumberSubstitutionVtbl numbersubstitutionvtbl
Definition: analyzer.c:2291
static unsigned int text_source_get_char_length(const struct text_source_context *context)
Definition: analyzer.c:379
static ULONG WINAPI fontfallback_Release(IDWriteFontFallback1 *iface)
Definition: analyzer.c:2365
static void get_number_substitutes(IDWriteNumberSubstitution *substitution, BOOL is_rtl, WCHAR *digits)
Definition: analyzer.c:1428
static HRESULT WINAPI dwritetextanalyzer1_GetScriptProperties(IDWriteTextAnalyzer2 *iface, DWRITE_SCRIPT_ANALYSIS sa, DWRITE_SCRIPT_PROPERTIES *props)
Definition: analyzer.c:2006
static void release_fallback_data(struct fallback_data *data)
Definition: analyzer.c:571
static HRESULT text_source_context_init(struct text_source_context *context, IDWriteTextAnalysisSource *source, UINT32 position, UINT32 length)
Definition: analyzer.c:421
static HRESULT fallbackbuilder_create_fallback(struct dwrite_fontfallback_builder *builder, struct dwrite_fontfallback **ret)
Definition: analyzer.c:2847
static const struct dwritescript_properties dwritescripts_properties[Script_LastId+1]
Definition: analyzer.c:48
#define _OT(a, b, c, d)
Definition: analyzer.c:45
#define NATIVE_DIGITS_LEN
Definition: analyzer.c:36
static const IDWriteTextAnalyzer2Vtbl textanalyzervtbl
Definition: analyzer.c:2213
const unsigned short bidi_direction_table[]
Definition: direction.c:6
static void analyzer_dump_user_features(DWRITE_TYPOGRAPHIC_FEATURES const **features, UINT32 const *feature_range_lengths, UINT32 feature_ranges)
Definition: analyzer.c:1500
HRESULT create_matching_font(IDWriteFontCollection *collection, const WCHAR *name, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, REFIID riid, void **obj)
Definition: analyzer.c:2479
static DWRITE_SCRIPT_ANALYSIS get_char_sa(UINT32 c)
Definition: analyzer.c:655
static ULONG WINAPI dwritenumbersubstitution_Release(IDWriteNumberSubstitution *iface)
Definition: analyzer.c:2275
static HRESULT WINAPI dwritetextanalyzer1_JustifyGlyphAdvances(IDWriteTextAnalyzer2 *iface, FLOAT width, UINT32 glyph_count, const DWRITE_JUSTIFICATION_OPPORTUNITY *jo, const FLOAT *advances, const DWRITE_GLYPH_OFFSET *offsets, FLOAT *justifiedadvances, DWRITE_GLYPH_OFFSET *justifiedoffsets)
Definition: analyzer.c:2088
static HRESULT WINAPI dwritetextanalyzer_GetGlyphPlacements(IDWriteTextAnalyzer2 *iface, WCHAR const *text, UINT16 const *clustermap, DWRITE_SHAPING_TEXT_PROPERTIES *text_props, UINT32 text_len, UINT16 const *glyphs, DWRITE_SHAPING_GLYPH_PROPERTIES const *glyph_props, UINT32 glyph_count, IDWriteFontFace *fontface, float emSize, BOOL is_sideways, BOOL is_rtl, DWRITE_SCRIPT_ANALYSIS const *analysis, WCHAR const *locale, DWRITE_TYPOGRAPHIC_FEATURES const **features, UINT32 const *feature_range_lengths, UINT32 feature_ranges, float *advances, DWRITE_GLYPH_OFFSET *offsets)
Definition: analyzer.c:1587
static const IDWriteFontFallback1Vtbl fontfallbackvtbl
Definition: analyzer.c:2566
linebreaking_classes
Definition: analyzer.c:756
@ b_H2
Definition: analyzer.c:771
@ b_IS
Definition: analyzer.c:781
@ b_JL
Definition: analyzer.c:768
@ b_CB
Definition: analyzer.c:763
@ b_OP
Definition: analyzer.c:774
@ b_CJ
Definition: analyzer.c:795
@ b_ID
Definition: analyzer.c:786
@ b_QU
Definition: analyzer.c:777
@ b_HY
Definition: analyzer.c:788
@ b_SY
Definition: analyzer.c:780
@ b_NL
Definition: analyzer.c:766
@ b_WJ
Definition: analyzer.c:767
@ b_EX
Definition: analyzer.c:779
@ b_BB
Definition: analyzer.c:789
@ b_XX
Definition: analyzer.c:773
@ b_HL
Definition: analyzer.c:794
@ b_PO
Definition: analyzer.c:783
@ b_ZW
Definition: analyzer.c:765
@ b_JT
Definition: analyzer.c:770
@ b_LF
Definition: analyzer.c:759
@ b_CL
Definition: analyzer.c:775
@ b_GL
Definition: analyzer.c:762
@ b_PR
Definition: analyzer.c:782
@ b_ZWJ
Definition: analyzer.c:799
@ b_CM
Definition: analyzer.c:760
@ b_RI
Definition: analyzer.c:796
@ b_BA
Definition: analyzer.c:790
@ b_JV
Definition: analyzer.c:769
@ b_BK
Definition: analyzer.c:757
@ b_CP
Definition: analyzer.c:776
@ b_CR
Definition: analyzer.c:758
@ b_EM
Definition: analyzer.c:798
@ b_AI
Definition: analyzer.c:792
@ b_NU
Definition: analyzer.c:784
@ b_SA
Definition: analyzer.c:791
@ b_H3
Definition: analyzer.c:772
@ b_SG
Definition: analyzer.c:761
@ b_AL
Definition: analyzer.c:785
@ b_NS
Definition: analyzer.c:778
@ b_SP
Definition: analyzer.c:764
@ b_B2
Definition: analyzer.c:793
@ b_EB
Definition: analyzer.c:797
@ b_IN
Definition: analyzer.c:787
static HRESULT WINAPI dwritetextanalyzer_AnalyzeBidi(IDWriteTextAnalyzer2 *iface, IDWriteTextAnalysisSource *source, UINT32 position, UINT32 length, IDWriteTextAnalysisSink *sink)
Definition: analyzer.c:1313
static ULONG WINAPI dwritetextanalyzer_AddRef(IDWriteTextAnalyzer2 *iface)
Definition: analyzer.c:1277
static HRESULT WINAPI dwritetextanalyzer1_ApplyCharacterSpacing(IDWriteTextAnalyzer2 *iface, FLOAT leading_spacing, FLOAT trailing_spacing, FLOAT min_advance_width, UINT32 len, UINT32 glyph_count, UINT16 const *clustermap, FLOAT const *advances, DWRITE_GLYPH_OFFSET const *offsets, DWRITE_SHAPING_GLYPH_PROPERTIES const *props, FLOAT *modified_advances, DWRITE_GLYPH_OFFSET *modified_offsets)
Definition: analyzer.c:1899
BreakConditionLocation
Definition: analyzer.c:751
@ BreakConditionAfter
Definition: analyzer.c:753
@ BreakConditionBefore
Definition: analyzer.c:752
static HRESULT analyze_script(struct text_source_context *context, IDWriteTextAnalysisSink *sink)
Definition: analyzer.c:688
static struct fallback_locale * fallback_builder_add_locale(struct dwrite_fontfallback_builder *builder, const WCHAR *locale_name)
Definition: analyzer.c:2663
static HRESULT WINAPI fontfallbackbuilder_AddMappings(IDWriteFontFallbackBuilder *iface, IDWriteFontFallback *fallback)
Definition: analyzer.c:2783
static struct fallback_locale * font_fallback_get_locale(const struct list *locales, const WCHAR *locale_name)
Definition: analyzer.c:514
void release_system_fontfallback(IDWriteFontFallback1 *iface)
Definition: analyzer.c:2575
static BOOL fallback_mapping_contains_character(const struct fallback_mapping *mapping, UINT32 ch)
Definition: analyzer.c:581
void release_system_fallback_data(void)
Definition: analyzer.c:3024
static ULONG WINAPI fontfallback_AddRef(IDWriteFontFallback1 *iface)
Definition: analyzer.c:2356
static HRESULT WINAPI fontfallback_MapCharacters(IDWriteFontFallback1 *iface, IDWriteTextAnalysisSource *source, UINT32 position, UINT32 length, IDWriteFontCollection *basecollection, const WCHAR *basefamily, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, UINT32 *mapped_length, IDWriteFont **ret_font, float *scale)
Definition: analyzer.c:2513
static HRESULT WINAPI fontfallback_QueryInterface(IDWriteFontFallback1 *iface, REFIID riid, void **obj)
Definition: analyzer.c:2337
static HRESULT WINAPI dwritetextanalyzer1_GetTextComplexity(IDWriteTextAnalyzer2 *iface, const WCHAR *text, UINT32 len, IDWriteFontFace *face, BOOL *is_simple, UINT32 *len_read, UINT16 *indices)
Definition: analyzer.c:2030
static void set_break_condition(UINT32 pos, enum BreakConditionLocation location, DWRITE_BREAK_CONDITION condition, struct linebreaking_state *state)
Definition: analyzer.c:815
static ULONG WINAPI fontfallbackbuilder_AddRef(IDWriteFontFallbackBuilder *iface)
Definition: analyzer.c:2636
static HRESULT fallbackbuilder_init_fallback_data(const struct dwrite_fontfallback_builder *builder, struct fallback_data *data)
Definition: analyzer.c:2790
static const struct fallback_description system_fallback_config[]
static void text_source_read_more(struct text_source_context *context)
Definition: analyzer.c:384
static ULONG WINAPI customfontfallback_Release(IDWriteFontFallback1 *iface)
Definition: analyzer.c:2592
static HRESULT WINAPI dwritetextanalyzer_QueryInterface(IDWriteTextAnalyzer2 *iface, REFIID riid, void **obj)
Definition: analyzer.c:1258
static IDWriteTextAnalyzer2 textanalyzer
Definition: analyzer.c:2239
static HRESULT fallback_locale_add_mapping(struct fallback_locale *locale, size_t index)
Definition: analyzer.c:490
static BOOL fallback_is_uvs(const struct text_source_context *context)
Definition: analyzer.c:2374
HRESULT create_numbersubstitution(DWRITE_NUMBER_SUBSTITUTION_METHOD method, const WCHAR *locale, BOOL ignore_user_override, IDWriteNumberSubstitution **ret)
Definition: analyzer.c:2305
static BOOL text_source_get_next_u32_char(struct text_source_context *context)
Definition: analyzer.c:432
HRESULT create_system_fontfallback(IDWriteFactory7 *factory, IDWriteFontFallback1 **ret)
Definition: analyzer.c:3029
static HRESULT WINAPI fontfallbackbuilder_AddMapping(IDWriteFontFallbackBuilder *iface, const DWRITE_UNICODE_RANGE *ranges, UINT32 ranges_count, WCHAR const **families, UINT32 families_count, IDWriteFontCollection *collection, WCHAR const *locale_name, WCHAR const *base_family, float scale)
Definition: analyzer.c:2676
static void system_fallback_parse_families(WCHAR *str, WCHAR **families, unsigned int max_count, unsigned int *ret)
Definition: analyzer.c:2964
static UINT16 get_char_script(UINT32 c)
Definition: analyzer.c:649
static UINT32 get_opentype_language(const WCHAR *locale)
Definition: analyzer.c:1415
const unsigned short wine_scripts_table[]
Definition: scripts.c:7
static HRESULT create_fontfallback_builder_internal(IDWriteFactory7 *factory, struct dwrite_fontfallback_builder **ret)
Definition: analyzer.c:2909
static HRESULT WINAPI dwritetextanalyzer_AnalyzeScript(IDWriteTextAnalyzer2 *iface, IDWriteTextAnalysisSource *source, UINT32 position, UINT32 length, IDWriteTextAnalysisSink *sink)
Definition: analyzer.c:1287
static const struct fallback_mapping * find_fallback_mapping(const struct fallback_data *fallback, const struct fallback_locale *locale, UINT32 ch)
Definition: analyzer.c:594
static struct dwrite_numbersubstitution * impl_from_IDWriteNumberSubstitution(IDWriteNumberSubstitution *iface)
Definition: analyzer.c:632
static BOOL is_char_from_simple_script(WCHAR c)
Definition: analyzer.c:2018
static BOOL has_strong_condition(DWRITE_BREAK_CONDITION old_condition, DWRITE_BREAK_CONDITION new_condition)
Definition: analyzer.c:802
static HRESULT apply_cluster_spacing(float leading_spacing, float trailing_spacing, float min_advance_width, unsigned int start, unsigned int end, float const *advances, DWRITE_GLYPH_OFFSET const *offsets, DWRITE_SHAPING_GLYPH_PROPERTIES const *glyph_props, float *modified_advances, DWRITE_GLYPH_OFFSET *modified_offsets)
Definition: analyzer.c:1737
static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface, WCHAR const *text, UINT32 length, IDWriteFontFace *fontface, BOOL is_sideways, BOOL is_rtl, DWRITE_SCRIPT_ANALYSIS const *analysis, WCHAR const *locale, IDWriteNumberSubstitution *substitution, DWRITE_TYPOGRAPHIC_FEATURES const **features, UINT32 const *feature_range_lengths, UINT32 feature_ranges, UINT32 max_glyph_count, UINT16 *clustermap, DWRITE_SHAPING_TEXT_PROPERTIES *text_props, UINT16 *glyphs, DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props, UINT32 *actual_glyph_count)
Definition: analyzer.c:1516
const unsigned short wine_linebreak_table[]
Definition: linebreak.c:7
static HRESULT WINAPI dwritetextanalyzer_AnalyzeLineBreakpoints(IDWriteTextAnalyzer2 *iface, IDWriteTextAnalysisSource *source, UINT32 position, UINT32 length, IDWriteTextAnalysisSink *sink)
Definition: analyzer.c:1393
static HRESULT WINAPI fontfallback1_MapCharacters(IDWriteFontFallback1 *iface, IDWriteTextAnalysisSource *source, UINT32 position, UINT32 length, IDWriteFontCollection *basecollection, const WCHAR *basefamily, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 values_count, UINT32 *mapped_length, FLOAT *scale, IDWriteFontFace5 **ret_fontface)
Definition: analyzer.c:2555
static const IDWriteFontFallback1Vtbl customfontfallbackvtbl
Definition: analyzer.c:2611
static INIT_ONCE init_system_fallback_once
Definition: analyzer.c:2981
static const IDWriteFontFallbackBuilderVtbl fontfallbackbuildervtbl
Definition: analyzer.c:2899
static HRESULT WINAPI fontfallbackbuilder_QueryInterface(IDWriteFontFallbackBuilder *iface, REFIID riid, void **obj)
Definition: analyzer.c:2620
static struct fallback_data system_fallback
Definition: analyzer.c:554
static struct dwrite_fontfallback_builder * impl_from_IDWriteFontFallbackBuilder(IDWriteFontFallbackBuilder *iface)
Definition: analyzer.c:644
IDWriteTextAnalyzer2 * get_text_analyzer(void)
Definition: analyzer.c:2241
static HRESULT WINAPI dwritetextanalyzer2_CheckTypographicFeature(IDWriteTextAnalyzer2 *iface, IDWriteFontFace *fontface, DWRITE_SCRIPT_ANALYSIS sa, const WCHAR *locale, DWRITE_FONT_FEATURE_TAG feature, UINT32 glyph_count, const UINT16 *glyphs, UINT8 *feature_applies)
Definition: analyzer.c:2182
HRESULT create_fontfallback_builder(IDWriteFactory7 *factory, IDWriteFontFallbackBuilder **ret)
Definition: analyzer.c:2929
static HRESULT WINAPI dwritetextanalyzer1_GetBaseline(IDWriteTextAnalyzer2 *iface, IDWriteFontFace *fontface, DWRITE_BASELINE baseline, BOOL vertical, BOOL is_simulation_allowed, DWRITE_SCRIPT_ANALYSIS sa, const WCHAR *localeName, INT32 *baseline_coord, BOOL *exists)
Definition: analyzer.c:1932
static void text_source_get_u32_char(struct text_source_context *context)
Definition: analyzer.c:397
static ULONG WINAPI customfontfallback_AddRef(IDWriteFontFallback1 *iface)
Definition: analyzer.c:2582
static HRESULT WINAPI dwritetextanalyzer_AnalyzeNumberSubstitution(IDWriteTextAnalyzer2 *iface, IDWriteTextAnalysisSource *source, UINT32 position, UINT32 length, IDWriteTextAnalysisSink *sink)
Definition: analyzer.c:1383
static HRESULT analyze_linebreaks(IDWriteTextAnalysisSource *source, UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT *breakpoints)
Definition: analyzer.c:857
static HRESULT WINAPI dwritetextanalyzer1_GetJustifiedGlyphs(IDWriteTextAnalyzer2 *iface, IDWriteFontFace *face, FLOAT font_em_size, DWRITE_SCRIPT_ANALYSIS sa, UINT32 length, UINT32 glyph_count, UINT32 max_glyphcount, const UINT16 *clustermap, const UINT16 *indices, const FLOAT *advances, const FLOAT *justifiedadvances, const DWRITE_GLYPH_OFFSET *justifiedoffsets, const DWRITE_SHAPING_GLYPH_PROPERTIES *prop, UINT32 *actual_count, UINT16 *modified_clustermap, UINT16 *modified_indices, FLOAT *modified_advances, DWRITE_GLYPH_OFFSET *modified_offsets)
Definition: analyzer.c:2097
BOOL lb_is_newline_char(WCHAR ch)
Definition: analyzer.c:851
static HRESULT WINAPI dwritetextanalyzer1_AnalyzeVerticalGlyphOrientation(IDWriteTextAnalyzer2 *iface, IDWriteTextAnalysisSource1 *source, UINT32 text_pos, UINT32 len, IDWriteTextAnalysisSink1 *sink)
Definition: analyzer.c:1991
static ULONG WINAPI dwritetextanalyzer_Release(IDWriteTextAnalyzer2 *iface)
Definition: analyzer.c:1282
static HRESULT WINAPI dwritetextanalyzer_GetGdiCompatibleGlyphPlacements(IDWriteTextAnalyzer2 *iface, WCHAR const *text, UINT16 const *clustermap, DWRITE_SHAPING_TEXT_PROPERTIES *text_props, UINT32 text_len, UINT16 const *glyphs, DWRITE_SHAPING_GLYPH_PROPERTIES const *glyph_props, UINT32 glyph_count, IDWriteFontFace *fontface, float emSize, float ppdip, DWRITE_MATRIX const *transform, BOOL use_gdi_natural, BOOL is_sideways, BOOL is_rtl, DWRITE_SCRIPT_ANALYSIS const *analysis, WCHAR const *locale, DWRITE_TYPOGRAPHIC_FEATURES const **features, UINT32 const *feature_range_lengths, UINT32 feature_ranges, float *advances, DWRITE_GLYPH_OFFSET *offsets)
Definition: analyzer.c:1660
static HRESULT WINAPI dwritetextanalyzer1_GetGlyphOrientationTransform(IDWriteTextAnalyzer2 *iface, DWRITE_GLYPH_ORIENTATION_ANGLE angle, BOOL is_sideways, DWRITE_MATRIX *transform)
Definition: analyzer.c:1998
static HRESULT WINAPI dwritenumbersubstitution_QueryInterface(IDWriteNumberSubstitution *iface, REFIID riid, void **obj)
Definition: analyzer.c:2246
static void system_fallback_parse_ranges(const char *str, DWRITE_UNICODE_RANGE *ranges, unsigned int max_count, unsigned int *ret)
Definition: analyzer.c:2942
static HRESULT WINAPI dwritetextanalyzer2_GetGlyphOrientationTransform(IDWriteTextAnalyzer2 *iface, DWRITE_GLYPH_ORIENTATION_ANGLE angle, BOOL is_sideways, FLOAT originX, FLOAT originY, DWRITE_MATRIX *m)
Definition: analyzer.c:2110
static HRESULT WINAPI fontfallbackbuilder_CreateFontFallback(IDWriteFontFallbackBuilder *iface, IDWriteFontFallback **ret)
Definition: analyzer.c:2880
static ULONG WINAPI fontfallbackbuilder_Release(IDWriteFontFallbackBuilder *iface)
Definition: analyzer.c:2646
static void release_fallback_mapping(struct fallback_mapping *mapping)
Definition: analyzer.c:559
const char * debugstr_sa_script(UINT16 script)
Definition: analyzer.c:209
static void fallback_locale_list_destroy(struct list *locales)
Definition: analyzer.c:478
static UINT32 get_cluster_length(UINT16 const *clustermap, UINT32 start, UINT32 text_len)
Definition: analyzer.c:1853
static struct dwrite_numbersubstitution * unsafe_impl_from_IDWriteNumberSubstitution(IDWriteNumberSubstitution *iface)
Definition: analyzer.c:2298
static struct dwrite_fontfallback * impl_from_IDWriteFontFallback1(IDWriteFontFallback1 *iface)
Definition: analyzer.c:639
static HRESULT fallback_map_characters(const struct dwrite_fontfallback *fallback, IDWriteTextAnalysisSource *source, UINT32 position, UINT32 text_length, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, IDWriteFont **ret_font, UINT32 *ret_length, float *scale)
Definition: analyzer.c:2405
static HRESULT WINAPI dwritetextanalyzer2_GetTypographicFeatures(IDWriteTextAnalyzer2 *iface, IDWriteFontFace *fontface, DWRITE_SCRIPT_ANALYSIS sa, const WCHAR *locale, UINT32 max_tagcount, UINT32 *actual_tagcount, DWRITE_FONT_FEATURE_TAG *tags)
Definition: analyzer.c:2159
static int state
Definition: maze.c:121
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedDecrement
Definition: armddk.h:52
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define index(s, c)
Definition: various.h:29
#define ARRAY_SIZE(A)
Definition: main.h:20
static void list_remove(struct list_entry *entry)
Definition: list.h:90
static void list_add_tail(struct list_entry *head, struct list_entry *entry)
Definition: list.h:83
static void list_init(struct list_entry *head)
Definition: list.h:51
#define FIXME(fmt,...)
Definition: precomp.h:53
#define WARN(fmt,...)
Definition: precomp.h:61
const GUID IID_IUnknown
Definition: list.h:39
Definition: _locale.h:75
string name() const
Definition: locale.cpp:388
range
Definition: d3dx9_private.h:58
DWRITE_MEASURING_MODE
Definition: dcommon.idl:36
@ DWRITE_MEASURING_MODE_GDI_CLASSIC
Definition: dcommon.idl:38
@ DWRITE_MEASURING_MODE_NATURAL
Definition: dcommon.idl:37
@ DWRITE_MEASURING_MODE_GDI_NATURAL
Definition: dcommon.idl:39
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define E_INVALIDARG
Definition: ddrawi.h:101
#define E_NOTIMPL
Definition: ddrawi.h:99
#define E_FAIL
Definition: ddrawi.h:102
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
HRESULT hr
Definition: delayimp.cpp:582
HRESULT bidi_computelevels(struct bidi_char *chars, unsigned int count, UINT8 baselevel)
Definition: bidi.c:1070
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
static WCHAR available[MAX_STRING_RESOURCE_LEN]
Definition: object.c:2402
#define TRACE_ON(x)
Definition: compat.h:75
#define wcsicmp
Definition: compat.h:15
#define lstrcpynW
Definition: compat.h:738
BOOL WINAPI InitOnceExecuteOnce(_Inout_ PINIT_ONCE InitOnce, _In_ __callback PINIT_ONCE_FN InitFn, _Inout_opt_ PVOID Parameter, _Outptr_opt_result_maybenull_ LPVOID *Context)
Definition: InitOnce.c:12
const WCHAR * text
Definition: package.c:1826
unsigned char ch[4][2]
Definition: console.c:118
_ACRTIMP wchar_t *__cdecl wcstok_s(wchar_t *, const wchar_t *, wchar_t **)
Definition: wcs.c:2036
_ACRTIMP int __cdecl wcscmp(const wchar_t *, const wchar_t *)
Definition: wcs.c:1977
_ACRTIMP __msvcrt_ulong __cdecl strtoul(const char *, char **, int)
Definition: string.c:1864
static wchar_t * wcsdup(const wchar_t *str)
Definition: string.h:94
method
Definition: dragdrop.c:54
return ret
Definition: mutex.c:147
#define L(x)
Definition: resources.c:13
@ DWRITE_SCRIPT_SHAPES_NO_VISUAL
Definition: dwrite.idl:330
@ DWRITE_SCRIPT_SHAPES_DEFAULT
Definition: dwrite.idl:329
DWRITE_BREAK_CONDITION
Definition: dwrite.idl:222
@ DWRITE_BREAK_CONDITION_MUST_BREAK
Definition: dwrite.idl:226
@ DWRITE_BREAK_CONDITION_CAN_BREAK
Definition: dwrite.idl:224
@ DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
Definition: dwrite.idl:225
@ DWRITE_BREAK_CONDITION_NEUTRAL
Definition: dwrite.idl:223
DWRITE_NUMBER_SUBSTITUTION_METHOD
Definition: dwrite.idl:335
@ DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE
Definition: dwrite.idl:338
@ DWRITE_NUMBER_SUBSTITUTION_METHOD_CONTEXTUAL
Definition: dwrite.idl:337
@ DWRITE_NUMBER_SUBSTITUTION_METHOD_TRADITIONAL
Definition: dwrite.idl:340
@ DWRITE_NUMBER_SUBSTITUTION_METHOD_FROM_CULTURE
Definition: dwrite.idl:336
@ DWRITE_NUMBER_SUBSTITUTION_METHOD_NATIONAL
Definition: dwrite.idl:339
DWRITE_FONT_WEIGHT
Definition: dwrite.idl:73
DWRITE_FONT_STYLE
Definition: dwrite.idl:109
DWRITE_FONT_STRETCH
Definition: dwrite.idl:94
DWRITE_FONT_FEATURE_TAG
Definition: dwrite.idl:243
DWRITE_BASELINE
Definition: dwrite_1.idl:413
@ DWRITE_BASELINE_MINIMUM
Definition: dwrite_1.idl:421
@ DWRITE_BASELINE_DEFAULT
Definition: dwrite_1.idl:414
@ DWRITE_BASELINE_CENTRAL
Definition: dwrite_1.idl:416
@ DWRITE_BASELINE_IDEOGRAPHIC_TOP
Definition: dwrite_1.idl:420
@ DWRITE_BASELINE_HANGING
Definition: dwrite_1.idl:418
@ DWRITE_BASELINE_MAXIMUM
Definition: dwrite_1.idl:422
@ DWRITE_BASELINE_IDEOGRAPHIC_BOTTOM
Definition: dwrite_1.idl:419
@ DWRITE_BASELINE_ROMAN
Definition: dwrite_1.idl:415
@ DWRITE_BASELINE_MATH
Definition: dwrite_1.idl:417
DWRITE_GLYPH_ORIENTATION_ANGLE
Definition: dwrite_1.idl:432
@ DWRITE_GLYPH_ORIENTATION_ANGLE_180_DEGREES
Definition: dwrite_1.idl:435
@ DWRITE_GLYPH_ORIENTATION_ANGLE_90_DEGREES
Definition: dwrite_1.idl:434
@ DWRITE_GLYPH_ORIENTATION_ANGLE_0_DEGREES
Definition: dwrite_1.idl:433
@ DWRITE_GLYPH_ORIENTATION_ANGLE_270_DEGREES
Definition: dwrite_1.idl:436
FLOAT baseline
Definition: dwrite_3.idl:860
float fontface_get_scaled_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode, float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
Definition: font.c:6384
HRESULT shape_get_glyphs(struct scriptshaping_context *context, const unsigned int *scripts)
Definition: shape.c:308
struct scriptshaping_cache * fontface_get_shaping_cache(struct dwrite_fontface *fontface)
Definition: font.c:559
struct dwrite_fontface * unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
Definition: font.c:2536
static unsigned short get_table_entry_32(const unsigned short *table, UINT ch)
static BOOL dwrite_array_reserve(void **elements, size_t *capacity, size_t count, size_t size)
HRESULT shape_get_typographic_features(struct scriptshaping_context *context, const unsigned int *scripts, unsigned int max_tagcount, unsigned int *actual_tagcount, DWRITE_FONT_FEATURE_TAG *tags)
Definition: shape.c:375
HRESULT shape_check_typographic_feature(struct scriptshaping_context *context, const unsigned int *scripts, unsigned int tag, unsigned int glyph_count, const UINT16 *glyphs, UINT8 *feature_applies)
Definition: shape.c:415
HRESULT shape_get_positions(struct scriptshaping_context *context, const unsigned int *scripts)
Definition: shape.c:233
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
Character const *const size_t const max_count
Definition: fullpath.cpp:66
static const FxOffsetAndName offsets[]
FxCollectionEntry * cur
GLuint start
Definition: gl.h:1545
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint GLuint end
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLint GLint GLsizei width
Definition: gl.h:1546
GLuint GLuint GLsizei GLenum const GLvoid * indices
Definition: gl.h:1545
GLuint GLenum GLenum transform
Definition: glext.h:9407
GLenum GLenum GLenum GLenum GLenum scale
Definition: glext.h:9032
GLenum src
Definition: glext.h:6340
GLenum condition
Definition: glext.h:9255
const GLubyte * c
Definition: glext.h:8905
GLuint index
Definition: glext.h:6031
GLenum GLuint GLint GLenum face
Definition: glext.h:7025
GLsizei GLenum const GLvoid GLuint GLsizei GLfloat * metrics
Definition: glext.h:11745
GLenum GLenum dst
Definition: glext.h:6340
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
const GLint * first
Definition: glext.h:5794
GLsizei GLenum GLboolean sink
Definition: glext.h:5672
GLboolean GLboolean g
Definition: glext.h:6204
GLfloat angle
Definition: glext.h:10853
GLenum GLenum GLenum GLenum mapping
Definition: glext.h:9031
GLfloat param
Definition: glext.h:5796
GLenum GLsizei len
Definition: glext.h:6722
const GLfloat * m
Definition: glext.h:10848
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble * u
Definition: glfuncs.h:240
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
REFIID riid
Definition: atlbase.h:39
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
voidpf uLong int origin
Definition: ioapi.h:144
uint32_t entry
Definition: isohybrid.c:63
static const int digits[]
Definition: decode.c:71
#define debugstr_guid
Definition: kernel32.h:35
#define debugstr_wn
Definition: kernel32.h:33
#define debugstr_w
Definition: kernel32.h:32
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
const char * tags[99]
Definition: apphelp.c:216
static PVOID ptr
Definition: dispmode.c:27
static const LARGE_INTEGER *static const HANDLE const LARGE_INTEGER *static PSLIST_ENTRY PSLIST_ENTRY last
Definition: sync.c:64
static BOOL is_rtl(void)
Definition: editor.c:53
INTERNETFEATURELIST feature
Definition: misc.c:1807
#define min(a, b)
Definition: monoChain.cc:55
script
Definition: msipriv.h:396
Definition: mk_font.cpp:20
#define LOCALE_NAME_MAX_LENGTH
short WCHAR
Definition: pedump.c:58
long LONG
Definition: pedump.c:60
#define IsEqualIID(riid1, riid2)
Definition: guiddef.h:95
#define REFIID
Definition: guiddef.h:118
#define calloc
Definition: rosglue.h:14
const WCHAR * str
@ Script_Inherited
Definition: scripts.h:8
@ Script_LastId
Definition: scripts.h:163
@ Script_Common
Definition: scripts.h:7
@ Script_Unknown
Definition: scripts.h:6
#define iswspace(_c)
Definition: ctype.h:669
wcscpy
static __inline const char * debugstr_fourcc(unsigned int cc)
Definition: debug.h:397
#define LIST_FOR_EACH_ENTRY(elem, list, type, field)
Definition: list.h:236
#define LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, list, type, field)
Definition: list.h:242
#define memset(x, y, z)
Definition: compat.h:39
weight
Definition: sortkey.c:157
#define TRACE(s)
Definition: solgame.cpp:4
DWRITE_SCRIPT_SHAPES shapes
Definition: dwrite.idl:530
UINT8 resolved
UINT8 explicit
UINT8 length
Definition: analyzer.c:741
unsigned int index
Definition: analyzer.c:740
Definition: http.c:7252
DWRITE_FONT_METRICS1 metrics
DWRITE_GLYPH_METRICS * glyphs[GLYPH_MAX/GLYPH_BLOCK_SIZE]
IDWriteFactory7 * factory
Definition: analyzer.c:549
struct fallback_data data
Definition: analyzer.c:550
IDWriteFontFallbackBuilder IDWriteFontFallbackBuilder_iface
Definition: analyzer.c:547
IDWriteFontFallback1 IDWriteFontFallback1_iface
Definition: analyzer.c:537
IDWriteFactory7 * factory
Definition: analyzer.c:539
size_t mappings_size
Definition: analyzer.c:542
struct fallback_data data
Definition: analyzer.c:541
IDWriteFontCollection * systemcollection
Definition: analyzer.c:540
DWRITE_NUMBER_SUBSTITUTION_METHOD method
Definition: analyzer.c:627
IDWriteNumberSubstitution IDWriteNumberSubstitution_iface
Definition: analyzer.c:624
UINT32 scripttags[3]
Definition: analyzer.c:41
DWRITE_SCRIPT_PROPERTIES props
Definition: analyzer.c:40
Definition: main.c:439
size_t count
Definition: analyzer.c:531
struct list locales
Definition: analyzer.c:532
struct fallback_mapping * mappings
Definition: analyzer.c:530
const char * ranges
Definition: analyzer.c:216
const WCHAR * locale
Definition: analyzer.c:218
const WCHAR * families
Definition: analyzer.c:217
struct list entry
Definition: analyzer.c:468
size_t count
Definition: analyzer.c:473
size_t * data
Definition: analyzer.c:472
WCHAR name[LOCALE_NAME_MAX_LENGTH]
Definition: analyzer.c:469
struct fallback_locale::@303 ranges
DWRITE_UNICODE_RANGE * ranges
Definition: analyzer.c:458
UINT32 ranges_count
Definition: analyzer.c:459
WCHAR ** families
Definition: analyzer.c:460
UINT32 families_count
Definition: analyzer.c:461
IDWriteFontCollection * collection
Definition: analyzer.c:462
struct break_index * breaks
Definition: analyzer.c:747
DWRITE_LINE_BREAKPOINT * breakpoints
Definition: analyzer.c:746
Definition: name.c:39
DWRITE_MEASURING_MODE measuring_mode
Definition: style.c:91
Definition: ecma_167.h:138
IDWriteTextAnalysisSource * source
Definition: analyzer.c:364
const WCHAR * text
Definition: analyzer.c:371
#define max(a, b)
Definition: svc.c:63
#define LIST_INIT(head)
Definition: queue.h:197
int32_t INT32
Definition: typedefs.h:58
float FLOAT
Definition: typedefs.h:69
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t UINT32
Definition: typedefs.h:59
uint32_t ULONG
Definition: typedefs.h:59
Definition: pdh_main.c:64
static const WCHAR props[]
Definition: wbemdisp.c:288
RTL_RUN_ONCE INIT_ONCE
Definition: winbase.h:3654
#define INIT_ONCE_STATIC_INIT
Definition: winbase.h:591
#define WINAPI
Definition: msvc.h:6
#define E_NOINTERFACE
Definition: winerror.h:3479
#define LOCALE_SOPENTYPELANGUAGETAG
Definition: winnls.h:175
#define IS_HIGH_SURROGATE(ch)
Definition: winnls.h:763
#define LOCALE_SISO639LANGNAME
Definition: winnls.h:136
#define LOCALE_NOUSEROVERRIDE
Definition: winnls.h:19
#define IS_LOW_SURROGATE(ch)
Definition: winnls.h:764
#define LOCALE_SNATIVEDIGITS
Definition: winnls.h:58