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