1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // Description:
25 // Parse a string of features specified as & separated pairs.
26 // e.g.
27 // 1001=1&2002=2&fav1=0
28 
29 // MARKER(update_precomp.py): autogen include statement, do not remove
30 #include "precompiled_vcl.hxx"
31 
32 #include <sal/types.h>
33 
34 #ifdef WNT
35 #include <tools/svwin.h>
36 #include <svsys.h>
37 #endif
38 
39 #include <graphite_features.hxx>
40 
41 using namespace grutils;
42 // These mustn't conflict with font name lists which use ; and ,
43 const char GrFeatureParser::FEAT_PREFIX = ':';
44 const char GrFeatureParser::FEAT_SEPARATOR = '&';
45 const char GrFeatureParser::FEAT_ID_VALUE_SEPARATOR = '=';
46 const std::string GrFeatureParser::ISO_LANG("lang");
47 
GrFeatureParser(gr::Font & font,const std::string lang)48 GrFeatureParser::GrFeatureParser(gr::Font & font, const std::string lang)
49     : mnNumSettings(0), mbErrors(false)
50 {
51     maLang.rgch[0] = maLang.rgch[1] = maLang.rgch[2] = maLang.rgch[3] = '\0';
52     setLang(font, lang);
53 }
54 
GrFeatureParser(gr::Font & font,const std::string features,const std::string lang)55 GrFeatureParser::GrFeatureParser(gr::Font & font, const std::string features, const std::string lang)
56     : mnNumSettings(0), mbErrors(false)
57 {
58     size_t nEquals = 0;
59     size_t nFeatEnd = 0;
60     size_t pos = 0;
61     maLang.rgch[0] = maLang.rgch[1] = maLang.rgch[2] = maLang.rgch[3] = '\0';
62     setLang(font, lang);
63     while (pos < features.length() && mnNumSettings < MAX_FEATURES)
64     {
65         nEquals = features.find(FEAT_ID_VALUE_SEPARATOR,pos);
66         if (nEquals == std::string::npos)
67         {
68             mbErrors = true;
69             break;
70         }
71         // check for a lang=xxx specification
72         if (features.compare(pos, nEquals - pos, ISO_LANG) == 0)
73         {
74             pos = nEquals + 1;
75             nFeatEnd = features.find(FEAT_SEPARATOR, pos);
76             if (nFeatEnd == std::string::npos)
77             {
78                 nFeatEnd = features.length();
79             }
80             if (nFeatEnd - pos > 3)
81                 mbErrors = true;
82             else
83             {
84                 gr::isocode aLang = maLang;
85                 for (size_t i = pos; i < nFeatEnd; i++)
86                     aLang.rgch[i-pos] = features[i];
87                 ext_std::pair<gr::LanguageIterator,gr::LanguageIterator> aSupported
88                     = font.getSupportedLanguages();
89                 gr::LanguageIterator iL = aSupported.first;
90                 while (iL != aSupported.second)
91                 {
92                     gr::isocode aSupportedLang = *iL;
93                     // here we only expect full 3 letter codes
94                     if (aLang.rgch[0] == aSupportedLang.rgch[0] &&
95                         aLang.rgch[1] == aSupportedLang.rgch[1] &&
96                         aLang.rgch[2] == aSupportedLang.rgch[2] &&
97                         aLang.rgch[3] == aSupportedLang.rgch[3]) break;
98                     ++iL;
99                 }
100                 if (iL == aSupported.second) mbErrors = true;
101                 else maLang = aLang;
102             }
103         }
104         else
105         {
106             if (isCharId(features, pos, nEquals - pos))
107                 maSettings[mnNumSettings].id = getCharId(features, pos, nEquals - pos);
108             else maSettings[mnNumSettings].id = getIntValue(features, pos, nEquals - pos);
109             pos = nEquals + 1;
110             nFeatEnd = features.find(FEAT_SEPARATOR, pos);
111             if (nFeatEnd == std::string::npos)
112             {
113                 nFeatEnd = features.length();
114             }
115             if (isCharId(features, pos, nFeatEnd - pos))
116                 maSettings[mnNumSettings].value = getCharId(features, pos, nFeatEnd - pos);
117             else
118                 maSettings[mnNumSettings].value= getIntValue(features, pos, nFeatEnd - pos);
119             if (isValid(font, maSettings[mnNumSettings]))
120                 mnNumSettings++;
121             else
122                 mbErrors = true;
123         }
124         pos = nFeatEnd + 1;
125     }
126 }
127 
setLang(gr::Font & font,const std::string & lang)128 void GrFeatureParser::setLang(gr::Font & font, const std::string & lang)
129 {
130     gr::isocode aLang = {{0,0,0,0}};
131     if (lang.length() > 2)
132     {
133         for (size_t i = 0; i < lang.length() && i < 3; i++)
134         {
135             if (lang[i] == '-') break;
136             aLang.rgch[i] = lang[i];
137         }
138         ext_std::pair<gr::LanguageIterator,gr::LanguageIterator> aSupported
139                     = font.getSupportedLanguages();
140         gr::LanguageIterator iL = aSupported.first;
141         while (iL != aSupported.second)
142         {
143             gr::isocode aSupportedLang = *iL;
144             if (aLang.rgch[0] == aSupportedLang.rgch[0] &&
145                 aLang.rgch[1] == aSupportedLang.rgch[1] &&
146                 aLang.rgch[2] == aSupportedLang.rgch[2] &&
147                 aLang.rgch[3] == aSupportedLang.rgch[3]) break;
148             ++iL;
149         }
150         if (iL != aSupported.second)
151             maLang = aLang;
152 #ifdef DEBUG
153         else
154             printf("%s has no features\n", aLang.rgch);
155 #endif
156     }
157 }
158 
GrFeatureParser(const GrFeatureParser & aCopy)159 GrFeatureParser::GrFeatureParser(const GrFeatureParser & aCopy)
160  : maLang(aCopy.maLang), mbErrors(aCopy.mbErrors)
161 {
162     mnNumSettings = aCopy.getFontFeatures(maSettings);
163 }
164 
~GrFeatureParser()165 GrFeatureParser::~GrFeatureParser()
166 {
167 }
168 
getFontFeatures(gr::FeatureSetting settings[64]) const169 size_t GrFeatureParser::getFontFeatures(gr::FeatureSetting settings[64]) const
170 {
171     if (settings)
172     {
173         std::copy(maSettings, maSettings + mnNumSettings, settings);
174     }
175     return mnNumSettings;
176 }
177 
isValid(gr::Font & font,gr::FeatureSetting & setting)178 bool GrFeatureParser::isValid(gr::Font & font, gr::FeatureSetting & setting)
179 {
180     gr::FeatureIterator i = font.featureWithID(setting.id);
181     if (font.getFeatures().second == i)
182     {
183         return false;
184     }
185     ext_std::pair< gr::FeatureSettingIterator, gr::FeatureSettingIterator >
186         validValues = font.getFeatureSettings(i);
187     gr::FeatureSettingIterator j = validValues.first;
188     while (j != validValues.second)
189     {
190         if (*j == setting.value) return true;
191         ++j;
192     }
193     return false;
194 }
195 
isCharId(const std::string & id,size_t offset,size_t length)196 bool GrFeatureParser::isCharId(const std::string & id, size_t offset, size_t length)
197 {
198     if (length > 4) return false;
199     for (size_t i = 0; i < length; i++)
200     {
201         if (i > 0 && id[offset+i] == '\0') continue;
202         if ((id[offset+i]) < 0x20 || (id[offset+i]) < 0)
203             return false;
204         if (i==0 && id[offset+i] < 0x41)
205             return false;
206     }
207     return true;
208 }
209 
getCharId(const std::string & id,size_t offset,size_t length)210 int GrFeatureParser::getCharId(const std::string & id, size_t offset, size_t length)
211 {
212     FeatId charId;
213     charId.num = 0;
214 #ifdef WORDS_BIGENDIAN
215     for (size_t i = 0; i < length; i++)
216     {
217         charId.label[i] = id[offset+i];
218     }
219 #else
220     for (size_t i = 0; i < length; i++)
221     {
222         charId.label[3-i] = id[offset+i];
223     }
224 #endif
225     return charId.num;
226 }
227 
getIntValue(const std::string & id,size_t offset,size_t length)228 int GrFeatureParser::getIntValue(const std::string & id, size_t offset, size_t length)
229 {
230     int value = 0;
231     int sign = 1;
232     for (size_t i = 0; i < length; i++)
233     {
234         switch (id[offset + i])
235         {
236         case '0':
237         case '1':
238         case '2':
239         case '3':
240         case '4':
241         case '5':
242         case '6':
243         case '7':
244         case '8':
245         case '9':
246             value *= 10;
247             if (sign < 0)
248             {
249                 value = -(id[offset + i] - '0');
250                 sign = 1;
251             }
252             value += (id[offset + i] - '0');
253             break;
254         case '-':
255             if (i == 0)
256                 sign = -1;
257             else
258             {
259                 mbErrors = true;
260                 break;
261             }
262         default:
263             mbErrors = true;
264             break;
265         }
266     }
267     return value;
268 }
269 
270 
hashCode() const271 sal_Int32 GrFeatureParser::hashCode() const
272 {
273     union IsoHash { sal_Int32 mInt; gr::isocode mCode; };
274     IsoHash isoHash;
275     isoHash.mCode = maLang;
276     sal_Int32 hash = isoHash.mInt;
277     for (size_t i = 0; i < mnNumSettings; i++)
278     {
279         hash = (hash << 16) ^ ((maSettings[i].id << 8) | maSettings[i].value);
280     }
281     return hash;
282 }
283