Apply user features to ranges!
[framework/uifw/harfbuzz.git] / src / hb-ot-shape.cc
1 /*
2  * Copyright (C) 2009  Red Hat, Inc.
3  *
4  *  This is part of HarfBuzz, a text shaping library.
5  *
6  * Permission is hereby granted, without written agreement and without
7  * license or royalty fees, to use, copy, modify, and distribute this
8  * software and its documentation for any purpose, provided that the
9  * above copyright notice and the following two paragraphs appear in
10  * all copies of this software.
11  *
12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16  * DAMAGE.
17  *
18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23  *
24  * Red Hat Author(s): Behdad Esfahbod
25  */
26
27 #include "hb-ot-shape-private.hh"
28
29 #include "hb-buffer-private.hh"
30
31 #include "hb-ot-layout.h"
32
33 hb_tag_t default_features[] = {
34   /* GSUB */
35   HB_TAG('c','c','m','p'),
36   HB_TAG('l','o','c','l'),
37   HB_TAG('l','i','g','a'),
38   HB_TAG('c','l','i','g'),
39   /* GPOS */
40   HB_TAG('k','e','r','n'),
41   HB_TAG('m','a','r','k'),
42   HB_TAG('m','k','m','k'),
43 };
44
45 struct lookup_map {
46   unsigned int index;
47   hb_mask_t mask;
48 };
49
50
51 static void
52 add_feature (hb_face_t    *face,
53              hb_tag_t      table_tag,
54              unsigned int  feature_index,
55              hb_mask_t     mask,
56              lookup_map   *lookups,
57              unsigned int *num_lookups,
58              unsigned int  room_lookups)
59 {
60   unsigned int i = room_lookups - *num_lookups;
61   lookups += *num_lookups;
62
63   unsigned int *lookup_indices = (unsigned int *) lookups;
64
65   hb_ot_layout_feature_get_lookup_indexes (face, table_tag, feature_index, 0,
66                                            &i,
67                                            lookup_indices);
68
69   *num_lookups += i;
70
71   while (i--) {
72     lookups[i].mask = mask;
73     lookups[i].index = lookup_indices[i];
74   }
75 }
76
77 static int
78 cmp_lookups (const void *p1, const void *p2)
79 {
80   const lookup_map *a = (const lookup_map *) p1;
81   const lookup_map *b = (const lookup_map *) p2;
82
83   return a->index - b->index;
84 }
85
86 static void
87 setup_lookups (hb_face_t    *face,
88                hb_buffer_t  *buffer,
89                hb_feature_t *features,
90                unsigned int  num_features,
91                hb_tag_t      table_tag,
92                lookup_map   *lookups,
93                unsigned int *num_lookups)
94 {
95   unsigned int i, j, script_index, language_index, feature_index, room_lookups;
96
97   room_lookups = *num_lookups;
98   *num_lookups = 0;
99
100   hb_ot_layout_table_choose_script (face, table_tag,
101                                     hb_ot_tags_from_script (buffer->script),
102                                     &script_index);
103   hb_ot_layout_script_find_language (face, table_tag, script_index,
104                                      hb_ot_tag_from_language (buffer->language),
105                                      &language_index);
106
107   if (hb_ot_layout_language_get_required_feature_index (face, table_tag, script_index, language_index,
108                                                         &feature_index))
109     add_feature (face, table_tag, feature_index, 1, lookups, num_lookups, room_lookups);
110
111   for (i = 0; i < ARRAY_LENGTH (default_features); i++)
112   {
113     if (hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index,
114                                             default_features[i],
115                                             &feature_index))
116       add_feature (face, table_tag, feature_index, 1, lookups, num_lookups, room_lookups);
117   }
118
119   /* Clear buffer masks. */
120   unsigned int count = buffer->len;
121   for (unsigned int i = 0; i < count; i++)
122     buffer->info[i].mask = 1;
123
124   unsigned int last_bit_used = 1;
125   for (i = 0; i < num_features; i++)
126   {
127     unsigned int bits_needed = _hb_bit_storage (features[i].value);
128     if (!bits_needed)
129       continue;
130     unsigned int mask = (1 << (last_bit_used + bits_needed)) - (1 << last_bit_used);
131     unsigned int value = features[i].value << last_bit_used;
132     last_bit_used += bits_needed;
133
134     if (hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index,
135                                             features[i].tag,
136                                             &feature_index))
137       add_feature (face, table_tag, feature_index, mask, lookups, num_lookups, room_lookups);
138
139     /* Turn mask on in the buffer, the über-slow way! */
140     unsigned int count = buffer->len;
141     for (unsigned int i = 0; i < count; i++) {
142         unsigned int cluster = buffer->info[i].cluster;
143         if (features[i].start <= cluster && cluster < features[i].end)
144           buffer->info[i].mask |= value;
145     }
146   }
147
148   qsort (lookups, *num_lookups, sizeof (lookups[0]), cmp_lookups);
149
150   if (*num_lookups)
151   {
152     for (i = 1, j = 0; i < *num_lookups; i++)
153       if (lookups[i].index != lookups[j].index)
154         lookups[++j] = lookups[i];
155       else
156         lookups[j].mask |= lookups[i].mask;
157     j++;
158     *num_lookups = j;
159   }
160 }
161
162
163 hb_bool_t
164 _hb_ot_substitute_complex (hb_font_t    *font HB_UNUSED,
165                            hb_face_t    *face,
166                            hb_buffer_t  *buffer,
167                            hb_feature_t *features,
168                            unsigned int  num_features)
169 {
170   lookup_map lookups[1000];
171   unsigned int num_lookups = ARRAY_LENGTH (lookups);
172   unsigned int i;
173
174   if (!hb_ot_layout_has_substitution (face))
175     return FALSE;
176
177   setup_lookups (face, buffer, features, num_features,
178                  HB_OT_TAG_GSUB,
179                  lookups, &num_lookups);
180
181   for (i = 0; i < num_lookups; i++)
182     hb_ot_layout_substitute_lookup (face, buffer, lookups[i].index, lookups[i].mask);
183
184   return TRUE;
185 }
186
187 hb_bool_t
188 _hb_ot_position_complex (hb_font_t    *font,
189                          hb_face_t    *face,
190                          hb_buffer_t  *buffer,
191                          hb_feature_t *features,
192                          unsigned int  num_features)
193 {
194   lookup_map lookups[1000];
195   unsigned int num_lookups = ARRAY_LENGTH (lookups);
196   unsigned int i;
197
198   if (!hb_ot_layout_has_positioning (face))
199     return FALSE;
200
201   setup_lookups (face, buffer, features, num_features,
202                  HB_OT_TAG_GPOS,
203                  lookups, &num_lookups);
204
205   for (i = 0; i < num_lookups; i++)
206     hb_ot_layout_position_lookup (font, face, buffer, lookups[i].index, lookups[i].mask);
207
208   hb_ot_layout_position_finish (font, face, buffer);
209
210   return TRUE;
211 }