Line data Source code
1 : /** 2 : Copyright (c) 2023-2024 Stappler LLC <admin@stappler.dev> 3 : 4 : Permission is hereby granted, free of charge, to any person obtaining a copy 5 : of this software and associated documentation files (the "Software"), to deal 6 : in the Software without restriction, including without limitation the rights 7 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 : copies of the Software, and to permit persons to whom the Software is 9 : furnished to do so, subject to the following conditions: 10 : 11 : The above copyright notice and this permission notice shall be included in 12 : all copies or substantial portions of the Software. 13 : 14 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 : THE SOFTWARE. 21 : **/ 22 : 23 : #include "SPFontStyle.h" 24 : #include "SPMemory.h" 25 : 26 : namespace STAPPLER_VERSIONIZED stappler::font { 27 : 28 : #ifdef __LCC__ 29 : 30 : constexpr FontStretch FontStretch::UltraCondensed = FontStretch(50 << 1); 31 : constexpr FontStretch FontStretch::ExtraCondensed = FontStretch((62 << 1) | 1); 32 : constexpr FontStretch FontStretch::Condensed = FontStretch(75 << 1); 33 : constexpr FontStretch FontStretch::SemiCondensed = FontStretch((87 << 1) | 1); 34 : constexpr FontStretch FontStretch::Normal = FontStretch(100 << 1); 35 : constexpr FontStretch FontStretch::SemiExpanded = FontStretch((112 << 1) | 1); 36 : constexpr FontStretch FontStretch::Expanded = FontStretch(125 << 1); 37 : constexpr FontStretch FontStretch::ExtraExpanded = FontStretch(150 << 1); 38 : constexpr FontStretch FontStretch::UltraExpanded = FontStretch(200 << 1); 39 : 40 : constexpr FontWeight FontWeight::Thin = FontWeight(100); 41 : constexpr FontWeight FontWeight::ExtraLight = FontWeight(200); 42 : constexpr FontWeight FontWeight::Light = FontWeight(300); 43 : constexpr FontWeight FontWeight::Normal = FontWeight(400); 44 : constexpr FontWeight FontWeight::Regular = FontWeight(400); 45 : constexpr FontWeight FontWeight::Medium = FontWeight(500); 46 : constexpr FontWeight FontWeight::SemiBold = FontWeight(600); 47 : constexpr FontWeight FontWeight::Bold = FontWeight(700); 48 : constexpr FontWeight FontWeight::ExtraBold = FontWeight(800); 49 : constexpr FontWeight FontWeight::Heavy = FontWeight(900); 50 : constexpr FontWeight FontWeight::Black = FontWeight(1000); 51 : 52 : constexpr FontSize FontSize::XXSmall = FontSize(uint16_t(8)); 53 : constexpr FontSize FontSize::XSmall = FontSize(uint16_t(10)); 54 : constexpr FontSize FontSize::Small = FontSize(uint16_t(12)); 55 : constexpr FontSize FontSize::Medium = FontSize(uint16_t(14)); 56 : constexpr FontSize FontSize::Large = FontSize(uint16_t(16)); 57 : constexpr FontSize FontSize::XLarge = FontSize(uint16_t(20)); 58 : constexpr FontSize FontSize::XXLarge = FontSize(uint16_t(24)); 59 : 60 : constexpr FontStyle FontStyle::Normal = FontStyle(0); 61 : constexpr FontStyle FontStyle::Italic = FontStyle(minOf<int16_t>()); 62 : constexpr FontStyle FontStyle::Oblique = FontStyle(-10 << 6); 63 : 64 : constexpr FontGrade FontGrade::Thin = FontGrade(-200); 65 : constexpr FontGrade FontGrade::Reduced = FontGrade(-50); 66 : constexpr FontGrade FontGrade::Normal = FontGrade(0); 67 : constexpr FontGrade FontGrade::Heavy = FontGrade(150); 68 : 69 : #endif 70 : 71 2245 : static void s_getSpecializationArgs(std::ostream &out, const FontSpecializationVector &vec) { 72 2245 : out << "?size=" << vec.fontSize.get(); 73 2245 : out << "&weight=" << vec.fontWeight.get(); 74 2245 : out << "&width=" << vec.fontStretch.get(); 75 2245 : switch (vec.fontStyle.get()) { 76 697 : case FontStyle::Normal.get(): out << "&style=normal"; break; 77 0 : case FontStyle::Italic.get(): out << "&style=italic"; break; 78 1548 : default: out << "&style=" << vec.fontStyle.get(); break; 79 : } 80 2245 : out << "&density=" << vec.density; 81 2245 : if (vec.fontGrade != FontGrade::Normal) { 82 1586 : out << "&grade=" << vec.fontGrade.get(); 83 : } 84 2245 : } 85 : 86 : template <> 87 0 : auto FontSpecializationVector::getSpecializationArgs<memory::PoolInterface>() const -> memory::PoolInterface::StringType { 88 0 : memory::PoolInterface::StringStreamType out; 89 0 : s_getSpecializationArgs(out, *this); 90 0 : return out.str(); 91 0 : } 92 : 93 : template <> 94 2245 : auto FontSpecializationVector::getSpecializationArgs<memory::StandartInterface>() const -> memory::StandartInterface::StringType { 95 2245 : memory::StandartInterface::StringStreamType out; 96 2245 : s_getSpecializationArgs(out, *this); 97 4490 : return out.str(); 98 2245 : } 99 : 100 0 : FontParameters FontParameters::create(StringView str, memory::pool_t *pool) { 101 0 : FontParameters ret; 102 : 103 : enum State { 104 : Family, 105 : Size, 106 : Style, 107 : Weight, 108 : Stretch, 109 : Overflow, 110 0 : } state = Family; 111 : 112 0 : str.split<StringView::Chars<'.'>>([&] (const StringView &ir) { 113 0 : StringView r(ir); 114 0 : switch (state) { 115 0 : case Family: 116 0 : ret.fontFamily = r.pdup(pool); 117 0 : state = Size; 118 0 : break; 119 0 : case Size: 120 0 : if (r.is("xxs")) { ret.fontSize = FontSize::XXSmall; } 121 0 : else if (r.is("xs")) { ret.fontSize = FontSize::XSmall; } 122 0 : else if (r.is("s")) { ret.fontSize = FontSize::Small; } 123 0 : else if (r.is("m")) { ret.fontSize = FontSize::Medium; } 124 0 : else if (r.is("l")) {ret.fontSize = FontSize::Large; } 125 0 : else if (r.is("xl")) { ret.fontSize = FontSize::XLarge; } 126 0 : else if (r.is("xxl")) { ret.fontSize = FontSize::XXLarge; } 127 0 : else { r.readInteger().unwrap([&] (int64_t value) { ret.fontSize = FontSize(value); }); } 128 0 : state = Style; 129 0 : break; 130 0 : case Style: 131 0 : if (r.is("i")) { ret.fontStyle = FontStyle::Italic; } 132 0 : else if (r.is("o")) { ret.fontStyle = FontStyle::Oblique; } 133 0 : else if (r.is("n")) { ret.fontStyle = FontStyle::Normal; } 134 0 : state = Weight; 135 0 : break; 136 0 : case Weight: 137 0 : ret.fontWeight = FontWeight(r.readInteger(10).get(400)); 138 0 : state = Stretch; 139 0 : break; 140 0 : case Stretch: 141 0 : ret.fontStretch = FontStretch(r.readInteger(10).get(100 << 1)); 142 0 : state = Overflow; 143 0 : break; 144 0 : default: break; 145 : } 146 0 : }); 147 0 : return ret; 148 : } 149 : 150 : template <> 151 0 : auto FontParameters::getFontConfigName<memory::PoolInterface>(StringView fontFamily, FontSize fontSize, FontStyle fontStyle, FontWeight fontWeight, 152 : FontStretch fontStretch, FontGrade fontGrade, FontVariant fontVariant, bool caps) -> memory::PoolInterface::StringType { 153 0 : auto size = fontSize; 154 0 : memory::PoolInterface::StringType name; 155 0 : name.reserve(fontFamily.size() + 14); 156 0 : name += fontFamily.str<memory::PoolInterface>(); 157 : 158 0 : if (caps && fontVariant == FontVariant::SmallCaps) { 159 0 : size -= size / 5.0f; 160 : } 161 : 162 0 : name += "." + mem_pool::toString(size.get()); 163 : 164 0 : switch (fontStyle.get()) { 165 0 : case FontStyle::Normal.get(): name += ".n"; break; 166 0 : case FontStyle::Italic.get(): name += ".i"; break; 167 0 : default: name += "."; name += mem_pool::toString(fontStyle.get()); break; 168 : } 169 : 170 0 : name += mem_pool::toString(".", fontWeight.get()); 171 0 : name += mem_pool::toString(".", fontStretch.get()); 172 0 : name += mem_pool::toString(".", fontGrade.get()); 173 0 : return name; 174 0 : } 175 : 176 : template <> 177 23155 : auto FontParameters::getFontConfigName<memory::StandartInterface>(StringView fontFamily, FontSize fontSize, FontStyle fontStyle, FontWeight fontWeight, 178 : FontStretch fontStretch, FontGrade fontGrade, FontVariant fontVariant, bool caps) -> memory::StandartInterface::StringType { 179 23155 : auto size = fontSize; 180 23155 : memory::StandartInterface::StringType name; 181 23155 : name.reserve(fontFamily.size() + 14); 182 23155 : name += fontFamily.str<memory::StandartInterface>(); 183 : 184 23155 : if (caps && fontVariant == FontVariant::SmallCaps) { 185 0 : size -= size / 5.0f; 186 : } 187 : 188 23155 : name += "." + mem_std::toString(size.get()); 189 : 190 23155 : switch (fontStyle.get()) { 191 20833 : case FontStyle::Normal.get(): name += ".n"; break; 192 0 : case FontStyle::Italic.get(): name += ".i"; break; 193 2322 : default: name += "."; name += mem_std::toString(fontStyle.get()); break; 194 : } 195 : 196 23155 : name += mem_std::toString(".", fontWeight.get()); 197 23155 : name += mem_std::toString(".", fontStretch.get()); 198 23155 : name += mem_std::toString(".", fontGrade.get()); 199 46310 : return name; 200 0 : } 201 : 202 0 : FontParameters FontParameters::getSmallCaps() const { 203 0 : FontParameters ret = *this; 204 0 : ret.fontSize -= ret.fontSize / 5.0f; 205 0 : return ret; 206 : } 207 : 208 5724 : FontSpecializationVector FontVariations::getSpecialization(const FontSpecializationVector &vec) const { 209 5724 : FontSpecializationVector ret = vec; 210 5724 : if ((axisMask & FontVariableAxis::Weight) != FontVariableAxis::None) { 211 2912 : ret.fontWeight = weight.clamp(vec.fontWeight); 212 : } else { 213 2812 : ret.fontWeight = weight.min; 214 : } 215 5724 : if ((axisMask & FontVariableAxis::Stretch) != FontVariableAxis::None) { 216 2812 : ret.fontStretch = stretch.clamp(vec.fontStretch); 217 : } else { 218 2912 : ret.fontStretch = stretch.min; 219 : } 220 5724 : if ((axisMask & FontVariableAxis::Grade) != FontVariableAxis::None) { 221 2812 : ret.fontGrade = grade.clamp(vec.fontGrade); 222 : } else { 223 2912 : ret.fontGrade = grade.min; 224 : } 225 : 226 5724 : switch (vec.fontStyle.get()) { 227 2628 : case FontStyle::Normal.get(): 228 : // we should have 0 on italic and slant 229 2628 : if (italic.min == 0 && slant.min <= FontStyle::Normal && slant.max >= FontStyle::Normal) { 230 2578 : ret.fontStyle = FontStyle::Normal; 231 : } else { 232 50 : if (italic.min > 0) { 233 50 : ret.fontStyle = FontStyle::Italic; 234 : } else { 235 0 : ret.fontStyle = slant.clamp(FontStyle::Normal); 236 : } 237 : } 238 2628 : break; 239 0 : case FontStyle::Italic.get(): 240 : // try true italic or slant emulation 241 0 : if (italic.min > 0) { 242 0 : ret.fontStyle = FontStyle::Italic; 243 : } else { 244 0 : ret.fontStyle = slant.clamp(FontStyle::Oblique); 245 : } 246 0 : break; 247 3096 : default: 248 3096 : if ((axisMask & FontVariableAxis::Slant) != FontVariableAxis::None) { 249 1548 : ret.fontStyle = slant.clamp(vec.fontStyle); 250 1548 : } else if ((axisMask & FontVariableAxis::Italic) != FontVariableAxis::None && italic.min != italic.max) { 251 0 : ret.fontStyle = FontStyle::Italic; 252 : } else { 253 1548 : if (italic.min == 1) { 254 0 : ret.fontStyle = FontStyle::Italic; 255 : } else { 256 1548 : ret.fontStyle = slant.min; 257 : } 258 : } 259 3096 : break; 260 : } 261 : 262 5724 : return ret; 263 : } 264 : 265 : }