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  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <unotools/fontdefs.hxx>
21 #include <unotools/fontcfg.hxx>
22 #include <rtl/ustrbuf.hxx>
23 #include <unordered_map>
24 
25 struct ImplLocalizedFontName
26 {
27     const char*         mpEnglishName;
28     const sal_Unicode*  mpLocalizedNames;
29 };
30 
31 // TODO: where did the 0,0 delimiters come from? A single 0 should suffice...
32 static sal_Unicode const aBatang[] = { 0xBC14, 0xD0D5, 0, 0 };
33 static sal_Unicode const aBatangChe[] = { 0xBC14, 0xD0D5, 0xCCB4, 0, 0 };
34 static sal_Unicode const aGungsuh[] = { 0xAD81, 0xC11C, 0, 0 };
35 static sal_Unicode const aGungsuhChe[] = { 0xAD81, 0xC11C, 0xCCB4, 0, 0 };
36 static sal_Unicode const aGulim[] = { 0xAD74, 0xB9BC, 0, 0 };
37 static sal_Unicode const aGulimChe[] = { 0xAD74, 0xB9BC, 0xCCB4, 0, 0 };
38 static sal_Unicode const aDotum[] = { 0xB3CB, 0xC6C0, 0, 0 };
39 static sal_Unicode const aDotumChe[] = { 0xB3CB, 0xC6C0, 0xCCB4, 0, 0 };
40 static sal_Unicode const aSimSun[] = { 0x5B8B, 0x4F53, 0, 0 };
41 static sal_Unicode const aNSimSun[] = { 0x65B0, 0x5B8B, 0x4F53, 0, 0 };
42 static sal_Unicode const aSimHei[] = { 0x9ED1, 0x4F53, 0, 0 };
43 static sal_Unicode const aSimKai[] = { 0x6977, 0x4F53, 0, 0 };
44 static sal_Unicode const azycjkSun[] = { 0x4E2D, 0x6613, 0x5B8B, 0x4F53, 0, 0 };
45 static sal_Unicode const azycjkHei[] = { 0x4E2D, 0x6613, 0x9ED1, 0x4F53, 0, 0 };
46 static sal_Unicode const azycjkKai[] = { 0x4E2D, 0x6613, 0x6977, 0x4F53, 0, 0 };
47 static sal_Unicode const aFZHei[] = { 0x65B9, 0x6B63, 0x9ED1, 0x4F53, 0, 0 };
48 static sal_Unicode const aFZKai[] = { 0x65B9, 0x6B63, 0x6977, 0x4F53, 0, 0 };
49 static sal_Unicode const aFZSongYI[] = { 0x65B9, 0x6B63, 0x5B8B, 0x4E00, 0, 0 };
50 static sal_Unicode const aFZShuSong[] = { 0x65B9, 0x6B63, 0x4E66, 0x5B8B, 0, 0 };
51 static sal_Unicode const aFZFangSong[] = { 0x65B9, 0x6B63, 0x4EFF, 0x5B8B, 0, 0 };
52 // Attention: this fonts includes the wrong encoding vector - so we double the names with correct and wrong encoding
53 // First one is the GB-Encoding (we think the correct one), second is the big5 encoded name
54 static sal_Unicode const aMHei[] = { 'm', 0x7B80, 0x9ED1, 0, 'm', 0x6F60, 0x7AAA, 0, 0 };
55 static sal_Unicode const aMKai[] = { 'm', 0x7B80, 0x6977, 0x566C, 0, 'm', 0x6F60, 0x7FF1, 0x628E, 0, 0 };
56 static sal_Unicode const aMSong[] = { 'm', 0x7B80, 0x5B8B, 0, 'm', 0x6F60, 0x51BC, 0, 0 };
57 static sal_Unicode const aCFangSong[] = { 'm', 0x7B80, 0x592B, 0x5B8B, 0, 'm', 0x6F60, 0x6E98, 0x51BC, 0, 0 };
58 static sal_Unicode const aMingLiU[] = { 0x7D30, 0x660E, 0x9AD4, 0, 0 };
59 static sal_Unicode const aPMingLiU[] = { 0x65B0, 0x7D30, 0x660E, 0x9AD4, 0, 0 };
60 static sal_Unicode const aHei[] = { 0x6865, 0, 0 };
61 static sal_Unicode const aKai[] = { 0x6B61, 0, 0 };
62 static sal_Unicode const aMing[] = { 0x6D69, 0x6E67, 0, 0 };
63 static sal_Unicode const aMSGothic[] = { 'm','s',       0x30B4, 0x30B7, 0x30C3, 0x30AF, 0, 0 };
64 static sal_Unicode const aMSPGothic[] = { 'm','s','p',  0x30B4, 0x30B7, 0x30C3, 0x30AF, 0, 0 };
65 static sal_Unicode const aMSMincho[] = { 'm', 's',      0x660E, 0x671D, 0 };
66 static sal_Unicode const aMSPMincho[] = { 'm','s','p',  0x660E, 0x671D, 0 };
67 static sal_Unicode const aMSYaHei[] = { 0x5FAE, 0x8F6F, 0x96C5, 0x9ED1, 0 };
68 static sal_Unicode const aMSJhengHei[] = { 0x5FAE, 0x8EDF, 0x6B63, 0x9ED1, 0x9AD4, 0 };
69 static sal_Unicode const aMeiryo[]    = { 0x30e1, 0x30a4, 0x30ea, 0x30aa, 0 };
70 static sal_Unicode const aHGMinchoL[] = { 'h','g',      0x660E, 0x671D, 'l', 0, 0 };
71 static sal_Unicode const aHGGothicB[] = { 'h','g',      0x30B4, 0x30B7, 0x30C3, 0x30AF, 'b', 0 };
72 static sal_Unicode const aHGPMinchoL[] = { 'h','g','p', 0x660E, 0x671D, 'l', 0 };
73 static sal_Unicode const aHGPGothicB[] = { 'h','g','p', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 'b', 0 };
74 static sal_Unicode const aHGMinchoLSun[] = { 'h','g',   0x660E, 0x671D, 'l', 's', 'u', 'n', 0 };
75 static sal_Unicode const aHGPMinchoLSun[] = { 'h','g','p', 0x660E, 0x671D, 'l', 's', 'u', 'n', 0 };
76 static sal_Unicode const aHGGothicBSun[] = { 'h', 'g', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 'b', 's', 'u', 'n', 0 };
77 static sal_Unicode const aHGPGothicBSun[] = { 'h', 'g', 'p', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 'b', 's', 'u', 'n', 0 };
78 static sal_Unicode const aHGHeiseiMin[] = { 'h', 'g', 0x5E73, 0x6210, 0x660E, 0x671D, 0x4F53, 0, 'h', 'g', 0x5E73, 0x6210, 0x660E, 0x671D, 0x4F53, 'w', '3', 'x', '1', '2', 0, 0 };
79 static sal_Unicode const aIPAMincho[] =  { 'i', 'p', 'a', 0x660E, 0x671D, 0 };
80 static sal_Unicode const aIPAPMincho[] = { 'i', 'p', 'a', 'p', 0x660E, 0x671D, 0 };
81 static sal_Unicode const aIPAGothic[] =  { 'i', 'p', 'a',  0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
82 static sal_Unicode const aIPAPGothic[] =  { 'i', 'p', 'a', 'p', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
83 static sal_Unicode const aIPAUIGothic[] =  { 'i', 'p', 'a', 'u', 'i', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
84 static sal_Unicode const aTakaoMincho[] =  { 't', 'a', 'k', 'a', 'o', 0x660E, 0x671D, 0 };
85 static sal_Unicode const aTakaoPMincho[] = { 't', 'a', 'k', 'a', 'o', 'p', 0x660E, 0x671D, 0 };
86 static sal_Unicode const aTakaoGothic[] =  { 't', 'a', 'k', 'a', 'o',  0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
87 static sal_Unicode const aTakaoPGothic[] =  { 't', 'a', 'k', 'a', 'o', 'p', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
88 static sal_Unicode const aSazanamiMincho[] = { 0x3055, 0x3056, 0x306A, 0x307F, 0x660E, 0x671D, 0, 0 };
89 static sal_Unicode const aSazanamiGothic[] = { 0x3055, 0x3056, 0x306A, 0x307F, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0, 0 };
90 static sal_Unicode const aKochiMincho[] = { 0x6771, 0x98A8, 0x660E, 0x671D, 0, 0 };
91 static sal_Unicode const aKochiGothic[] = { 0x6771, 0x98A8, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0, 0 };
92 static sal_Unicode const aSunDotum[] = { 0xC36C, 0xB3CB, 0xC6C0, 0, 0 };
93 static sal_Unicode const aSunGulim[] = { 0xC36C, 0xAD74, 0xB9BC, 0, 0 };
94 static sal_Unicode const aSunBatang[] = { 0xC36C, 0xBC14, 0xD0D5, 0, 0 };
95 static sal_Unicode const aBaekmukDotum[] = { 0xBC31, 0xBB35, 0xB3CB, 0xC6C0, 0, 0 };
96 static sal_Unicode const aBaekmukGulim[] = { 0xBC31, 0xBB35, 0xAD74, 0xB9BC, 0, 0 };
97 static sal_Unicode const aBaekmukBatang[] = { 0xBC31, 0xBB35, 0xBC14, 0xD0D5, 0, 0 };
98 static sal_Unicode const aFzMingTi[] = { 0x65B9, 0x6B63, 0x660E, 0x9AD4, 0, 0 };
99 static sal_Unicode const aFzHeiTiTW[]= { 0x65B9, 0x6B63, 0x9ED1, 0x9AD4, 0, 0 };
100 static sal_Unicode const aFzKaiTiTW[]= { 0x65B9, 0x6B63, 0x6977, 0x9AD4, 0, 0 };
101 static sal_Unicode const aFzHeiTiCN[]= { 0x65B9, 0x6B63, 0x9ED1, 0x4F53, 0, 0 };
102 static sal_Unicode const aFzKaiTiCN[]= { 0x65B9, 0x6B63, 0x6977, 0x4F53, 0, 0 };
103 static sal_Unicode const aFzSongTi[] = { 0x65B9, 0x6B63, 0x5B8B, 0x4F53, 0, 0 };
104 static sal_Unicode const aHYMyeongJoExtra[]         = { 'h', 'y', 0xACAC, 0xBA85, 0xC870, 0, 0 };
105 static sal_Unicode const aHYSinMyeongJoMedium[]     = { 'h', 'y', 0xC2E0, 0xBA85, 0xC870, 0, 0 };
106 static sal_Unicode const aHYGothicMedium[]          = { 'h', 'y', 0xC911, 0xACE0, 0xB515, 0, 0 };
107 static sal_Unicode const aHYGraphicMedium[]         = { 'h', 'y', 0xADF8, 0xB798, 0xD53D, 'm', 0, 0 };
108 static sal_Unicode const aHYGraphic[]               = { 'h', 'y', 0xADF8, 0xB798, 0xD53D, 0, 0 };
109 static sal_Unicode const aNewGulim[]                = { 0xC0C8, 0xAD74, 0xB9BC, 0, 0 };
110 static sal_Unicode const aSunGungseo[]              = { 0xC36C, 0xAD81, 0xC11C, 0, 0 };
111 static sal_Unicode const aHYGungSoBold[]            = { 'h','y', 0xAD81, 0xC11C, 'b', 0, 0 };
112 static sal_Unicode const aHYGungSo[]                 = { 'h','y', 0xAD81, 0xC11C, 0, 0 };
113 static sal_Unicode const aSunHeadLine[]             = { 0xC36C, 0xD5E4, 0xB4DC, 0xB77C, 0xC778, 0, 0 };
114 static sal_Unicode const aHYHeadLineMedium[]        = { 'h', 'y', 0xD5E4, 0xB4DC, 0xB77C, 0xC778, 'm', 0, 0 };
115 static sal_Unicode const aHYHeadLine[]              = { 'h', 'y', 0xD5E4, 0xB4DC, 0xB77C, 0xC778, 0, 0 };
116 static sal_Unicode const aYetR[]                    = { 0xD734, 0xBA3C, 0xC61B, 0xCCB4, 0, 0 };
117 static sal_Unicode const aHYGothicExtra[]           = { 'h', 'y', 0xACAC, 0xACE0, 0xB515, 0, 0 };
118 static sal_Unicode const aSunMokPan[]               = { 0xC36C, 0xBAA9, 0xD310, 0, 0 };
119 static sal_Unicode const aSunYeopseo[]              = { 0xC36C, 0xC5FD, 0xC11C, 0, 0 };
120 static sal_Unicode const aSunBaekSong[]              = { 0xC36C, 0xBC31, 0xC1A1, 0, 0 };
121 static sal_Unicode const aHYPostLight[]             = { 'h', 'y', 0xC5FD, 0xC11C, 'l', 0, 0 };
122 static sal_Unicode const aHYPost[]                  = { 'h', 'y', 0xC5FD, 0xC11C, 0, 0 };
123 static sal_Unicode const aMagicR[]                  = { 0xD734, 0xBA3C, 0xB9E4, 0xC9C1, 0xCCB4, 0, 0 };
124 static sal_Unicode const aSunCrystal[]              = { 0xC36C, 0xD06C, 0xB9AC, 0xC2A4, 0xD0C8, 0, 0 };
125 static sal_Unicode const aSunSaemmul[]              = { 0xC36C, 0xC0D8, 0xBB3C, 0, 0 };
126 static sal_Unicode const aHaansoftBatang[]          = { 0xD55C, 0xCEF4, 0xBC14, 0xD0D5, 0, 0 };
127 static sal_Unicode const aHaansoftDotum[]           = { 0xD55C, 0xCEF4, 0xB3CB, 0xC6C0, 0, 0 };
128 static sal_Unicode const aHyhaeseo[]                = { 0xD55C, 0xC591, 0xD574, 0xC11C, 0, 0 };
129 static sal_Unicode const aMDSol[]                   = { 'm', 'd', 0xC194, 0xCCB4, 0, 0 };
130 static sal_Unicode const aMDGaesung[]               = { 'm', 'd', 0xAC1C, 0xC131, 0xCCB4, 0, 0 };
131 static sal_Unicode const aMDArt[]                   = { 'm', 'd', 0xC544, 0xD2B8, 0xCCB4, 0, 0 };
132 static sal_Unicode const aMDAlong[]                 = { 'm', 'd', 0xC544, 0xB871, 0xCCB4, 0, 0 };
133 static sal_Unicode const aMDEasop[]                 = { 'm', 'd', 0xC774, 0xC19D, 0xCCB4, 0, 0 };
134 static sal_Unicode const aHYShortSamulMedium[]      = { 'h', 'y', 0xC595, 0xC740, 0xC0D8, 0xBB3C, 'm', 0 };
135 static sal_Unicode const aHYShortSamul[]            = { 'h', 'y', 0xC595, 0xC740, 0xC0D8, 0xBB3C, 0 };
136 static sal_Unicode const aHGGothicE[]               = { 'h','g', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'e', 0 };
137 static sal_Unicode const aHGPGothicE[]              = { 'h','g','p', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'e', 0 };
138 static sal_Unicode const aHGSGothicE[]              = { 'h','g','s', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'e', 0 };
139 static sal_Unicode const aHGGothicM[]               = { 'h','g', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'm', 0 };
140 static sal_Unicode const aHGPGothicM[]              = { 'h','g','p', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'm', 0 };
141 static sal_Unicode const aHGSGothicM[]              = { 'h','g','s', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'm', 0 };
142 static sal_Unicode const aHGGyoshotai[]             = { 'h','g', 0x884C, 0x66F8, 0x4F53, 0 };
143 static sal_Unicode const aHGPGyoshotai[]            = { 'h','g','p', 0x884C, 0x66F8, 0x4F53, 0 };
144 static sal_Unicode const aHGSGyoshotai[]            = { 'h','g','s', 0x884C, 0x66F8, 0x4F53, 0 };
145 static sal_Unicode const aHGKyokashotai[]           = { 'h','g', 0x6559, 0x79D1, 0x66F8, 0x4F53, 0 };
146 static sal_Unicode const aHGPKyokashotai[]          = { 'h','g','p', 0x6559, 0x79D1, 0x66F8, 0x4F53, 0 };
147 static sal_Unicode const aHGSKyokashotai[]          = { 'h','g','s', 0x6559, 0x79D1, 0x66F8, 0x4F53, 0 };
148 static sal_Unicode const aHGMinchoB[]               = { 'h','g', 0x660E, 0x671D, 'b', 0 };
149 static sal_Unicode const aHGPMinchoB[]              = { 'h','g','p', 0x660E, 0x671D, 'b', 0 };
150 static sal_Unicode const aHGSMinchoB[]              = { 'h','g','s', 0x660E, 0x671D, 'b', 0 };
151 static sal_Unicode const aHGMinchoE[]               = { 'h','g', 0x660E, 0x671D, 'e', 0 };
152 static sal_Unicode const aHGPMinchoE[]              = { 'h','g','p', 0x660E, 0x671D, 'e', 0 };
153 static sal_Unicode const aHGSMinchoE[]              = { 'h','g','s', 0x660E, 0x671D, 'e', 0 };
154 static sal_Unicode const aHGSoeiKakupoptai[]        = { 'h','g', 0x5275,0x82F1,0x89D2,0xFF8E,
155                             0xFF9F,0xFF6F,0xFF8C,0xFF9F,0x4F53,0};
156 static sal_Unicode const aHGPSoeiKakupoptai[]       = { 'h','g', 'p', 0x5275,0x82F1,0x89D2,0xFF8E,
157                             0xFF9F,0xFF6F,0xFF8C,0xFF9F,0x4F53,0};
158 static sal_Unicode const aHGSSoeiKakupoptai[]       = { 'h','g', 's', 0x5275,0x82F1,0x89D2,0xFF8E,
159                             0xFF9F,0xFF6F,0xFF8C,0xFF9F,0x4F53,0};
160 static sal_Unicode const aHGSoeiPresenceEB[]        = { 'h','g', 0x5275,0x82F1,0xFF8C,0xFF9F,
161                             0xFF9A,0xFF7E,0xFF9E,0xFF9D,0xFF7D, 'e','b',0};
162 static sal_Unicode const aHGPSoeiPresenceEB[]       = { 'h','g','p', 0x5275,0x82F1,0xFF8C,0xFF9F,
163                             0xFF9A,0xFF7E,0xFF9E,0xFF9D,0xFF7D, 'e','b',0};
164 static sal_Unicode const aHGSSoeiPresenceEB[]       = { 'h','g','s', 0x5275,0x82F1,0xFF8C,0xFF9F,
165                             0xFF9A,0xFF7E,0xFF9E,0xFF9D,0xFF7D, 'e','b',0};
166 static sal_Unicode const aHGSoeiKakugothicUB[]      = { 'h','g', 0x5275,0x82F1,0x89D2,0xFF7A,
167                             0xFF9E,0xFF7C,0xFF6F,0xFF78,'u','b',0};
168 static sal_Unicode const aHGPSoeiKakugothicUB[]     = { 'h','g','p', 0x5275,0x82F1,0x89D2,0xFF7A,
169                             0xFF9E,0xFF7C,0xFF6F,0xFF78,'u','b',0};
170 static sal_Unicode const aHGSSoeiKakugothicUB[]     = { 'h','g','s', 0x5275,0x82F1,0x89D2,0xFF7A,
171                             0xFF9E,0xFF7C,0xFF6F,0xFF78,'u','b',0};
172 static sal_Unicode const aHGSeikaishotaiPRO[]       = { 'h','g', 0x6B63,0x6977,0x66F8,0x4F53, '-','p','r','o',0};
173 static sal_Unicode const aHGMaruGothicMPRO[]        = { 'h','g', 0x4E38,0xFF7A,0xFF9E,0xFF7C,0xFF6F,0xFF78, '-','p','r','o',0};
174 static sal_Unicode const aHiraginoMinchoPro[]       = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x660E, 0x671D, 'p','r','o',0};
175 static sal_Unicode const aHiraginoMinchoProN[]      = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x660E, 0x671D, 'p','r','o','n',0};
176 static sal_Unicode const aHiraginoKakuGothicPro[]   = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x89D2, 0x30B4, 'p','r','o',0};
177 static sal_Unicode const aHiraginoKakuGothicProN[]  = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x89D2, 0x30B4, 'p','r','o','n',0};
178 static sal_Unicode const aHiraginoMaruGothicPro[]   = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x4E38, 0x30B4, 'p','r','o',0};
179 static sal_Unicode const aHiraginoMaruGothicProN[]  = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x4E38, 0x30B4, 'p','r','o','n',0};
180 
181 static const ImplLocalizedFontName aImplLocalizedNamesList[] =
182 {
183 {   "batang",               aBatang },
184 {   "batangche",            aBatangChe },
185 {   "gungshu",              aGungsuh },
186 {   "gungshuche",           aGungsuhChe },
187 {   "gulim",                aGulim },
188 {   "gulimche",             aGulimChe },
189 {   "dotum",                aDotum },
190 {   "dotumche",             aDotumChe },
191 {   "simsun",               aSimSun },
192 {   "nsimsun",              aNSimSun },
193 {   "simhei",               aSimHei },
194 {   "simkai",               aSimKai },
195 {   "zycjksun",             azycjkSun },
196 {   "zycjkhei",             azycjkHei },
197 {   "zycjkkai",             azycjkKai },
198 {   "fzhei",                aFZHei },
199 {   "fzkai",                aFZKai },
200 {   "fzsong",               aFZSongYI },
201 {   "fzshusong",            aFZShuSong },
202 {   "fzfangsong",           aFZFangSong },
203 {   "mhei",                 aMHei },
204 {   "mkai",                 aMKai },
205 {   "msong",                aMSong },
206 {   "cfangsong",            aCFangSong },
207 {   "mingliu",              aMingLiU },
208 {   "pmingliu",             aPMingLiU },
209 {   "hei",                  aHei },
210 {   "kai",                  aKai },
211 {   "ming",                 aMing },
212 {   "msgothic",             aMSGothic },
213 {   "mspgothic",            aMSPGothic },
214 {   "msmincho",             aMSMincho },
215 {   "mspmincho",            aMSPMincho },
216 {   "microsoftjhenghei",    aMSJhengHei },
217 {   "microsoftyahei",       aMSYaHei },
218 {   "meiryo",               aMeiryo },
219 {   "hgminchol",            aHGMinchoL },
220 {   "hggothicb",            aHGGothicB },
221 {   "hgpminchol",           aHGPMinchoL },
222 {   "hgpgothicb",           aHGPGothicB },
223 {   "hgmincholsun",         aHGMinchoLSun },
224 {   "hggothicbsun",         aHGGothicBSun },
225 {   "hgpmincholsun",        aHGPMinchoLSun },
226 {   "hgpgothicbsun",        aHGPGothicBSun },
227 {   "hgheiseimin",          aHGHeiseiMin },
228 {   "ipamincho",            aIPAMincho },
229 {   "ipapmincho",           aIPAPMincho },
230 {   "ipagothic",            aIPAGothic },
231 {   "ipapgothic",           aIPAPGothic },
232 {   "ipauigothic",          aIPAUIGothic },
233 {   "takaomincho",          aTakaoMincho },
234 {   "takaopmincho",         aTakaoPMincho },
235 {   "takaogothic",          aTakaoGothic },
236 {   "takaopgothic",         aTakaoPGothic },
237 {   "sazanamimincho",       aSazanamiMincho },
238 {   "sazanamigothic",       aSazanamiGothic },
239 {   "kochimincho",          aKochiMincho },
240 {   "kochigothic",          aKochiGothic },
241 {   "sundotum",             aSunDotum },
242 {   "sungulim",             aSunGulim },
243 {   "sunbatang",            aSunBatang },
244 {   "baekmukdotum",         aBaekmukDotum },
245 {   "baekmukgulim",         aBaekmukGulim },
246 {   "baekmukbatang",        aBaekmukBatang },
247 {   "fzheiti",              aFzHeiTiCN },
248 {   "fzheiti",              aFzHeiTiTW },
249 {   "fzkaiti",              aFzKaiTiCN },
250 {   "fzkaitib",             aFzKaiTiTW },
251 {   "fzmingtib",            aFzMingTi },
252 {   "fzsongti",             aFzSongTi },
253 {   "hymyeongjoextra",      aHYMyeongJoExtra },
254 {   "hysinmyeongjomedium",  aHYSinMyeongJoMedium },
255 {   "hygothicmedium",       aHYGothicMedium },
256 {   "hygraphicmedium",      aHYGraphicMedium },
257 {   "hygraphic",            aHYGraphic },
258 {   "newgulim",             aNewGulim },
259 {   "sungungseo",           aSunGungseo },
260 {   "hygungsobold",         aHYGungSoBold },
261 {   "hygungso",             aHYGungSo },
262 {   "sunheadline",          aSunHeadLine },
263 {   "hyheadlinemedium",     aHYHeadLineMedium },
264 {   "hyheadline",           aHYHeadLine },
265 {   "yetr",                 aYetR },
266 {   "hygothicextra",        aHYGothicExtra },
267 {   "sunmokpan",            aSunMokPan },
268 {   "sunyeopseo",           aSunYeopseo },
269 {   "sunbaeksong",          aSunBaekSong },
270 {   "hypostlight",          aHYPostLight },
271 {   "hypost",               aHYPost },
272 {   "magicr",               aMagicR },
273 {   "suncrystal",           aSunCrystal },
274 {   "sunsaemmul",           aSunSaemmul },
275 {   "hyshortsamulmedium",   aHYShortSamulMedium },
276 {   "hyshortsamul",         aHYShortSamul },
277 {   "haansoftbatang",       aHaansoftBatang },
278 {   "haansoftdotum",        aHaansoftDotum },
279 {   "hyhaeseo",             aHyhaeseo },
280 {   "mdsol",                aMDSol },
281 {   "mdgaesung",            aMDGaesung },
282 {   "mdart",                aMDArt },
283 {   "mdalong",              aMDAlong },
284 {   "mdeasop",              aMDEasop },
285 {   "hggothice",            aHGGothicE },
286 {   "hgpgothice",           aHGPGothicE },
287 {   "hgsgothice",           aHGSGothicE },
288 {   "hggothicm",            aHGGothicM },
289 {   "hgpgothicm",           aHGPGothicM },
290 {   "hgsgothicm",           aHGSGothicM },
291 {   "hggyoshotai",          aHGGyoshotai },
292 {   "hgpgyoshotai",         aHGPGyoshotai },
293 {   "hgsgyoshotai",         aHGSGyoshotai },
294 {   "hgkyokashotai",        aHGKyokashotai },
295 {   "hgpkyokashotai",       aHGPKyokashotai },
296 {   "hgskyokashotai",       aHGSKyokashotai },
297 {   "hgminchob",            aHGMinchoB },
298 {   "hgpminchob",           aHGPMinchoB },
299 {   "hgsminchob",           aHGSMinchoB },
300 {   "hgminchoe",            aHGMinchoE },
301 {   "hgpminchoe",           aHGPMinchoE },
302 {   "hgsminchoe",           aHGSMinchoE },
303 {   "hgsoeikakupoptai",     aHGSoeiKakupoptai },
304 {   "hgpsoeikakupopta",     aHGPSoeiKakupoptai },
305 {   "hgssoeikakupopta",     aHGSSoeiKakupoptai },
306 {   "hgsoeipresenceeb",     aHGSoeiPresenceEB },
307 {   "hgpsoeipresenceeb",    aHGPSoeiPresenceEB },
308 {   "hgssoeipresenceeb",    aHGSSoeiPresenceEB },
309 {   "hgsoeikakugothicub",   aHGSoeiKakugothicUB },
310 {   "hgpsoeikakugothicub",  aHGPSoeiKakugothicUB },
311 {   "hgssoeikakugothicub",  aHGSSoeiKakugothicUB },
312 {   "hgseikaishotaipro",    aHGSeikaishotaiPRO },
313 {   "hgmarugothicmpro",     aHGMaruGothicMPRO },
314 {   "hiraginominchopro",    aHiraginoMinchoPro },
315 {   "hiraginominchopron",   aHiraginoMinchoProN },
316 {   "hiraginokakugothicpro", aHiraginoKakuGothicPro },
317 {   "hiraginokakugothicpron", aHiraginoKakuGothicProN },
318 {   "hiraginomarugothicpro", aHiraginoMaruGothicPro },
319 {   "hiraginomarugothicpron", aHiraginoMaruGothicProN },
320 {   nullptr,                   nullptr },
321 };
322 
StripScriptFromName(const OUString & _aName)323 OUString StripScriptFromName(const OUString& _aName)
324 {
325     // I worry that someone will have a font which *does* have
326     // e.g. "Greek" legitimately at the end of its name :-(
327     const char*const suffixes[] = { " baltic",
328                               " ce",
329                               " cyr",
330                               " greek",
331                               " tur",
332                               " (arabic)",
333                               " (hebrew)",
334                               " (thai)",
335                               " (vietnamese)"
336                             };
337 
338     OUString aName = _aName;
339     // These can be crazily piled up, e.g. Times New Roman CYR Greek
340     bool bFinished = false;
341     while (!bFinished)
342     {
343         bFinished = true;
344         for (const char* suffix : suffixes)
345         {
346             size_t nLen = strlen(suffix);
347             if (aName.endsWithIgnoreAsciiCaseAsciiL(suffix, nLen))
348             {
349                 bFinished = false;
350                 aName = aName.copy(0, aName.getLength() - nLen);
351             }
352         }
353     }
354     return aName;
355 }
356 
GetEnglishSearchFontName(const OUString & rInName)357 OUString GetEnglishSearchFontName(const OUString& rInName)
358 {
359     OUStringBuffer rName(rInName);
360     bool        bNeedTranslation = false;
361     sal_Int32  nLen = rName.getLength();
362 
363     // Remove trailing whitespaces
364     sal_Int32 i = nLen;
365     while ( i && (rName[ i-1 ] < 32) )
366         i--;
367     if ( i != nLen )
368          rName.truncate(i);
369 
370     nLen = rName.getLength();
371 
372     // remove all whitespaces and converts to lower case ASCII
373     // TODO: better transliteration to ASCII e.g. all digits
374     i = 0;
375     while ( i < nLen )
376     {
377         sal_Unicode c = rName[ i ];
378         if ( c > 127 )
379         {
380             // Translate to Lowercase-ASCII
381             // FullWidth-ASCII to half ASCII
382             if ( (c >= 0xFF00) && (c <= 0xFF5E) )
383             {
384                 c -= 0xFF00-0x0020;
385                 // Upper to Lower
386                 if ( (c >= 'A') && (c <= 'Z') )
387                     c += 'a' - 'A';
388 
389                 rName[ i ] = c;
390 
391            }
392             else
393             {
394                 // Only Fontnames with None-Ascii-Characters must be translated
395                 bNeedTranslation = true;
396             }
397         }
398         // not lowercase Ascii
399         else if ( !((c >= 'a') && (c <= 'z')) )
400         {
401             // To Lowercase-Ascii
402             if ( (c >= 'A') && (c <= 'Z') )
403             {
404                 c += 'a' - 'A';
405                 rName[ i ] = c;
406             }
407             else if( ((c < '0') || (c > '9')) && (c != ';') && (c != '(') && (c != ')') ) // not 0-9, semicolon, or brackets
408             {
409                 // Remove white spaces and special characters
410                 rName.remove(i,1);
411                 nLen--;
412                 continue;
413             }
414         }
415 
416         i++;
417     }
418     OUString rNameStr = rName.makeStringAndClear();
419     // translate normalized localized name to its normalized English ASCII name
420     if( bNeedTranslation )
421     {
422         typedef std::unordered_map<OUString, const char*> FontNameDictionary;
423         static FontNameDictionary aDictionary( SAL_N_ELEMENTS(aImplLocalizedNamesList) );
424         // the font name dictionary needs to be initialized once
425         if( aDictionary.empty() )
426         {
427             // TODO: check if all dictionary entries are already normalized?
428             const ImplLocalizedFontName* pList = aImplLocalizedNamesList;
429             for(; pList->mpEnglishName; ++pList )
430                 aDictionary[ pList->mpLocalizedNames ] = pList->mpEnglishName;
431         }
432 
433         FontNameDictionary::const_iterator it = aDictionary.find( rNameStr );
434         if( it != aDictionary.end() )
435             rNameStr = OUString::createFromAscii ( it->second );
436     }
437 
438     return rNameStr;
439 }
440 
GetNextFontToken(const OUString & rTokenStr,sal_Int32 & rIndex)441 OUString GetNextFontToken( const OUString& rTokenStr, sal_Int32& rIndex )
442 {
443     // check for valid start index
444     sal_Int32 nStringLen = rTokenStr.getLength();
445     if( rIndex >= nStringLen )
446     {
447         rIndex = -1;
448         return OUString();
449     }
450 
451     // find the next token delimiter and return the token substring
452     const sal_Unicode* pStr = rTokenStr.getStr() + rIndex;
453     const sal_Unicode* pEnd = rTokenStr.getStr() + nStringLen;
454     for(; pStr < pEnd; ++pStr )
455         if( (*pStr == ';') || (*pStr == ',') )
456             break;
457 
458     sal_Int32 nTokenStart = rIndex;
459     sal_Int32 nTokenLen;
460     if( pStr < pEnd )
461     {
462         rIndex = sal::static_int_cast<sal_Int32>(pStr - rTokenStr.getStr());
463         nTokenLen = rIndex - nTokenStart;
464         ++rIndex; // skip over token separator
465     }
466     else
467     {
468         // no token delimiter found => handle last token
469         rIndex = -1;
470 
471         // optimize if the token string consists of just one token
472         if( !nTokenStart )
473         {
474             return rTokenStr;
475         }
476         else
477         {
478             nTokenLen = nStringLen - nTokenStart;
479         }
480     }
481 
482     return rTokenStr.copy( nTokenStart, nTokenLen );
483 }
484 
ImplIsFontToken(const OUString & rName,const OUString & rToken)485 static bool ImplIsFontToken( const OUString& rName, const OUString& rToken )
486 {
487     OUString      aTempName;
488     sal_Int32  nIndex = 0;
489     do
490     {
491         aTempName = GetNextFontToken( rName, nIndex );
492         if ( rToken == aTempName )
493             return true;
494     }
495     while ( nIndex != -1 );
496 
497     return false;
498 }
499 
ImplAppendFontToken(OUString & rName,const OUString & rNewToken)500 static void ImplAppendFontToken( OUString& rName, const OUString& rNewToken )
501 {
502     if ( !rName.isEmpty() )
503     {
504         rName += ";";
505     }
506     rName += rNewToken;
507 }
508 
AddTokenFontName(OUString & rName,const OUString & rNewToken)509 void AddTokenFontName( OUString& rName, const OUString& rNewToken )
510 {
511     if ( !ImplIsFontToken( rName, rNewToken ) )
512         ImplAppendFontToken( rName, rNewToken );
513 }
514 
GetSubsFontName(const OUString & rName,SubsFontFlags nFlags)515 OUString GetSubsFontName( const OUString& rName, SubsFontFlags nFlags )
516 {
517     OUString aName;
518 
519     sal_Int32 nIndex = 0;
520     OUString aOrgName = GetEnglishSearchFontName(
521                                 GetNextFontToken( rName, nIndex ) );
522 
523     // #93662# do not try to replace StarSymbol with MS only font
524     if( nFlags == (SubsFontFlags::MS|SubsFontFlags::ONLYONE)
525     &&  ( aOrgName == "starsymbol"
526       ||  aOrgName == "opensymbol" ) )
527         return aName;
528 
529     const utl::FontNameAttr* pAttr = utl::FontSubstConfiguration::get().getSubstInfo( aOrgName );
530     if ( pAttr && (nFlags & SubsFontFlags::MS) )
531     {
532         for( const auto& rSubstitution : pAttr->MSSubstitutions )
533             if( ! ImplIsFontToken( rName, rSubstitution ) )
534             {
535                 ImplAppendFontToken( aName, rSubstitution );
536                 if( nFlags & SubsFontFlags::ONLYONE )
537                 {
538                     break;
539                 }
540             }
541     }
542 
543     return aName;
544 }
545 
IsStarSymbol(const OUString & rFontName)546 bool IsStarSymbol(const OUString &rFontName)
547 {
548     sal_Int32 nIndex = 0;
549     OUString sFamilyNm(GetNextFontToken(rFontName, nIndex));
550     return (sFamilyNm.equalsIgnoreAsciiCase("starsymbol") ||
551         sFamilyNm.equalsIgnoreAsciiCase("opensymbol"));
552 }
553 
554 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
555