1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  */
10 
11 #include <font/OpenTypeFeatureDefinitionList.hxx>
12 #include <font/OpenTypeFeatureStrings.hrc>
13 
14 #include <rtl/character.hxx>
15 
16 #include <algorithm>
17 
18 namespace vcl::font
19 {
OpenTypeFeatureDefinitionListPrivate()20 OpenTypeFeatureDefinitionListPrivate::OpenTypeFeatureDefinitionListPrivate() { init(); }
21 
init()22 void OpenTypeFeatureDefinitionListPrivate::init()
23 {
24     m_aFeatureDefinition.assign({
25         { featureCode("aalt"), STR_FONT_FEATURE_ID_AALT },
26         { featureCode("afrc"), STR_FONT_FEATURE_ID_AFRC },
27         { featureCode("alig"), STR_FONT_FEATURE_ID_ALIG },
28         { featureCode("c2pc"), STR_FONT_FEATURE_ID_C2PC },
29         { featureCode("c2sc"), STR_FONT_FEATURE_ID_C2SC },
30         { featureCode("calt"), STR_FONT_FEATURE_ID_CALT },
31         { featureCode("case"), STR_FONT_FEATURE_ID_CASE },
32         { featureCode("clig"), STR_FONT_FEATURE_ID_CLIG },
33         { featureCode("cpct"), STR_FONT_FEATURE_ID_CPCT },
34         { featureCode("cpsp"), STR_FONT_FEATURE_ID_CPSP },
35         { featureCode("cswh"), STR_FONT_FEATURE_ID_CSWH },
36         { featureCode("dcap"), STR_FONT_FEATURE_ID_DCAP },
37         { featureCode("dlig"), STR_FONT_FEATURE_ID_DLIG },
38         { featureCode("dnom"), STR_FONT_FEATURE_ID_DNOM },
39         { featureCode("dpng"), STR_FONT_FEATURE_ID_DPNG },
40         { featureCode("expt"), STR_FONT_FEATURE_ID_EXPT },
41         { featureCode("falt"), STR_FONT_FEATURE_ID_FALT },
42         { featureCode("frac"), STR_FONT_FEATURE_ID_FRAC,
43           std::vector<FeatureParameter>{ { 0, STR_FONT_FEATURE_ID_FRAC_PARAM_0 },
44                                          { 1, STR_FONT_FEATURE_ID_FRAC_PARAM_1 },
45                                          { 2, STR_FONT_FEATURE_ID_FRAC_PARAM_2 } } },
46         { featureCode("fwid"), STR_FONT_FEATURE_ID_FWID },
47         { featureCode("halt"), STR_FONT_FEATURE_ID_HALT },
48         { featureCode("hist"), STR_FONT_FEATURE_ID_HIST },
49         { featureCode("hkna"), STR_FONT_FEATURE_ID_HKNA },
50         { featureCode("hlig"), STR_FONT_FEATURE_ID_HLIG },
51         { featureCode("hngl"), STR_FONT_FEATURE_ID_HNGL },
52         { featureCode("hojo"), STR_FONT_FEATURE_ID_HOJO },
53         { featureCode("hwid"), STR_FONT_FEATURE_ID_HWID },
54         { featureCode("ital"), STR_FONT_FEATURE_ID_ITAL },
55         { featureCode("jalt"), STR_FONT_FEATURE_ID_JALT },
56         { featureCode("jp78"), STR_FONT_FEATURE_ID_JP78 },
57         { featureCode("jp83"), STR_FONT_FEATURE_ID_JP83 },
58         { featureCode("jp90"), STR_FONT_FEATURE_ID_JP90 },
59         { featureCode("jp04"), STR_FONT_FEATURE_ID_JP04 },
60         { featureCode("kern"), STR_FONT_FEATURE_ID_KERN },
61         { featureCode("lfbd"), STR_FONT_FEATURE_ID_LFBD },
62         { featureCode("liga"), STR_FONT_FEATURE_ID_LIGA },
63         { featureCode("lnum"), STR_FONT_FEATURE_ID_LNUM },
64         { featureCode("mgrk"), STR_FONT_FEATURE_ID_MGRK },
65         { featureCode("nalt"), STR_FONT_FEATURE_ID_NALT },
66         { featureCode("nlck"), STR_FONT_FEATURE_ID_NLCK },
67         { featureCode("numr"), STR_FONT_FEATURE_ID_NUMR },
68         { featureCode("onum"), STR_FONT_FEATURE_ID_ONUM },
69         { featureCode("opbd"), STR_FONT_FEATURE_ID_OPBD },
70         { featureCode("ordn"), STR_FONT_FEATURE_ID_ORDN },
71         { featureCode("ornm"), STR_FONT_FEATURE_ID_ORNM },
72         { featureCode("palt"), STR_FONT_FEATURE_ID_PALT },
73         { featureCode("pcap"), STR_FONT_FEATURE_ID_PCAP },
74         { featureCode("pkna"), STR_FONT_FEATURE_ID_PKNA },
75         { featureCode("pnum"), STR_FONT_FEATURE_ID_PNUM },
76         { featureCode("pwid"), STR_FONT_FEATURE_ID_PWID },
77         { featureCode("qwid"), STR_FONT_FEATURE_ID_QWID },
78         { featureCode("rtbd"), STR_FONT_FEATURE_ID_RTBD },
79         { featureCode("ruby"), STR_FONT_FEATURE_ID_RUBY },
80         { featureCode("salt"), STR_FONT_FEATURE_ID_SALT },
81         { featureCode("sinf"), STR_FONT_FEATURE_ID_SINF },
82         { featureCode("smcp"), STR_FONT_FEATURE_ID_SMCP },
83         { featureCode("smpl"), STR_FONT_FEATURE_ID_SMPL },
84         { featureCode("subs"), STR_FONT_FEATURE_ID_SUBS },
85         { featureCode("sups"), STR_FONT_FEATURE_ID_SUPS },
86         { featureCode("swsh"), STR_FONT_FEATURE_ID_SWSH },
87         { featureCode("titl"), STR_FONT_FEATURE_ID_TITL },
88         { featureCode("tnam"), STR_FONT_FEATURE_ID_TNAM },
89         { featureCode("tnum"), STR_FONT_FEATURE_ID_TNUM },
90         { featureCode("trad"), STR_FONT_FEATURE_ID_TRAD },
91         { featureCode("twid"), STR_FONT_FEATURE_ID_TWID },
92         { featureCode("unic"), STR_FONT_FEATURE_ID_UNIC },
93         { featureCode("valt"), STR_FONT_FEATURE_ID_VALT },
94         { featureCode("vhal"), STR_FONT_FEATURE_ID_VHAL },
95         { featureCode("vkna"), STR_FONT_FEATURE_ID_VKNA },
96         { featureCode("vkrn"), STR_FONT_FEATURE_ID_VKRN },
97         { featureCode("vpal"), STR_FONT_FEATURE_ID_VPAL },
98         { featureCode("vrt2"), STR_FONT_FEATURE_ID_VRT2 },
99         { featureCode("vrtr"), STR_FONT_FEATURE_ID_VRTR },
100         { featureCode("zero"), STR_FONT_FEATURE_ID_ZERO },
101     });
102 
103     for (size_t i = 0; i < m_aFeatureDefinition.size(); ++i)
104     {
105         m_aCodeToIndex.emplace(m_aFeatureDefinition[i].getCode(), i);
106     }
107 
108     m_aRequiredFeatures.assign({
109         featureCode("abvf"), featureCode("abvm"), featureCode("abvs"), featureCode("akhn"),
110         featureCode("blwf"), featureCode("blwm"), featureCode("blws"), featureCode("ccmp"),
111         featureCode("cfar"), featureCode("cjct"), featureCode("curs"), featureCode("dist"),
112         featureCode("dtls"), featureCode("fin2"), featureCode("fin3"), featureCode("fina"),
113         featureCode("flac"), featureCode("half"), featureCode("haln"), featureCode("init"),
114         featureCode("isol"), featureCode("ljmo"), featureCode("locl"), featureCode("ltra"),
115         featureCode("ltrm"), featureCode("mark"), featureCode("med2"), featureCode("medi"),
116         featureCode("mkmk"), featureCode("mset"), featureCode("nukt"), featureCode("pref"),
117         featureCode("pres"), featureCode("pstf"), featureCode("psts"), featureCode("rand"),
118         featureCode("rclt"), featureCode("rkrf"), featureCode("rlig"), featureCode("rphf"),
119         featureCode("rtla"), featureCode("rtlm"), featureCode("rvrn"), featureCode("size"),
120         featureCode("ssty"), featureCode("stch"), featureCode("tjmo"), featureCode("vatu"),
121         featureCode("vert"), featureCode("vjmo"),
122     });
123 }
124 
125 namespace
126 {
isCharacterVariantCode(sal_uInt32 nFeatureCode)127 bool isCharacterVariantCode(sal_uInt32 nFeatureCode)
128 {
129     return char((sal_uInt32(nFeatureCode) >> 24) & 0xFF) == 'c'
130            && char((sal_uInt32(nFeatureCode) >> 16) & 0xFF) == 'v';
131 }
132 
isStylisticSetCode(sal_uInt32 nFeatureCode)133 bool isStylisticSetCode(sal_uInt32 nFeatureCode)
134 {
135     return char((sal_uInt32(nFeatureCode) >> 24) & 0xFF) == 's'
136            && char((sal_uInt32(nFeatureCode) >> 16) & 0xFF) == 's';
137 }
138 
getNumericLowerPart(sal_uInt32 nFeatureCode)139 OUString getNumericLowerPart(sal_uInt32 nFeatureCode)
140 {
141     char cChar1((sal_uInt32(nFeatureCode) >> 8) & 0xFF);
142     char cChar2((sal_uInt32(nFeatureCode) >> 0) & 0xFF);
143 
144     if (rtl::isAsciiDigit(static_cast<unsigned char>(cChar1))
145         && rtl::isAsciiDigit(static_cast<unsigned char>(cChar2)))
146     {
147         return OUStringChar(cChar1) + OUStringChar(cChar2);
148     }
149     return OUString();
150 }
151 
152 } // end anonymous namespace
153 
isSpecialFeatureCode(sal_uInt32 nFeatureCode)154 bool OpenTypeFeatureDefinitionListPrivate::isSpecialFeatureCode(sal_uInt32 nFeatureCode)
155 {
156     return isCharacterVariantCode(nFeatureCode) || isStylisticSetCode(nFeatureCode);
157 }
158 
159 FeatureDefinition
handleSpecialFeatureCode(sal_uInt32 nFeatureCode)160 OpenTypeFeatureDefinitionListPrivate::handleSpecialFeatureCode(sal_uInt32 nFeatureCode)
161 {
162     FeatureDefinition aFeatureDefinition;
163     OUString sNumericPart = getNumericLowerPart(nFeatureCode);
164     if (!sNumericPart.isEmpty())
165     {
166         if (isCharacterVariantCode(nFeatureCode))
167             aFeatureDefinition = { nFeatureCode, STR_FONT_FEATURE_ID_CVXX, sNumericPart };
168         else if (isStylisticSetCode(nFeatureCode))
169             aFeatureDefinition = { nFeatureCode, STR_FONT_FEATURE_ID_SSXX, sNumericPart };
170     }
171     return aFeatureDefinition;
172 }
173 
getDefinition(sal_uInt32 nFeatureCode)174 FeatureDefinition OpenTypeFeatureDefinitionListPrivate::getDefinition(sal_uInt32 nFeatureCode)
175 {
176     if (isSpecialFeatureCode(nFeatureCode))
177     {
178         return handleSpecialFeatureCode(nFeatureCode);
179     }
180 
181     if (m_aCodeToIndex.find(nFeatureCode) != m_aCodeToIndex.end())
182     {
183         size_t nIndex = m_aCodeToIndex.at(nFeatureCode);
184         return m_aFeatureDefinition[nIndex];
185     }
186     return FeatureDefinition();
187 }
188 
isRequired(sal_uInt32 nFeatureCode)189 bool OpenTypeFeatureDefinitionListPrivate::isRequired(sal_uInt32 nFeatureCode)
190 {
191     return std::find(m_aRequiredFeatures.begin(), m_aRequiredFeatures.end(), nFeatureCode)
192            != m_aRequiredFeatures.end();
193 }
194 
195 } // end vcl::font namespace
196 
197 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
198