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"
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
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
)
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
85 JOINING_TYPE_C
= JOINING_TYPE_D
,
86 JOINING_GROUP_ALAPH
= 4,
87 JOINING_GROUP_DALATH_RISH
= 5,
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
,
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
);
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
);
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
);
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
,