win32u: Move NtUserDrawCaptionTemp implementation from user32.
[wine.git] / dlls / dwrite / shapers / arabic.c
blob720f18915a4904e0beba25f16f9e1e1ea2e75d57
1 /*
2 * Copyright HarfBuzz Project authors
3 * Copyright 2020 Nikolay Sivov for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "dwrite_private.h"
21 #include "scripts.h"
23 static const unsigned int arabic_features[] =
25 DWRITE_MAKE_OPENTYPE_TAG('i','s','o','l'),
26 DWRITE_MAKE_OPENTYPE_TAG('f','i','n','a'),
27 DWRITE_MAKE_OPENTYPE_TAG('f','i','n','2'),
28 DWRITE_MAKE_OPENTYPE_TAG('f','i','n','3'),
29 DWRITE_MAKE_OPENTYPE_TAG('m','e','d','i'),
30 DWRITE_MAKE_OPENTYPE_TAG('m','e','d','2'),
31 DWRITE_MAKE_OPENTYPE_TAG('i','n','i','t'),
34 enum arabic_shaping_action
36 ISOL,
37 FINA,
38 FIN2,
39 FIN3,
40 MEDI,
41 MED2,
42 INIT,
43 NONE,
44 NUM_FEATURES = NONE,
47 static BOOL feature_is_syriac(unsigned int tag)
49 return tag == arabic_features[FIN2] || tag == arabic_features[FIN3] ||
50 tag == arabic_features[MED2];
53 static void arabic_collect_features(struct scriptshaping_context *context,
54 struct shaping_features *features)
56 unsigned int i;
58 shape_enable_feature(features, DWRITE_MAKE_OPENTYPE_TAG('c','c','m','p'), 0);
59 shape_enable_feature(features, DWRITE_MAKE_OPENTYPE_TAG('l','o','c','l'), 0);
60 shape_start_next_stage(features, NULL);
62 for (i = 0; i < ARRAY_SIZE(arabic_features); ++i)
64 unsigned int flags = context->script == Script_Arabic && !feature_is_syriac(arabic_features[i]) ?
65 FEATURE_HAS_FALLBACK : 0;
66 shape_add_feature_full(features, arabic_features[i], flags, 1);
67 shape_start_next_stage(features, NULL);
70 shape_enable_feature(features, DWRITE_MAKE_OPENTYPE_TAG('r','l','i','g'), FEATURE_MANUAL_ZWJ | FEATURE_HAS_FALLBACK);
72 shape_enable_feature(features, DWRITE_MAKE_OPENTYPE_TAG('r','c','l','t'), FEATURE_MANUAL_ZWJ);
73 shape_enable_feature(features, DWRITE_MAKE_OPENTYPE_TAG('c','a','l','t'), FEATURE_MANUAL_ZWJ);
74 shape_start_next_stage(features, NULL);
76 shape_enable_feature(features, DWRITE_MAKE_OPENTYPE_TAG('m','s','e','t'), 0);
79 enum arabic_joining_type
81 JOINING_TYPE_U = 0,
82 JOINING_TYPE_L = 1,
83 JOINING_TYPE_R = 2,
84 JOINING_TYPE_D = 3,
85 JOINING_TYPE_C = JOINING_TYPE_D,
86 JOINING_GROUP_ALAPH = 4,
87 JOINING_GROUP_DALATH_RISH = 5,
88 JOINING_TYPES = 6,
89 JOINING_TYPE_T = 6,
92 static const struct arabic_state_table_entry
94 unsigned char prev_action;
95 unsigned char curr_action;
96 unsigned char next_state;
98 arabic_state_table[][JOINING_TYPES] =
100 /* U, L, R, D, ALAPH, DALATH_RISH */
101 /* State 0: prev was U, not willing to join. */
102 { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,6}, },
104 /* State 1: prev was R or ISOL/ALAPH, not willing to join. */
105 { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN2,5}, {NONE,ISOL,6}, },
107 /* State 2: prev was D/L in ISOL form, willing to join. */
108 { {NONE,NONE,0}, {NONE,ISOL,2}, {INIT,FINA,1}, {INIT,FINA,3}, {INIT,FINA,4}, {INIT,FINA,6}, },
110 /* State 3: prev was D in FINA form, willing to join. */
111 { {NONE,NONE,0}, {NONE,ISOL,2}, {MEDI,FINA,1}, {MEDI,FINA,3}, {MEDI,FINA,4}, {MEDI,FINA,6}, },
113 /* State 4: prev was FINA ALAPH, not willing to join. */
114 { {NONE,NONE,0}, {NONE,ISOL,2}, {MED2,ISOL,1}, {MED2,ISOL,2}, {MED2,FIN2,5}, {MED2,ISOL,6}, },
116 /* State 5: prev was FIN2/FIN3 ALAPH, not willing to join. */
117 { {NONE,NONE,0}, {NONE,ISOL,2}, {ISOL,ISOL,1}, {ISOL,ISOL,2}, {ISOL,FIN2,5}, {ISOL,ISOL,6}, },
119 /* State 6: prev was DALATH/RISH, not willing to join. */
120 { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN3,5}, {NONE,ISOL,6}, }
123 extern const unsigned short arabic_shaping_table[] DECLSPEC_HIDDEN;
125 static unsigned short arabic_get_joining_type(WCHAR ch)
127 const unsigned short *table = arabic_shaping_table;
128 return table[table[table[ch >> 8] + ((ch >> 4) & 0x0f)] + (ch & 0xf)];
131 static void arabic_set_shaping_action(struct scriptshaping_context *context,
132 unsigned int idx, enum arabic_shaping_action action)
134 context->glyph_infos[idx].props &= ~(0xf << 16);
135 context->glyph_infos[idx].props |= (action & 0xf) << 16;
138 static enum arabic_shaping_action arabic_get_shaping_action(const struct scriptshaping_context *context,
139 unsigned int idx)
141 return (context->glyph_infos[idx].props >> 16) & 0xf;
144 static void arabic_setup_masks(struct scriptshaping_context *context,
145 const struct shaping_features *features)
147 unsigned int i, prev = ~0u, state = 0;
148 unsigned int masks[NUM_FEATURES];
150 for (i = 0; i < context->glyph_count; ++i)
152 unsigned short this_type = arabic_get_joining_type(context->glyph_infos[i].codepoint);
153 const struct arabic_state_table_entry *entry;
155 if (this_type == JOINING_TYPE_T)
157 arabic_set_shaping_action(context, i, NONE);
158 continue;
161 entry = &arabic_state_table[state][this_type];
163 if (entry->prev_action != NONE && prev != ~0u)
164 arabic_set_shaping_action(context, prev, entry->prev_action);
166 arabic_set_shaping_action(context, i, entry->curr_action);
168 prev = i;
169 state = entry->next_state;
172 for (i = 0; i < ARRAY_SIZE(masks); ++i)
173 masks[i] = shape_get_feature_1_mask(features, arabic_features[i]);
175 /* Unaffected glyphs get action NONE with zero mask. */
176 for (i = 0; i < context->glyph_count; ++i)
178 enum arabic_shaping_action action = arabic_get_shaping_action(context, i);
179 if (action != NONE)
180 opentype_layout_unsafe_to_break(context, i, i + 1);
181 context->glyph_infos[i].mask |= masks[action];
185 const struct shaper arabic_shaper =
187 arabic_collect_features,
188 arabic_setup_masks,