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