core/info.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Avisynth+ | ||
| 2 | // https://avs-plus.net | ||
| 3 | // | ||
| 4 | // This program is free software; you can redistribute it and/or modify | ||
| 5 | // it under the terms of the GNU General Public License as published by | ||
| 6 | // the Free Software Foundation; either version 2 of the License, or | ||
| 7 | // (at your option) any later version. | ||
| 8 | // | ||
| 9 | // This program is distributed in the hope that it will be useful, | ||
| 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | // GNU General Public License for more details. | ||
| 13 | // | ||
| 14 | // You should have received a copy of the GNU General Public License | ||
| 15 | // along with this program; if not, write to the Free Software | ||
| 16 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit | ||
| 17 | // http://www.gnu.org/copyleft/gpl.html . | ||
| 18 | // | ||
| 19 | // Linking Avisynth statically or dynamically with other modules is making a | ||
| 20 | // combined work based on Avisynth. Thus, the terms and conditions of the GNU | ||
| 21 | // General Public License cover the whole combination. | ||
| 22 | // | ||
| 23 | // As a special exception, the copyright holders of Avisynth give you | ||
| 24 | // permission to link Avisynth with independent modules that communicate with | ||
| 25 | // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license | ||
| 26 | // terms of these independent modules, and to copy and distribute the | ||
| 27 | // resulting combined work under terms of your choice, provided that | ||
| 28 | // every copy of the combined work is accompanied by a complete copy of | ||
| 29 | // the source code of Avisynth (the version of Avisynth used to produce the | ||
| 30 | // combined work), being distributed under the terms of the GNU General | ||
| 31 | // Public License plus this exception. An independent module is a module | ||
| 32 | // which is not derived from or based on Avisynth, such as 3rd-party filters, | ||
| 33 | // import and export plugins, or graphical user interfaces. | ||
| 34 | |||
| 35 | // pinterf: | ||
| 36 | // high bit depth, planar RGB | ||
| 37 | // utf8 option, internally unicode | ||
| 38 | // info_h font definition reorganized, Latin-1 Supplement 00A0-00FF | ||
| 39 | // Configurable color | ||
| 40 | // Configurable halocolor (text outline) | ||
| 41 | // Configurable background fading | ||
| 42 | // Alignment | ||
| 43 | // multiline | ||
| 44 | // multiple size, multiple fonts, "Terminus", "info_h" | ||
| 45 | // chroma location, overlay-like weighted chroma handling | ||
| 46 | |||
| 47 | #include "info.h" | ||
| 48 | #include <cstring> | ||
| 49 | #include <sstream> | ||
| 50 | #include <fstream> | ||
| 51 | #include <unordered_map> | ||
| 52 | #include <array> | ||
| 53 | #include <iomanip> | ||
| 54 | #include <avs/filesystem.h> | ||
| 55 | |||
| 56 | #include <locale> | ||
| 57 | #include <cstdio> | ||
| 58 | #include <cassert> | ||
| 59 | #include "fonts/fixedfonts.h" | ||
| 60 | #include "strings.h" | ||
| 61 | #include "../convert/convert_helper.h" | ||
| 62 | |||
| 63 | // helper function for remapping an utf8 string to font index entry list | ||
| 64 | 7 | std::vector<int> BitmapFont::remap(const std::string& s_utf8) | |
| 65 | { | ||
| 66 | // new vector with characters remapped to font table indexes | ||
| 67 | 7 | std::vector<int> s_remapped; | |
| 68 |
1/2✓ Branch 3 → 4 taken 7 times.
✗ Branch 3 → 43 not taken.
|
7 | const size_t real_len = str_utf8_size(s_utf8); |
| 69 |
1/2✓ Branch 4 → 5 taken 7 times.
✗ Branch 4 → 43 not taken.
|
7 | s_remapped.resize(real_len); |
| 70 | |||
| 71 | 7 | size_t index = 0; | |
| 72 | 7 | const char* p = s_utf8.data(); | |
| 73 | 7 | const char* end = p + s_utf8.size(); | |
| 74 |
2/2✓ Branch 33 → 8 taken 369 times.
✓ Branch 33 → 34 taken 7 times.
|
376 | while (p < end) { |
| 75 | // Get the lead byte of the current UTF-8 character | ||
| 76 | 369 | unsigned char lb = static_cast<unsigned char>(*p); | |
| 77 | // Determine the number of bytes in the current UTF-8 character | ||
| 78 | 369 | int n = 0; | |
| 79 |
1/2✓ Branch 8 → 9 taken 369 times.
✗ Branch 8 → 10 not taken.
|
369 | if ((lb & 0x80) == 0) n = 1; // 0xxxxxxx |
| 80 | ✗ | else if ((lb & 0xE0) == 0xC0) n = 2; // 110xxxxx | |
| 81 | ✗ | else if ((lb & 0xF0) == 0xE0) n = 3; // 1110xxxx | |
| 82 | ✗ | else if ((lb & 0xF8) == 0xF0) n = 4; // 11110xxx | |
| 83 | else { | ||
| 84 | // Invalid lead byte, skip | ||
| 85 | ✗ | ++p; | |
| 86 | ✗ | continue; | |
| 87 | } | ||
| 88 | // Create a buffer to store the UTF-8 character code | ||
| 89 | 369 | char utf8_char_buf[5] = { 0 }; | |
| 90 | // Copy the bytes from the string to the buffer | ||
| 91 | 369 | std::memcpy(utf8_char_buf, p, n); | |
| 92 | // finds by utf8 character sequence in font index table | ||
| 93 |
2/4✓ Branch 19 → 20 taken 369 times.
✗ Branch 19 → 38 not taken.
✓ Branch 20 → 21 taken 369 times.
✗ Branch 20 → 36 not taken.
|
738 | auto it = charReMapUtf8.find(utf8_char_buf); |
| 94 |
1/2✓ Branch 25 → 26 taken 369 times.
✗ Branch 25 → 29 not taken.
|
369 | if (it != charReMapUtf8.end()) |
| 95 | 369 | s_remapped[index] = it->second; | |
| 96 | else | ||
| 97 | ✗ | s_remapped[index] = 0; // empty neutral character (space) | |
| 98 | 369 | index++; | |
| 99 | // Advance the pointer by the number of bytes | ||
| 100 | 369 | p += n; | |
| 101 | } | ||
| 102 | 7 | return s_remapped; | |
| 103 | ✗ | } | |
| 104 | |||
| 105 | // Internal function! For creating source code from a previously LoadBDF'd font file | ||
| 106 | // see fixedfonts.cpp | ||
| 107 | ✗ | void BitmapFont::SaveAsC(const uint16_t* _codepoints) | |
| 108 | { | ||
| 109 | ✗ | if (font_filename == "") return; // no GUS no sound :) | |
| 110 | |||
| 111 | ✗ | std::string fontname; | |
| 112 | ✗ | if (font_filename.substr(0, 4) == "ter-") | |
| 113 | ✗ | font_name = "Terminus"; | |
| 114 | else | ||
| 115 | ✗ | font_name = font_filename; | |
| 116 | |||
| 117 | ✗ | std::ostringstream ss; | |
| 118 | ✗ | ss << "namespace fixed_font_# {" << std::endl; | |
| 119 | ✗ | ss << "// -- start of autogenerated text ---" << std::endl; | |
| 120 | ✗ | ss << "// definition section for font: " << font_filename << std::endl; | |
| 121 | ✗ | ss << "constexpr int CHARCOUNT = " << std::to_string(number_of_chars) << ";" << std::endl; | |
| 122 | ✗ | ss << "constexpr int WIDTH = " << std::to_string(global_bbx.width) << ";" << std::endl; | |
| 123 | ✗ | ss << "constexpr int HEIGHT = " << std::to_string(global_bbx.height) << ";" << std::endl; | |
| 124 | ✗ | ss << "constexpr int OFFSET_X = " << std::to_string(global_bbx.offset_x) << ";" << std::endl; | |
| 125 | ✗ | ss << "constexpr int OFFSET_Y = " << std::to_string(global_bbx.offset_y) << ";" << std::endl; | |
| 126 | ✗ | ss << "constexpr FixedFont_info_t fixedfont_info = {" << std::endl; | |
| 127 | ✗ | ss << " \"" << font_filename << "\", // font name" << std::endl; | |
| 128 | ✗ | ss << " \"" << font_filename << "\", // font name internal" << std::endl; | |
| 129 | ✗ | ss << " CHARCOUNT, // num of chars" << std::endl; | |
| 130 | ✗ | ss << " WIDTH, HEIGHT, OFFSET_X, OFFSET_Y," << std::endl; | |
| 131 | ✗ | ss << " " << (bold ? "true" : "false") << " // bold" << std::endl; | |
| 132 | ✗ | ss << "};" << std::endl; | |
| 133 | ✗ | ss << "// font bitmap definitions" << std::endl; | |
| 134 | ✗ | ss << "constexpr std::array<uint16_t, CHARCOUNT * HEIGHT> fixedfont_bitmap = {" << std::endl; | |
| 135 | ✗ | for (int charcount = 0; charcount < number_of_chars; charcount++) | |
| 136 | { | ||
| 137 | ✗ | constexpr int LINES_BY_N = 16; // maximum number of constants per line | |
| 138 | ✗ | for (int y = 0; y < global_bbx.height; y++) { | |
| 139 | ✗ | ss << "0x"; | |
| 140 | ✗ | for (int x = 0; x < fontline_bytes; x++) { | |
| 141 | ✗ | uint8_t charline = font_bitmaps[(charcount * global_bbx.height + y) * fontline_bytes + x]; | |
| 142 | ✗ | ss << std::setfill('0') << std::setw(2) << std::hex << charline; | |
| 143 | } | ||
| 144 | ✗ | const bool last = charcount == number_of_chars - 1 && y == global_bbx.height - 1; | |
| 145 | ✗ | if (!last) ss << ","; | |
| 146 | ✗ | if (y == global_bbx.height - 1) | |
| 147 | ✗ | ss << " // u" << std::setw(4) << std::hex << _codepoints[charcount]; | |
| 148 | ✗ | if (y % LINES_BY_N == LINES_BY_N - 1) ss << std::endl; // last line of character- forced new line | |
| 149 | } | ||
| 150 | ✗ | if (global_bbx.height % LINES_BY_N != 0) | |
| 151 | ✗ | ss << std::endl; | |
| 152 | }; | ||
| 153 | // example output: | ||
| 154 | // 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, | ||
| 155 | // 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // u0020 | ||
| 156 | // 0x0000,0x0000,0x0000,0x0000,0x0300,0x0300,0x0300,0x0300,0x0300,0x0300,0x0300,0x0300,0x0300,0x0300,0x0300,0x0300, | ||
| 157 | // 0x0000,0x0000,0x0300,0x0300,0x0300,0x0300,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // u0021 | ||
| 158 | |||
| 159 | ✗ | ss << "};" << std::endl; | |
| 160 | ✗ | ss << "// codepoints array" << std::endl; | |
| 161 | ✗ | ss << "constexpr std::array<uint16_t, CHARCOUNT> fixedfont_codepoints = {" << std::endl; | |
| 162 | ✗ | for (int charcount = 0; charcount < number_of_chars; charcount++) | |
| 163 | { | ||
| 164 | ✗ | constexpr int LINES_BY_N = 16; | |
| 165 | ✗ | int val = _codepoints[charcount]; | |
| 166 | ✗ | ss << "0x" << std::setfill('0') << std::setw(4) << std::hex << val; | |
| 167 | ✗ | const bool last = charcount == number_of_chars - 1; | |
| 168 | ✗ | if (!last) ss << ","; | |
| 169 | ✗ | if (charcount % LINES_BY_N == LINES_BY_N - 1) ss << std::endl; | |
| 170 | } | ||
| 171 | ✗ | ss << "};" << std::endl; | |
| 172 | |||
| 173 | ✗ | ss << "} // namespace" << std::endl; | |
| 174 | ✗ | ss << "// -- end of autogenerated text ---" << std::endl; | |
| 175 | // | ||
| 176 | ✗ | std::ofstream outFile(font_filename + ".cpp_sample"); | |
| 177 | ✗ | outFile << ss.str(); | |
| 178 | ✗ | outFile.close(); | |
| 179 | |||
| 180 | /* usage: | ||
| 181 | // Predefined fonts main table | ||
| 182 | constexpr int PREDEFINED_FONT_COUNT = 2; | ||
| 183 | static const uint16_t* font_bitmaps[PREDEFINED_FONT_COUNT] = | ||
| 184 | { | ||
| 185 | &fixed_font_1::fixedfont_bitmap[0], | ||
| 186 | &fixed_font_2::fixedfont_bitmap[0] | ||
| 187 | // ... | ||
| 188 | }; | ||
| 189 | static const uint16_t* font_codepoints[PREDEFINED_FONT_COUNT] = | ||
| 190 | { | ||
| 191 | &fixed_font_1::fixedfont_codepoints[0], | ||
| 192 | &fixed_font_2::fixedfont_codepoints[0] | ||
| 193 | // ... | ||
| 194 | }; | ||
| 195 | static const FixedFont_info_t* font_infos[PREDEFINED_FONT_COUNT] = | ||
| 196 | { | ||
| 197 | &fixed_font_1::fixedfont_info, | ||
| 198 | &fixed_font_2::fixedfont_info | ||
| 199 | // ... | ||
| 200 | }; | ||
| 201 | */ | ||
| 202 | ✗ | } | |
| 203 | |||
| 204 | typedef struct CharInfo { // STARTCHAR charname | ||
| 205 | std::string friendly_name; | ||
| 206 | uint16_t encoding; | ||
| 207 | int dwidth_x, dwidth_y; | ||
| 208 | // DWIDTH not supported, same as main PIXELSIZE | ||
| 209 | // font properties can be overridden. | ||
| 210 | BBX bbx; | ||
| 211 | int empty_lines_bottom; | ||
| 212 | int empty_lines_top; | ||
| 213 | int bits_to_shift; | ||
| 214 | } CharDef; | ||
| 215 | |||
| 216 | typedef struct FontProperties { | ||
| 217 | std::string Copyright; | ||
| 218 | std::string Notice; | ||
| 219 | std::string Family_name; | ||
| 220 | std::string Weight_name; | ||
| 221 | int pixel_size; | ||
| 222 | int font_ascent; // 12 | ||
| 223 | int font_descent; // 4 | ||
| 224 | uint16_t default_char; // 65533 | ||
| 225 | } FontProperties; | ||
| 226 | |||
| 227 | typedef struct FontInfo { | ||
| 228 | std::string font; // n/a | ||
| 229 | int size_points, size_dpi_x, size_dpi_y; // n/a | ||
| 230 | // these may be overridden by individual characters. | ||
| 231 | BBX bbx; // FONTBOUNDINGBOX e.g. 8 16 0 -4 | ||
| 232 | int chars; // number of characters | ||
| 233 | int fontline_bytes; // length of a single font line in the byte array | ||
| 234 | } FontInfo; | ||
| 235 | |||
| 236 | class BdfFont { | ||
| 237 | public: | ||
| 238 | std::string font_filename; | ||
| 239 | FontInfo font_info; | ||
| 240 | FontProperties font_properties; | ||
| 241 | std::vector<uint16_t> codepoints_array; | ||
| 242 | std::vector<std::string> charnames_array; | ||
| 243 | // each character can have different bounding box dimensions from global one | ||
| 244 | std::vector<BBX> bbx_array; | ||
| 245 | // one character line is not limited to 16/32 pixels anymore: | ||
| 246 | std::vector<uint8_t> font_bitmaps; | ||
| 247 | }; | ||
| 248 | |||
| 249 | ✗ | std::string UnQuote(std::string s) { | |
| 250 | ✗ | if (s.size() >= 2 && s.substr(0, 1) == "\"" && (s.substr(s.size() - 1, 1) == "\"")) | |
| 251 | ✗ | return s.substr(1,s.size()-2); // zero based | |
| 252 | ✗ | return s; | |
| 253 | } | ||
| 254 | |||
| 255 | ✗ | static void vector_shl(uint8_t* buf, const size_t size, const size_t bits) { | |
| 256 | ✗ | const size_t whole_chunks = bits / 8; | |
| 257 | |||
| 258 | // more bits that size | ||
| 259 | ✗ | if (whole_chunks >= size) { | |
| 260 | ✗ | memset(buf, 0, size); | |
| 261 | ✗ | return; | |
| 262 | } | ||
| 263 | |||
| 264 | ✗ | if (whole_chunks) { | |
| 265 | ✗ | memmove(buf, buf + whole_chunks, size - whole_chunks); | |
| 266 | ✗ | memset(buf + size - whole_chunks, 0, whole_chunks); | |
| 267 | } | ||
| 268 | |||
| 269 | ✗ | const uint8_t final_shift = bits % 8; | |
| 270 | |||
| 271 | ✗ | if (final_shift) { | |
| 272 | ✗ | const auto right = 8 - final_shift; | |
| 273 | ✗ | const size_t len = size - whole_chunks - 1; | |
| 274 | ✗ | for (size_t i = 0; i < len; i++) { | |
| 275 | ✗ | buf[i] = (buf[i] << final_shift) | (buf[i + 1] >> right); | |
| 276 | } | ||
| 277 | ✗ | buf[len] = buf[len] << final_shift; | |
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | ✗ | static void vector_shr(uint8_t* buf, const size_t size, const size_t bits) { | |
| 282 | ✗ | const size_t whole_chunks = bits / 8; | |
| 283 | |||
| 284 | // more bits that size | ||
| 285 | ✗ | if (whole_chunks >= size) { | |
| 286 | ✗ | memset(buf, 0, size); | |
| 287 | ✗ | return; | |
| 288 | } | ||
| 289 | |||
| 290 | ✗ | if (whole_chunks) { | |
| 291 | ✗ | memmove(buf + whole_chunks, buf, size - whole_chunks); | |
| 292 | ✗ | memset(buf, 0, whole_chunks); | |
| 293 | } | ||
| 294 | |||
| 295 | ✗ | const uint8_t final_shift = bits % 8; | |
| 296 | |||
| 297 | ✗ | if (final_shift) { | |
| 298 | ✗ | const auto left = 8 - final_shift; | |
| 299 | ✗ | const size_t len = size - whole_chunks - 1; | |
| 300 | ✗ | auto index = size - 1; | |
| 301 | ✗ | for (size_t i = 0; i < len; i++) { | |
| 302 | ✗ | buf[index] = (buf[index] >> final_shift) | (buf[index - 1] << left); | |
| 303 | ✗ | index--; | |
| 304 | } | ||
| 305 | ✗ | buf[index] = buf[index] >> final_shift; | |
| 306 | } | ||
| 307 | } | ||
| 308 | |||
| 309 | ✗ | static BdfFont LoadBMF(std::string name, bool bold) { | |
| 310 | |||
| 311 | // https://en.wikipedia.org/wiki/Glyph_Bitmap_Distribution_Format | ||
| 312 | // also for make cpp source code, see BdfFont methods | ||
| 313 | |||
| 314 | enum loadstate { ls_Init, ls_StartFont, ls_StartProperties, ls_Char }; | ||
| 315 | |||
| 316 | ✗ | BdfFont fnt; | |
| 317 | ✗ | CharInfo current_char; | |
| 318 | |||
| 319 | ✗ | std::string temp; | |
| 320 | //std::ifstream ss("c:\\Download\\terminus-font-4.48\\terminus-font-4.48\\ter-u16n.bdf"); | ||
| 321 | ✗ | std::ifstream ss; | |
| 322 | // explicite font file name | ||
| 323 | ✗ | auto fname = fs::path(name); | |
| 324 | |||
| 325 | ✗ | if (!fs::exists(name)) | |
| 326 | ✗ | return fnt; | |
| 327 | |||
| 328 | ✗ | fnt.font_filename = fname.filename().generic_string(); | |
| 329 | ✗ | ss.open(name); | |
| 330 | |||
| 331 | ✗ | loadstate state = ls_Init; | |
| 332 | |||
| 333 | ✗ | size_t line_counter = 0; | |
| 334 | ✗ | int char_counter = 0; | |
| 335 | |||
| 336 | // make list governed by LF separator | ||
| 337 | ✗ | while (std::getline(ss, temp, '\n')) { | |
| 338 | ✗ | std::string token; | |
| 339 | ✗ | std::istringstream ssline(temp); | |
| 340 | |||
| 341 | ✗ | std::getline(ssline, token, ' '); | |
| 342 | |||
| 343 | ✗ | if (token.size() == 0) continue; | |
| 344 | |||
| 345 | ✗ | switch (state) { | |
| 346 | ✗ | case ls_Init: | |
| 347 | ✗ | if (token == "STARTFONT") | |
| 348 | ✗ | state = ls_StartFont; | |
| 349 | else { | ||
| 350 | // unexpected token | ||
| 351 | } | ||
| 352 | ✗ | break; | |
| 353 | ✗ | case ls_StartFont: | |
| 354 | ✗ | if (token == "ENDFONT") { | |
| 355 | ✗ | state = ls_Init; | |
| 356 | } | ||
| 357 | ✗ | else if (token == "FONT") { | |
| 358 | // FONT-xos4-Terminus-Bold-R-Normal--16-160-72-72-C-80-ISO10646-1 | ||
| 359 | ✗ | std::getline(ssline, token, ' '); | |
| 360 | ✗ | fnt.font_info.font = UnQuote(token); | |
| 361 | } | ||
| 362 | ✗ | else if (token == "SIZE") { | |
| 363 | // SIZE 16 72 72 | ||
| 364 | // size in points, X and Y-axis resolution | ||
| 365 | ✗ | std::getline(ssline, token, ' '); | |
| 366 | ✗ | fnt.font_info.size_points = std::stoi(token); | |
| 367 | ✗ | std::getline(ssline, token, ' '); | |
| 368 | ✗ | fnt.font_info.size_dpi_x = std::stoi(token); | |
| 369 | ✗ | std::getline(ssline, token, ' '); | |
| 370 | ✗ | fnt.font_info.size_dpi_y = std::stoi(token); | |
| 371 | } | ||
| 372 | ✗ | else if (token == "FONTBOUNDINGBOX") { | |
| 373 | // FONTBOUNDINGBOX 8 16 0 -4 | ||
| 374 | // bounding box of 8 pixels wide and 16 pixels high | ||
| 375 | // lower left hand corner starting at x=0, y=-4. Note that although the bounding box is defined to be a 8x16 cell, | ||
| 376 | // this can be overridden for individual glyphs. | ||
| 377 | |||
| 378 | // e.g: Terminus: FONTBOUNDINGBOX 8 16 0 -4Â Â Terminus | ||
| 379 | // later for "A": BBX 8 16 0 -4 | ||
| 380 | // Unifont: FONTBOUNDINGBOX 16 16 0 -2Â Unifont | ||
| 381 | // later for "A": BBX 8 16 0 -2 should override the global bounding box | ||
| 382 | |||
| 383 | ✗ | std::getline(ssline, token, ' '); | |
| 384 | ✗ | fnt.font_info.bbx.width = std::stoi(token); | |
| 385 | ✗ | std::getline(ssline, token, ' '); | |
| 386 | ✗ | fnt.font_info.bbx.height = std::stoi(token); | |
| 387 | ✗ | std::getline(ssline, token, ' '); | |
| 388 | ✗ | fnt.font_info.bbx.offset_x = std::stoi(token); | |
| 389 | ✗ | std::getline(ssline, token, ' '); | |
| 390 | ✗ | fnt.font_info.bbx.offset_y = std::stoi(token); | |
| 391 | |||
| 392 | // a single font line can occupy variable amount of bytes depending on font width | ||
| 393 | // Note: in this implementation these global font dimensions are _the_ | ||
| 394 | // dimensions of the fixed size font | ||
| 395 | // Note, that this is the maximum theoretical width; some BDF fonts (unifont) contain variable width characters | ||
| 396 | // contrary to that it contains monospaced "C" type characters. In this case latin characters are 8 pixels wide, | ||
| 397 | // and use DWIDTH and BBOX as 8, less than FONTBOUNDINGBOX value of 16. | ||
| 398 | // but CJK characters are 16 pixels wide. | ||
| 399 | ✗ | fnt.font_info.fontline_bytes = (fnt.font_info.bbx.width + 7) / 8; | |
| 400 | } | ||
| 401 | ✗ | else if (token == "STARTPROPERTIES") { | |
| 402 | // STARTPROPERTIES 20 | ||
| 403 | // do not check line count now | ||
| 404 | ✗ | state = ls_StartProperties; | |
| 405 | } | ||
| 406 | ✗ | else if (token == "CHARS") { | |
| 407 | ✗ | std::getline(ssline, token); | |
| 408 | ✗ | fnt.font_info.chars = std::stoi(token); | |
| 409 | // allocate area for "character_count" * "height" | ||
| 410 | ✗ | fnt.font_bitmaps.resize(fnt.font_info.chars * fnt.font_info.bbx.height * fnt.font_info.fontline_bytes); | |
| 411 | ✗ | fnt.charnames_array.resize(fnt.font_info.chars); | |
| 412 | ✗ | fnt.codepoints_array.resize(fnt.font_info.chars); | |
| 413 | ✗ | fnt.bbx_array.resize(fnt.font_info.chars); | |
| 414 | } | ||
| 415 | ✗ | else if (token == "STARTCHAR") { | |
| 416 | ✗ | std::getline(ssline, token); | |
| 417 | ✗ | current_char.friendly_name = token; | |
| 418 | ✗ | current_char.encoding = 0; | |
| 419 | ✗ | current_char.dwidth_x = 0; | |
| 420 | ✗ | current_char.dwidth_y = 0; | |
| 421 | ✗ | current_char.bbx = fnt.font_info.bbx; // inherited from FONTBOUNDINGBOX | |
| 422 | ✗ | current_char.bits_to_shift = 0; | |
| 423 | ✗ | current_char.empty_lines_bottom = 0; | |
| 424 | ✗ | current_char.empty_lines_top = 0; | |
| 425 | |||
| 426 | ✗ | state = ls_Char; | |
| 427 | } | ||
| 428 | else { | ||
| 429 | // unexpected token | ||
| 430 | } | ||
| 431 | ✗ | break; | |
| 432 | ✗ | case ls_StartProperties: | |
| 433 | ✗ | if (token == "ENDPROPERTIES") { | |
| 434 | ✗ | state = ls_StartFont; | |
| 435 | } | ||
| 436 | /* | ||
| 437 | FAMILY_NAME "Terminus" | ||
| 438 | FOUNDRY "xos4" | ||
| 439 | SETWIDTH_NAME "Normal" | ||
| 440 | ADD_STYLE_NAME "" | ||
| 441 | COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov" | ||
| 442 | NOTICE "Licensed under the SIL Open Font License, Version 1.1" | ||
| 443 | WEIGHT_NAME "Bold" | ||
| 444 | SLANT "R" | ||
| 445 | PIXEL_SIZE 16 | ||
| 446 | POINT_SIZE 160 | ||
| 447 | RESOLUTION_X 72 | ||
| 448 | RESOLUTION_Y 72 | ||
| 449 | SPACING "C" | ||
| 450 | AVERAGE_WIDTH 80 | ||
| 451 | CHARSET_REGISTRY "ISO10646" | ||
| 452 | CHARSET_ENCODING "1" | ||
| 453 | MIN_SPACE 8 | ||
| 454 | */ | ||
| 455 | ✗ | else if (token == "FAMILY_NAME") { | |
| 456 | //FAMILY_NAME "Terminus" | ||
| 457 | ✗ | std::getline(ssline, token, ' '); | |
| 458 | ✗ | fnt.font_properties.Family_name = UnQuote(token); | |
| 459 | } | ||
| 460 | ✗ | else if (token == "COPYRIGHT") { | |
| 461 | ✗ | std::getline(ssline, token, ' '); | |
| 462 | ✗ | fnt.font_properties.Copyright = UnQuote(token); | |
| 463 | } | ||
| 464 | ✗ | else if (token == "NOTICE") { | |
| 465 | ✗ | std::getline(ssline, token, ' '); | |
| 466 | ✗ | fnt.font_properties.Notice = UnQuote(token); | |
| 467 | } | ||
| 468 | ✗ | else if (token == "WEIGHT_NAME") { | |
| 469 | // "Medium", "Bold" | ||
| 470 | ✗ | std::getline(ssline, token, ' '); | |
| 471 | ✗ | fnt.font_properties.Weight_name = UnQuote(token); | |
| 472 | } | ||
| 473 | ✗ | else if (token == "PIXEL_SIZE") { | |
| 474 | ✗ | std::getline(ssline, token, ' '); | |
| 475 | ✗ | fnt.font_properties.pixel_size = std::stoi(token); | |
| 476 | } | ||
| 477 | ✗ | else if (token == "FONT_ASCENT") { | |
| 478 | // FONT_ASCENT 12 | ||
| 479 | // 12 of the 16 pixels in height are above the baseline. | ||
| 480 | ✗ | std::getline(ssline, token, ' '); | |
| 481 | ✗ | fnt.font_properties.font_ascent = std::stoi(token); | |
| 482 | } | ||
| 483 | ✗ | else if (token == "FONT_DESCENT") { | |
| 484 | // FONT_DESCENT 4 | ||
| 485 | // 4 of the 16 pixels in height are below the baseline | ||
| 486 | ✗ | std::getline(ssline, token, ' '); | |
| 487 | ✗ | fnt.font_properties.font_descent = std::stoi(token); | |
| 488 | } | ||
| 489 | ✗ | else if (token == "DEFAULT_CHAR") { | |
| 490 | // DEFAULT_CHAR 65533 | ||
| 491 | ✗ | std::getline(ssline, token, ' '); | |
| 492 | ✗ | fnt.font_properties.default_char = std::stoi(token); | |
| 493 | } | ||
| 494 | ✗ | break; | |
| 495 | ✗ | case ls_Char: | |
| 496 | ✗ | if (token == "ENDCHAR") { | |
| 497 | // add to vector | ||
| 498 | ✗ | state = ls_StartFont; | |
| 499 | } | ||
| 500 | ✗ | else if (token == "DWIDTH") { | |
| 501 | // DWIDTH 9 0 | ||
| 502 | // declares the Device Width of a glyph. After the glyph is rendered, the start of the next glyph is | ||
| 503 | // offset 9 pixels on the X-axis and | ||
| 504 | // offset 0 pixels on the Y-axis from the current glyph origin. | ||
| 505 | // They are not necessarily equal to the width of the glyph. | ||
| 506 | // It is simply the offset on the X-axis to move the current point to the start of the next glyph. | ||
| 507 | // dwidth_y is not used in Avisynth, fonts are of fixed heights | ||
| 508 | ✗ | std::getline(ssline, token, ' '); | |
| 509 | ✗ | current_char.dwidth_x = std::stoi(token); | |
| 510 | ✗ | std::getline(ssline, token, ' '); | |
| 511 | ✗ | current_char.dwidth_y = std::stoi(token); | |
| 512 | } | ||
| 513 | ✗ | else if (token == "ENCODING") { | |
| 514 | // ENCODING 32 | ||
| 515 | ✗ | std::getline(ssline, token, ' '); | |
| 516 | ✗ | current_char.encoding = std::stoi(token); | |
| 517 | } | ||
| 518 | ✗ | else if (token == "BBX") { | |
| 519 | // BBX 8 16 0 -4 bounding box. 8 pixels wide and 16 pixels tall; | ||
| 520 | // lower left corner is offset by 0 on the X and -4 pixels on the Y axis. | ||
| 521 | |||
| 522 | // Originally we only assumed Monospaced, uniformly fixed size fonts. | ||
| 523 | // But technically we can have variable width characters inside due to per character BBOX. | ||
| 524 | // E.g. Latin characters usually have a DWIDTH of 8, while others like CJK Unifont | ||
| 525 | // characters have a DWIDTH of 16. (like U + 007F and CJK glyphs). Because of these | ||
| 526 | // wider characters, the FONTBOUNDINGBOX must be 16 pixels wide to signal the renderer | ||
| 527 | // the maximum possible width for the font type (useful for buffer preallocation). But | ||
| 528 | // ordinarly Latin characters are still 8 bits wide. | ||
| 529 | // So can we support "fixed width" fonts which contains character bitmaps of different widths. | ||
| 530 | |||
| 531 | ✗ | std::getline(ssline, token, ' '); | |
| 532 | ✗ | current_char.bbx.width = std::stoi(token); | |
| 533 | ✗ | std::getline(ssline, token, ' '); | |
| 534 | ✗ | current_char.bbx.height = std::stoi(token); | |
| 535 | ✗ | std::getline(ssline, token, ' '); | |
| 536 | ✗ | current_char.bbx.offset_x = std::stoi(token); | |
| 537 | ✗ | std::getline(ssline, token, ' '); | |
| 538 | ✗ | current_char.bbx.offset_y = std::stoi(token); | |
| 539 | ✗ | current_char.empty_lines_bottom = current_char.bbx.offset_y - fnt.font_info.bbx.offset_y; | |
| 540 | ✗ | current_char.empty_lines_top = fnt.font_info.bbx.height - (current_char.empty_lines_bottom + current_char.bbx.height); | |
| 541 | ✗ | current_char.bits_to_shift = current_char.bbx.width - current_char.dwidth_x; // actual per-characer dwidth_x can differ from font_info.bbx.width | |
| 542 | } | ||
| 543 | ✗ | else if (token == "BITMAP") { | |
| 544 | /* space: | ||
| 545 | STARTCHAR space | ||
| 546 | ENCODING 32 | ||
| 547 | SWIDTH 692 0 | ||
| 548 | DWIDTH 9 0 | ||
| 549 | BBX 0 0 0 0 | ||
| 550 | BITMAP | ||
| 551 | ENDCHAR | ||
| 552 | |||
| 553 | or | ||
| 554 | |||
| 555 | 6x12: | ||
| 556 | BITMAP | ||
| 557 | 00 | ||
| 558 | 00 | ||
| 559 | 70 | ||
| 560 | 88 | ||
| 561 | 08 | ||
| 562 | 30 | ||
| 563 | 08 | ||
| 564 | 08 | ||
| 565 | 88 | ||
| 566 | 70 | ||
| 567 | 00 | ||
| 568 | 00 | ||
| 569 | ENDCHAR | ||
| 570 | |||
| 571 | 10x18: | ||
| 572 | BITMAP | ||
| 573 | 0000 | ||
| 574 | 0000 | ||
| 575 | 0000 | ||
| 576 | 3F00 | ||
| 577 | 6180 | ||
| 578 | 6180 | ||
| 579 | 0180 | ||
| 580 | 0180 | ||
| 581 | 1F00 | ||
| 582 | 0180 | ||
| 583 | 0180 | ||
| 584 | 0180 | ||
| 585 | 6180 | ||
| 586 | 6180 | ||
| 587 | 3F00 | ||
| 588 | 0000 | ||
| 589 | 0000 | ||
| 590 | 0000 | ||
| 591 | ENDCHAR | ||
| 592 | */ | ||
| 593 | ✗ | fnt.codepoints_array[char_counter] = current_char.encoding; | |
| 594 | ✗ | fnt.charnames_array[char_counter] = current_char.friendly_name; | |
| 595 | ✗ | fnt.bbx_array[char_counter] = current_char.bbx; | |
| 596 | ✗ | char_counter++; | |
| 597 | |||
| 598 | // by spec: charlines are left aligned within byte boundaries | ||
| 599 | |||
| 600 | // fill empty top lines | ||
| 601 | ✗ | for (int count = 0; count < current_char.empty_lines_top; count++) { | |
| 602 | // fontline_bytes bytes per line | ||
| 603 | ✗ | for(int i = 0; i < fnt.font_info.fontline_bytes; i++) | |
| 604 | ✗ | fnt.font_bitmaps[line_counter++] = 0; | |
| 605 | } | ||
| 606 | |||
| 607 | // one character line is of (almost) arbitrary length, not limited to 16 or 32 bits | ||
| 608 | ✗ | std::vector<uint8_t> charline_buffer(fnt.font_info.fontline_bytes); | |
| 609 | ✗ | const size_t linebuf_len = fnt.font_info.fontline_bytes; | |
| 610 | |||
| 611 | ✗ | for(int count = 0; count < current_char.bbx.height; count++) | |
| 612 | { | ||
| 613 | ✗ | std::getline(ss, temp); | |
| 614 | |||
| 615 | ✗ | size_t len = temp.length(); | |
| 616 | ✗ | const size_t bytes_defined = len / 2; | |
| 617 | |||
| 618 | ✗ | if (len % 2) { | |
| 619 | // weird, one byte must be defined on two hexadecimal characters | ||
| 620 | // FIXME: should give an error | ||
| 621 | } | ||
| 622 | ✗ | if (bytes_defined > linebuf_len) { | |
| 623 | // weird, more bytes defined that needed for the font width defined in the header | ||
| 624 | // FIXME: should give an error | ||
| 625 | ✗ | len = linebuf_len * 2; // until then a safe limit | |
| 626 | } | ||
| 627 | ✗ | size_t buf_ctr = 0; | |
| 628 | // two hex characters by two character then put into byte buffer | ||
| 629 | ✗ | for (size_t i = 0; i < len; i += 2) { | |
| 630 | ✗ | auto ssss = temp.substr(i, 2); // next two hex chars | |
| 631 | ✗ | charline_buffer[buf_ctr++] = (uint8_t)std::stoul(ssss, nullptr, 16); | |
| 632 | ✗ | } | |
| 633 | ✗ | for (auto i = buf_ctr; i < linebuf_len; i++) | |
| 634 | ✗ | charline_buffer[i] = 0; | |
| 635 | |||
| 636 | // shift full buffer, they are msb...lsb for increasing addresses | ||
| 637 | ✗ | if (current_char.bits_to_shift < 0) { | |
| 638 | ✗ | const int bits_to_shift_left = -current_char.bits_to_shift; | |
| 639 | ✗ | vector_shl(charline_buffer.data(), fnt.font_info.fontline_bytes, bits_to_shift_left); | |
| 640 | } | ||
| 641 | ✗ | else if (current_char.bits_to_shift > 0) { | |
| 642 | ✗ | const int bits_to_shift_right = current_char.bits_to_shift; | |
| 643 | ✗ | vector_shr(charline_buffer.data(), fnt.font_info.fontline_bytes, bits_to_shift_right); | |
| 644 | } | ||
| 645 | |||
| 646 | ✗ | for(int i = 0; i < fnt.font_info.fontline_bytes; i++) { | |
| 647 | ✗ | fnt.font_bitmaps[line_counter++] = charline_buffer[i]; | |
| 648 | } | ||
| 649 | } | ||
| 650 | |||
| 651 | // fill empty bottom lines | ||
| 652 | ✗ | for (int count = 0; count < current_char.empty_lines_bottom; count++) { | |
| 653 | // fontline_bytes bytes per line | ||
| 654 | ✗ | for (int i = 0; i < fnt.font_info.fontline_bytes; i++) | |
| 655 | ✗ | fnt.font_bitmaps[line_counter++] = 0; | |
| 656 | } | ||
| 657 | |||
| 658 | ✗ | } | |
| 659 | ✗ | break; | |
| 660 | } | ||
| 661 | ✗ | } | |
| 662 | |||
| 663 | ✗ | return fnt; | |
| 664 | ✗ | } | |
| 665 | /* | ||
| 666 | |||
| 667 | STARTFONT 2.1 | ||
| 668 | FONT -xos4-Terminus-Bold-R-Normal--16-160-72-72-C-80-ISO10646-1 | ||
| 669 | SIZE 16 72 72 | ||
| 670 | FONTBOUNDINGBOX 8 16 0 -4 | ||
| 671 | |||
| 672 | STARTPROPERTIES 20 | ||
| 673 | FAMILY_NAME "Terminus" | ||
| 674 | FOUNDRY "xos4" | ||
| 675 | SETWIDTH_NAME "Normal" | ||
| 676 | ADD_STYLE_NAME "" | ||
| 677 | COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov" | ||
| 678 | NOTICE "Licensed under the SIL Open Font License, Version 1.1" | ||
| 679 | WEIGHT_NAME "Bold" | ||
| 680 | SLANT "R" | ||
| 681 | PIXEL_SIZE 16 | ||
| 682 | POINT_SIZE 160 | ||
| 683 | RESOLUTION_X 72 | ||
| 684 | RESOLUTION_Y 72 | ||
| 685 | SPACING "C" | ||
| 686 | AVERAGE_WIDTH 80 | ||
| 687 | CHARSET_REGISTRY "ISO10646" | ||
| 688 | CHARSET_ENCODING "1" | ||
| 689 | MIN_SPACE 8 | ||
| 690 | FONT_ASCENT 12 | ||
| 691 | FONT_DESCENT 4 | ||
| 692 | DEFAULT_CHAR 65533 | ||
| 693 | ENDPROPERTIES | ||
| 694 | |||
| 695 | CHARS 1354 | ||
| 696 | |||
| 697 | STARTCHAR space | ||
| 698 | ENCODING 32 | ||
| 699 | SWIDTH 500 0 | ||
| 700 | DWIDTH 8 0 | ||
| 701 | BBX 8 16 0 -4 | ||
| 702 | BITMAP | ||
| 703 | ... | ||
| 704 | 00 | ||
| 705 | ENDCHAR | ||
| 706 | |||
| 707 | ENDFONT | ||
| 708 | */ | ||
| 709 | |||
| 710 | static constexpr int ATA_LEFT = 1; | ||
| 711 | static constexpr int ATA_RIGHT = 2; | ||
| 712 | static constexpr int ATA_CENTER = 4; | ||
| 713 | |||
| 714 | static constexpr int ATA_TOP = 8; | ||
| 715 | static constexpr int ATA_BOTTOM = 16; | ||
| 716 | static constexpr int ATA_BASELINE = 32; | ||
| 717 | |||
| 718 | 8 | static int alignToBitmask(int align_1_to_9) | |
| 719 | { | ||
| 720 | // alignment 1-9: digit positions on numeric keypad | ||
| 721 | 8 | int al = 0; | |
| 722 |
1/10✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
✗ Branch 2 → 5 not taken.
✗ Branch 2 → 6 not taken.
✗ Branch 2 → 7 not taken.
✗ Branch 2 → 8 not taken.
✓ Branch 2 → 9 taken 8 times.
✗ Branch 2 → 10 not taken.
✗ Branch 2 → 11 not taken.
✗ Branch 2 → 12 not taken.
|
8 | switch (align_1_to_9) // This spec where [X, Y] is relative to the text (inverted logic) |
| 723 | { | ||
| 724 | ✗ | case 1: al = ATA_BOTTOM | ATA_LEFT; break; // .---- | |
| 725 | ✗ | case 2: al = ATA_BOTTOM | ATA_CENTER; break; // --.-- | |
| 726 | ✗ | case 3: al = ATA_BOTTOM | ATA_RIGHT; break; // ----. | |
| 727 | ✗ | case 4: al = ATA_BASELINE | ATA_LEFT; break; // .____ | |
| 728 | ✗ | case 5: al = ATA_BASELINE | ATA_CENTER; break; // __.__ | |
| 729 | ✗ | case 6: al = ATA_BASELINE | ATA_RIGHT; break; // ____. | |
| 730 | 8 | case 7: al = ATA_TOP | ATA_LEFT; break; // `---- | |
| 731 | ✗ | case 8: al = ATA_TOP | ATA_CENTER; break; // --`-- | |
| 732 | ✗ | case 9: al = ATA_TOP | ATA_RIGHT; break; // ----` | |
| 733 | ✗ | default: al = ATA_BASELINE | ATA_LEFT; break; // .____ | |
| 734 | } | ||
| 735 | 8 | return al; | |
| 736 | } | ||
| 737 | |||
| 738 | 42 | static int getColorForPlane(int plane, int color) | |
| 739 | { | ||
| 740 |
3/5✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 14 times.
✓ Branch 2 → 5 taken 14 times.
✓ Branch 2 → 6 taken 14 times.
✗ Branch 2 → 7 not taken.
|
42 | switch (plane) { |
| 741 | ✗ | case PLANAR_A: | |
| 742 | ✗ | return (color >> 24) & 0xff; break; | |
| 743 | 14 | case PLANAR_R: | |
| 744 | case PLANAR_Y: | ||
| 745 | 14 | return (color >> 16) & 0xff; break; | |
| 746 | 14 | case PLANAR_G: | |
| 747 | case PLANAR_U: | ||
| 748 | 14 | return (color >> 8) & 0xff; break; | |
| 749 | 14 | case PLANAR_B: | |
| 750 | case PLANAR_V: | ||
| 751 | 14 | return color & 0xff; break; | |
| 752 | } | ||
| 753 | ✗ | return color & 0xFF; | |
| 754 | } | ||
| 755 | |||
| 756 | template<typename pixel_t, bool fadeBackground> | ||
| 757 | void AVS_FORCEINLINE LightOnePixelPackedRGB(const bool lightIt, BYTE* _dp, int val_color_R, int val_color_G, int val_color_B) | ||
| 758 | { | ||
| 759 | 59427 | pixel_t* dp = reinterpret_cast<pixel_t*>(_dp); | |
| 760 | 59427 | if (lightIt) { | |
| 761 | 7902 | dp[0] = val_color_B; | |
| 762 | 7902 | dp[1] = val_color_G; | |
| 763 | 7902 | dp[2] = val_color_R; | |
| 764 | } | ||
| 765 | else { | ||
| 766 | if constexpr (fadeBackground) { | ||
| 767 | ✗ | dp[0] = (pixel_t)((dp[0] * 7) >> 3); | |
| 768 | ✗ | dp[1] = (pixel_t)((dp[1] * 7) >> 3); | |
| 769 | ✗ | dp[2] = (pixel_t)((dp[2] * 7) >> 3); | |
| 770 | } | ||
| 771 | } | ||
| 772 | 59427 | } | |
| 773 | |||
| 774 | template<typename pixel_t, bool fadeBackground, bool isRGB> | ||
| 775 | void AVS_FORCEINLINE LightOnePixel(const bool lightIt, pixel_t* dstp, int j, pixel_t& val_color, int bits_per_pixel) | ||
| 776 | { | ||
| 777 | // some optimization hint | ||
| 778 | if constexpr (sizeof(pixel_t) == 1) | ||
| 779 | ✗ | bits_per_pixel = 8; | |
| 780 | else if constexpr (sizeof(pixel_t) == 4) | ||
| 781 | ✗ | bits_per_pixel = 32; | |
| 782 | |||
| 783 | ✗ | if (lightIt) { // character definition bits aligned to msb | |
| 784 | ✗ | dstp[j] = val_color; | |
| 785 | } | ||
| 786 | else { | ||
| 787 | // 16 = y_min | ||
| 788 | // speed optimization: one subtraction less, 5-8% faster | ||
| 789 | // (((Y - 16) * 7) >> 3) + 16 = ((Y * 7) >> 3) + 2 | ||
| 790 | // in general: ((Y * 7) >> 3) + n, where n = range_min - ((range_min * 7) >> 3) | ||
| 791 | if constexpr (fadeBackground) { | ||
| 792 | // background darkening | ||
| 793 | if constexpr (isRGB) { | ||
| 794 | if constexpr (sizeof(pixel_t) != 4) | ||
| 795 | ✗ | dstp[j] = (pixel_t)((dstp[j] * 7) >> 3); | |
| 796 | else { | ||
| 797 | ✗ | constexpr float factor = 7.0f / 8; | |
| 798 | ✗ | dstp[j] = (pixel_t)(dstp[j] * factor); | |
| 799 | } | ||
| 800 | } | ||
| 801 | else { | ||
| 802 | if constexpr (sizeof(pixel_t) != 4) { | ||
| 803 | ✗ | const int range_min = 16 << (bits_per_pixel - 8); | |
| 804 | ✗ | const int n = range_min - ((range_min * 7) >> 3); | |
| 805 | ✗ | dstp[j] = (pixel_t)(((dstp[j] * 7) >> 3) + n); // (_dstp[j] - range_min) * 7) >> 3) + range_min); | |
| 806 | } | ||
| 807 | else { | ||
| 808 | ✗ | constexpr float range_min_f = 16.0f / 255.0f; | |
| 809 | ✗ | dstp[j] = (pixel_t)(((dstp[j] - range_min_f) * 7 / 8) + range_min_f); | |
| 810 | } | ||
| 811 | } | ||
| 812 | } | ||
| 813 | } | ||
| 814 | ✗ | } | |
| 815 | |||
| 816 | template<typename pixel_t, int logXRatioUV, int logYRatioUV, bool fadeBackground, ChromaLocationMode chromaMode> | ||
| 817 | ✗ | static void LightOneUVPixel(pixel_t* dstpU, int j, pixel_t* dstpV, pixel_t& font_color_u, pixel_t& font_color_v, pixel_t& halo_color_u, pixel_t& halo_color_v, | |
| 818 | int fontpixelcount, int halopixelcount, | ||
| 819 | int bits_per_pixel | ||
| 820 | ) | ||
| 821 | { | ||
| 822 | if constexpr (!fadeBackground) { | ||
| 823 | ✗ | if (halopixelcount == 0 && fontpixelcount == 0) return; // no change, keep background | |
| 824 | } | ||
| 825 | |||
| 826 | // some optimization hint | ||
| 827 | if constexpr (sizeof(pixel_t) == 1) | ||
| 828 | ✗ | bits_per_pixel = 8; | |
| 829 | else if constexpr (sizeof(pixel_t) == 4) | ||
| 830 | ✗ | bits_per_pixel = 32; | |
| 831 | |||
| 832 | // weighed count | ||
| 833 | ✗ | constexpr int totalpixelcount = | |
| 834 | (chromaMode == LEFT_420) ? 8 : // 1-2-1 | 1-2-1 | ||
| 835 | (chromaMode == LEFT_422) ? 4 : // 1-2-1 | ||
| 836 | (chromaMode == CENTER_420) ? 4 : // 1-1 | 1-1 | ||
| 837 | (chromaMode == CENTER_422) ? 2 : // 1-1 | ||
| 838 | (chromaMode == CENTER_411) ? 4 : // 1-1-1-1 | ||
| 839 | 1; // unreached | ||
| 840 | |||
| 841 | ✗ | if (fontpixelcount == totalpixelcount) { | |
| 842 | ✗ | dstpU[j] = font_color_u; | |
| 843 | ✗ | dstpV[j] = font_color_v; | |
| 844 | } | ||
| 845 | ✗ | else if (halopixelcount == totalpixelcount) { | |
| 846 | ✗ | dstpU[j] = halo_color_u; | |
| 847 | ✗ | dstpV[j] = halo_color_v; | |
| 848 | } | ||
| 849 | else { | ||
| 850 | // not reached, only when subsampled | ||
| 851 | ✗ | pixel_t actualU = dstpU[j]; | |
| 852 | ✗ | pixel_t actualV = dstpV[j]; | |
| 853 | ✗ | const int backgroundpixelcount = totalpixelcount - fontpixelcount - halopixelcount; | |
| 854 | |||
| 855 | if constexpr (fadeBackground) { | ||
| 856 | // have to fade the existing background color | ||
| 857 | // speed optimization: one subtraction less | ||
| 858 | // (((U - 128) * 7) >> 3) + 128 = ((U * 7) >> 3) + 16 | ||
| 859 | // in general: ((U * 7) >> 3) + n where n = range_half - ((range_half * 7) >> 3) | ||
| 860 | if constexpr (sizeof(pixel_t) != 4) { | ||
| 861 | ✗ | int range_half = 1 << (bits_per_pixel - 1); | |
| 862 | ✗ | int n = range_half - ((range_half * 7) >> 3); | |
| 863 | ✗ | actualU = (pixel_t)(((actualU * 7) >> 3) + n); // ((((U - range_half) * 7) >> 3) + range_half); | |
| 864 | ✗ | actualV = (pixel_t)(((actualV * 7) >> 3) + n); | |
| 865 | } | ||
| 866 | else { | ||
| 867 | ✗ | constexpr float chroma_center = 0.0f; // ancient times this was 0.5 | |
| 868 | ✗ | constexpr float factor = 7.0f / 8.0f; | |
| 869 | ✗ | actualU = (pixel_t)(((actualU - chroma_center) * factor) + chroma_center); | |
| 870 | ✗ | actualV = (pixel_t)(((actualV - chroma_center) * factor) + chroma_center); | |
| 871 | } | ||
| 872 | } | ||
| 873 | |||
| 874 | // compute resulting color weighted by pixel kinds | ||
| 875 | if constexpr (sizeof(pixel_t) != 4) { | ||
| 876 | ✗ | constexpr int rounder = totalpixelcount >> 1; | |
| 877 | ✗ | constexpr int divshift = | |
| 878 | (chromaMode == LEFT_420) ? 3 : | ||
| 879 | (chromaMode == LEFT_422) ? 2 : | ||
| 880 | (chromaMode == CENTER_420) ? 2 : | ||
| 881 | (chromaMode == CENTER_422) ? 1 : | ||
| 882 | (chromaMode == CENTER_411) ? 2 : | ||
| 883 | 0; // unreached | ||
| 884 | |||
| 885 | ✗ | const int effective_color_u = (font_color_u * fontpixelcount + halo_color_u * halopixelcount + actualU * backgroundpixelcount + rounder); | |
| 886 | ✗ | const int effective_color_v = (font_color_v * fontpixelcount + halo_color_v * halopixelcount + actualV * backgroundpixelcount + rounder); | |
| 887 | ✗ | dstpU[j] = effective_color_u >> divshift; | |
| 888 | ✗ | dstpV[j] = effective_color_v >> divshift; | |
| 889 | } | ||
| 890 | else { | ||
| 891 | ✗ | constexpr float chroma_center = 0.0f; | |
| 892 | ✗ | float effective_color_u = (font_color_u - chroma_center) * fontpixelcount + (halo_color_u - chroma_center) * halopixelcount + (actualU - chroma_center) * backgroundpixelcount; | |
| 893 | ✗ | float effective_color_v = (font_color_v - chroma_center) * fontpixelcount + (halo_color_v - chroma_center) * halopixelcount + (actualV - chroma_center) * backgroundpixelcount; | |
| 894 | ✗ | dstpU[j] = effective_color_u / totalpixelcount + chroma_center; | |
| 895 | ✗ | dstpV[j] = effective_color_v / totalpixelcount + chroma_center; | |
| 896 | } | ||
| 897 | } | ||
| 898 | ✗ | } | |
| 899 | |||
| 900 | // s (containing the indexes to the fontbitmap array) is modified in-place | ||
| 901 | 7 | static void adjustWriteLimits(std::vector<int>& s, const std::vector<BBX>& bbx_array, const int vi_width, const int vi_height, | |
| 902 | const int FONT_WIDTH_not_used, const int FONT_HEIGHT, | ||
| 903 | int align, | ||
| 904 | const bool useHalocolor, | ||
| 905 | int& x, int& y, int& len, int& startindex, int& xstart, int& ystart, int& yend) | ||
| 906 | { | ||
| 907 | 7 | const int al = alignToBitmask(align); | |
| 908 | |||
| 909 | // cannot calculate with len * FONT_WIDTH, because characters can have different widths | ||
| 910 | 7 | int total_width = 0; | |
| 911 |
2/2✓ Branch 7 → 4 taken 369 times.
✓ Branch 7 → 8 taken 7 times.
|
376 | for (int i = 0; i < len; i++) { |
| 912 | // bbx_array is the array of bounding boxes for each character | ||
| 913 | // s[i] is the index to the fontbitmap array | ||
| 914 | 369 | total_width += bbx_array[s[i]].width; | |
| 915 | } | ||
| 916 | |||
| 917 | // alignment X | ||
| 918 |
1/2✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 7 times.
|
7 | if (al & ATA_RIGHT) |
| 919 | ✗ | x -= (total_width - 1); | |
| 920 |
1/2✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 7 times.
|
7 | else if (al & ATA_CENTER) |
| 921 | ✗ | x -= (total_width / 2); | |
| 922 | |||
| 923 | // alignment Y | ||
| 924 |
1/2✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 7 times.
|
7 | if (al & ATA_BASELINE) |
| 925 | ✗ | y -= FONT_HEIGHT / 2; | |
| 926 |
1/2✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 7 times.
|
7 | else if (al & ATA_BOTTOM) |
| 927 | ✗ | y -= (FONT_HEIGHT - 1); | |
| 928 | |||
| 929 |
1/2✓ Branch 16 → 17 taken 7 times.
✗ Branch 16 → 18 not taken.
|
7 | const int final_height = useHalocolor ? FONT_HEIGHT + 2 : FONT_HEIGHT; |
| 930 |
1/2✓ Branch 19 → 20 taken 7 times.
✗ Branch 19 → 21 not taken.
|
7 | if (useHalocolor) y = y - 1; // one more top line, adjust y (we do it after the alignment!) |
| 931 | |||
| 932 | // Chop text if exceed right margin | ||
| 933 | // keep last character of which at least one pixel can be drawn | ||
| 934 | |||
| 935 | // Fixed FONT_WIDTH calculation logic is replaced with logic which allows variable width characters | ||
| 936 | // Starting the truncation from the right side until the last character fits into the right margin, at least one pixel of it. | ||
| 937 | // bbx.width is the width of the character, not the whole font, this amount must be subtracted from the right margin. | ||
| 938 |
5/6✓ Branch 25 → 26 taken 8 times.
✗ Branch 25 → 30 not taken.
✓ Branch 28 → 29 taken 1 time.
✓ Branch 28 → 30 taken 7 times.
✓ Branch 31 → 22 taken 1 time.
✓ Branch 31 → 32 taken 7 times.
|
8 | while(len > 0 && total_width > vi_width - x + bbx_array[s[len - 1]].width) { |
| 939 | // remove last character | ||
| 940 | 1 | len--; | |
| 941 | 1 | total_width -= bbx_array[s[len]].width; | |
| 942 | } | ||
| 943 | /* // old method left here intentionally: | ||
| 944 | if (len * FONT_WIDTH > width - x) | ||
| 945 | len = (width - x + FONT_WIDTH - 1) / FONT_WIDTH; | ||
| 946 | */ | ||
| 947 | |||
| 948 | // FIXME: what if the character not, but its left side halo would be seen? | ||
| 949 | |||
| 950 | 7 | startindex = 0; | |
| 951 | 7 | xstart = 0; | |
| 952 | // Chop 1st char if exceed left margin | ||
| 953 |
1/2✗ Branch 32 → 33 not taken.
✓ Branch 32 → 40 taken 7 times.
|
7 | if (x < 0) { |
| 954 | // startindex is the first position in the string to be drawn | ||
| 955 | // Previously we had a global font-constant FONT_WIDTH, it was the same as x / FONT_WIDTH | ||
| 956 | // and the internal start position could be calculated as (-x) % FONT_WIDTH. | ||
| 957 | // Now that we allow that BDF originated characters can have different widths, we must | ||
| 958 | // calculate the startindex one-by-one from the left side. | ||
| 959 | ✗ | while (startindex < len && x < 0) { | |
| 960 | // s[startindex] is the index to the fontbitmap array | ||
| 961 | // bbx_array[s[startindex]].width is the width of the character | ||
| 962 | ✗ | x += bbx_array[s[startindex]].width; | |
| 963 | ✗ | startindex++; | |
| 964 | } | ||
| 965 | // x is the remaining negative offset, which is the start position of the first character | ||
| 966 | ✗ | xstart = x; // this is the start position of the first character | |
| 967 | // OLD method left here intentionally: | ||
| 968 | /* | ||
| 969 | startindex = (-x) / FONT_WIDTH; | ||
| 970 | xstart = (-x) % FONT_WIDTH; | ||
| 971 | */ | ||
| 972 | ✗ | x = 0; | |
| 973 | } | ||
| 974 | |||
| 975 | 7 | ystart = 0; | |
| 976 | 7 | yend = final_height; | |
| 977 | // Chop font if exceed bottom margin | ||
| 978 |
1/2✗ Branch 40 → 41 not taken.
✓ Branch 40 → 42 taken 7 times.
|
7 | if (y > vi_height - final_height) |
| 979 | ✗ | yend = vi_height - y; | |
| 980 | |||
| 981 | // Chop font if exceed top margin | ||
| 982 |
1/2✗ Branch 42 → 43 not taken.
✓ Branch 42 → 44 taken 7 times.
|
7 | if (y < 0) { |
| 983 | ✗ | ystart = -y; | |
| 984 | ✗ | y = 0; | |
| 985 | } | ||
| 986 | |||
| 987 | // Roll in start index | ||
| 988 |
1/2✗ Branch 44 → 45 not taken.
✓ Branch 44 → 59 taken 7 times.
|
7 | if (startindex > 0) { |
| 989 | ✗ | s.erase(s.begin(), s.begin() + startindex); | |
| 990 | ✗ | len -= startindex; | |
| 991 | } | ||
| 992 | 7 | } | |
| 993 | |||
| 994 | // Inserts leftmost 'bitcount' bits of fontlinebuf at the end of the byte buffer dst, | ||
| 995 | // Target is the 'bitposition'th bit | ||
| 996 | 4808 | static void insert_from_msb_bit(uint8_t *dst, int bitposition, const uint8_t* fontlinebuf, int fontlinebuf_size, int bitcount) | |
| 997 | { | ||
| 998 | 4808 | int pos = bitposition / 8; | |
| 999 | 4808 | int bitindex = bitposition % 8; | |
| 1000 |
2/2✓ Branch 2 → 3 taken 4528 times.
✓ Branch 2 → 10 taken 280 times.
|
4808 | if (bitindex > 0) { |
| 1001 | 4528 | const int usable_msb_count = 8 - bitindex; | |
| 1002 | // mask FF >> (bitindex) | ||
| 1003 | // bitindex 1 mask = 10000000 01111111 | ||
| 1004 | // bitindex 7 mask = 11111110 00000001 | ||
| 1005 | 4528 | const uint8_t mask = (uint8_t)(0xFF >> bitindex); // leftmost (msb) N bits | |
| 1006 | 4528 | const uint8_t partial_val = (uint8_t)((fontlinebuf[0] >> bitindex) & mask); // shift leftmost bits lsb | |
| 1007 | 4528 | dst[pos++] |= partial_val; // or'd with existing | |
| 1008 | |||
| 1009 | 4528 | bitcount -= usable_msb_count; | |
| 1010 | |||
| 1011 | // deal with shifted buffer from now on | ||
| 1012 | 4528 | int bufpos = 0; | |
| 1013 |
2/2✓ Branch 8 → 4 taken 3252 times.
✓ Branch 8 → 9 taken 4528 times.
|
7780 | while (bitcount > 0) { |
| 1014 | uint8_t val; | ||
| 1015 |
1/2✓ Branch 4 → 5 taken 3252 times.
✗ Branch 4 → 6 not taken.
|
3252 | if (bufpos <fontlinebuf_size - 1) |
| 1016 | 3252 | val = (fontlinebuf[bufpos] << usable_msb_count) | (fontlinebuf[bufpos + 1] >> (8 - usable_msb_count)); | |
| 1017 | else | ||
| 1018 | ✗ | val = (fontlinebuf[bufpos] << usable_msb_count); // suppose that unused lsb bits were 0 in the end | |
| 1019 | |||
| 1020 | // put actual byte into buffer | ||
| 1021 | 3252 | dst[pos++] = val; | |
| 1022 | 3252 | bufpos++; | |
| 1023 | 3252 | bitcount -= 8; | |
| 1024 | } | ||
| 1025 | 4528 | return; | |
| 1026 | } | ||
| 1027 | |||
| 1028 | 280 | int bufpos = 0; | |
| 1029 |
2/2✓ Branch 12 → 11 taken 98 times.
✓ Branch 12 → 13 taken 280 times.
|
378 | while (bitcount > 0) { |
| 1030 | // put actual byte into buffer | ||
| 1031 | 98 | dst[pos++] = fontlinebuf[bufpos++]; // suppose that unused lsb bits were 0 in the end | |
| 1032 | 98 | bitcount -= 8; | |
| 1033 | } | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | 59427 | static uint8_t get_bit(uint8_t* src, const int bitposition) | |
| 1037 | { | ||
| 1038 | 59427 | int pos = bitposition / 8; | |
| 1039 | 59427 | int bitindex = bitposition % 8; | |
| 1040 | 59427 | const uint8_t mask = 1 << (7 - bitindex); | |
| 1041 | 59427 | return src[pos] & mask; | |
| 1042 | } | ||
| 1043 | |||
| 1044 | ✗ | static int get_bits(uint8_t* src, int bitposition, int count) | |
| 1045 | { | ||
| 1046 | ✗ | int bitcounter = 0; | |
| 1047 | ✗ | while (count--) { | |
| 1048 | ✗ | if (0 != get_bit(src, bitposition++)) | |
| 1049 | ✗ | bitcounter++; | |
| 1050 | } | ||
| 1051 | ✗ | return bitcounter; | |
| 1052 | } | ||
| 1053 | |||
| 1054 | 7 | void PreRendered::make_outline() { | |
| 1055 | 7 | auto h = stringbitmap.size(); | |
| 1056 | 7 | auto w = stringbitmap[0].size(); | |
| 1057 | |||
| 1058 | // circular line buffer for holding precalculated shifted lines | ||
| 1059 |
1/2✓ Branch 7 → 8 taken 7 times.
✗ Branch 7 → 51 not taken.
|
14 | std::vector<uint8_t> buf1(w); |
| 1060 |
1/2✓ Branch 11 → 12 taken 7 times.
✗ Branch 11 → 54 not taken.
|
14 | std::vector<uint8_t> buf2(w); |
| 1061 |
1/2✓ Branch 15 → 16 taken 7 times.
✗ Branch 15 → 57 not taken.
|
7 | std::vector<uint8_t> buf3(w); |
| 1062 | |||
| 1063 | // it's unnecessary to mask the last byte against valid bitcounter, they won't drawn | ||
| 1064 | // const uint8_t mask = ~(0xFF >> (8 - (bitcounter % 8))); | ||
| 1065 | |||
| 1066 | // shift a line left and rights and result is or'd | ||
| 1067 | 98 | auto make_dizzyLR = [](uint8_t* dst, auto src, size_t w) { | |
| 1068 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 98 times.
|
98 | if (w == 1) |
| 1069 | { | ||
| 1070 | ✗ | *dst = (src[0] << 1) | (src[0] >> 1); | |
| 1071 | ✗ | return; | |
| 1072 | } | ||
| 1073 | // leftmost | ||
| 1074 | 98 | uint8_t left = (src[0] << 1) | (src[1] >> (8 - 1)); | |
| 1075 | 98 | uint8_t right = 0 | (src[0] >> 1); | |
| 1076 | 98 | *dst = left | right; | |
| 1077 | 98 | dst++; | |
| 1078 | 98 | src++; | |
| 1079 | // middle | ||
| 1080 |
2/2✓ Branch 6 → 5 taken 3696 times.
✓ Branch 6 → 7 taken 98 times.
|
3794 | for (size_t i = 1; i < w - 1; ++i) |
| 1081 | { | ||
| 1082 | 3696 | left = (src[0] << 1) | (src[1] >> (8 - 1)); | |
| 1083 | 3696 | right = (src[-1] << (8 - 1)) | (src[0] >> 1); | |
| 1084 | 3696 | *dst++ = left | right; | |
| 1085 | 3696 | src++; | |
| 1086 | } | ||
| 1087 | // rightmost | ||
| 1088 | 98 | left = (src[0] << 1) | 0; | |
| 1089 | 98 | right = (src[-1] << (8 - 1)) | (src[0] >> 1); | |
| 1090 | 98 | *dst = left | right; | |
| 1091 | }; | ||
| 1092 | |||
| 1093 | #if defined(_MSC_VER) && _MSC_VER < 1944 | ||
| 1094 | // MSVC's optimizer fail (as of 17.8.4, release, optimize for speed, SSE2) would | ||
| 1095 | // Workaround. Bad code generated. Compiler bug. | ||
| 1096 | // Fixed (said) in 17.9 preview 3 (_MSC_VER 1939) | ||
| 1097 | // Tested again in 17.14 (_MSC_VER 1944), it's OK. | ||
| 1098 | // https://developercommunity.visualstudio.com/t/Bad-c-codegen-in-1784-x64-unless-se/10565370 | ||
| 1099 | volatile uint8_t* src_prev; | ||
| 1100 | volatile uint8_t* src; | ||
| 1101 | #else | ||
| 1102 | uint8_t* src_prev; | ||
| 1103 | uint8_t* src; | ||
| 1104 | #endif | ||
| 1105 | uint8_t* src_next; | ||
| 1106 | uint8_t* dst; | ||
| 1107 | |||
| 1108 | uint8_t* tmp_line; | ||
| 1109 | 7 | uint8_t* prev_line_LR = buf1.data(); | |
| 1110 | 7 | uint8_t* curr_line_LR = buf2.data(); | |
| 1111 | 7 | uint8_t* next_line_LR = buf3.data(); | |
| 1112 | |||
| 1113 | // line 0, no previous line | ||
| 1114 | 7 | size_t y = 0; | |
| 1115 | 7 | dst = stringbitmap_outline[y].data(); | |
| 1116 | 7 | src = stringbitmap[y].data(); | |
| 1117 | 7 | src_next = stringbitmap[y + 1].data(); | |
| 1118 | 7 | make_dizzyLR(curr_line_LR, src, w); | |
| 1119 | 7 | make_dizzyLR(next_line_LR, src_next, w); | |
| 1120 |
2/2✓ Branch 30 → 29 taken 278 times.
✓ Branch 30 → 31 taken 7 times.
|
285 | for (size_t x = 0; x < w; x++) { |
| 1121 | 278 | dst[x] = (curr_line_LR[x] | next_line_LR[x] | src_next[x]) & ~src[x]; | |
| 1122 | } | ||
| 1123 | 7 | tmp_line = prev_line_LR; | |
| 1124 | 7 | prev_line_LR = curr_line_LR; | |
| 1125 | 7 | curr_line_LR = next_line_LR; | |
| 1126 | 7 | next_line_LR = tmp_line; | |
| 1127 | |||
| 1128 | 7 | src_prev = src; | |
| 1129 | 7 | src = src_next; | |
| 1130 | 7 | y++; | |
| 1131 | |||
| 1132 | // middle lines, y runs on 1..(h-2) | ||
| 1133 |
2/2✓ Branch 41 → 32 taken 84 times.
✓ Branch 41 → 42 taken 7 times.
|
91 | for (; y < h - 1; y++) |
| 1134 | { | ||
| 1135 | 84 | dst = stringbitmap_outline[y].data(); | |
| 1136 | 84 | src_next = stringbitmap[y + 1].data(); | |
| 1137 | 84 | make_dizzyLR(next_line_LR, src_next, w); | |
| 1138 |
2/2✓ Branch 39 → 38 taken 3336 times.
✓ Branch 39 → 40 taken 84 times.
|
3420 | for (size_t x = 0; x < w; x++) { |
| 1139 | 3336 | dst[x] = (prev_line_LR[x] | curr_line_LR[x] | next_line_LR[x] | src_prev[x] | src_next[x]) & ~src[x]; | |
| 1140 | } | ||
| 1141 | 84 | tmp_line = prev_line_LR; | |
| 1142 | 84 | prev_line_LR = curr_line_LR; | |
| 1143 | 84 | curr_line_LR = next_line_LR; | |
| 1144 | 84 | next_line_LR = tmp_line; | |
| 1145 | 84 | src_prev = src; | |
| 1146 | 84 | src = src_next; | |
| 1147 | } | ||
| 1148 | // last one, no next line | ||
| 1149 | 7 | dst = stringbitmap_outline[y].data(); | |
| 1150 |
2/2✓ Branch 46 → 45 taken 278 times.
✓ Branch 46 → 47 taken 7 times.
|
285 | for (size_t x = 0; x < w; x++) { |
| 1151 | 278 | dst[x] = (prev_line_LR[x] | curr_line_LR[x] | src_prev[x]) & ~src[x]; | |
| 1152 | } | ||
| 1153 | 7 | } | |
| 1154 | |||
| 1155 | 7 | PreRendered::PreRendered( | |
| 1156 | const uint8_t* fonts, | ||
| 1157 | const int fontline_bytes_storage, | ||
| 1158 | const int _vi_width, const int _vi_height, // from VideoInfo | ||
| 1159 | int _x, int _y, // they may change | ||
| 1160 | std::vector<int>& s, | ||
| 1161 | // each character can have different width, variable bbx.width is used instead of font-level constant FONT_WIDTH | ||
| 1162 | const std::vector<BBX>& bbx_array, | ||
| 1163 | int align, | ||
| 1164 | const bool _useHalocolor, | ||
| 1165 | |||
| 1166 | // Each character can have a different width; variable bbx.width is used instead of the font-level constant FONT_WIDTH. | ||
| 1167 | // | ||
| 1168 | // A BDF font can contain mixed sizes. The next two parameters (FONT_WIDTH, FONT_HEIGHT) represent the global maximum | ||
| 1169 | // font size. A font file may contain per-character widths and heights in bbx_array. | ||
| 1170 | // | ||
| 1171 | // Regarding the wider spacing in Unifont: | ||
| 1172 | // This is due to how FONTBOUNDINGBOX is interpreted during rendering. In Unifont's BDF header, FONTBOUNDINGBOX is set | ||
| 1173 | // to 16 pixels wide. In earlier versions of Avisynth, having a BDF header with FONTBOUNDINGBOX set to 16 pixels wide | ||
| 1174 | // globally caused all glyphs, regardless of their actual per-character width, to be rendered with 16-pixel spacing in | ||
| 1175 | // Avisynth's Text() function. This resulted in visible gaps for narrower, 8-pixel wide Latin characters. | ||
| 1176 | // | ||
| 1177 | // While Unifont is conceptually monospaced, it technically includes variable-width glyphs. | ||
| 1178 | // For example, Latin characters have DWIDTH 8, but others (like U+007F or CJK characters) use DWIDTH 16. | ||
| 1179 | // | ||
| 1180 | // Thus, the global FONTBOUNDINGBOX only specifies a maximum size for buffer allocation and must be 16 pixels wide. | ||
| 1181 | // In a fully BDF-compliant renderer, the per-character DWIDTH and BBX values can override the global bounding box | ||
| 1182 | // for spacing and alignment. | ||
| 1183 | // | ||
| 1184 | // Since Avisynth 3.7.6, the BDF renderer implements this override behavior. | ||
| 1185 | |||
| 1186 | const int FONT_WIDTH, const int FONT_HEIGHT, | ||
| 1187 | const int _safety_bits_x_left, | ||
| 1188 | const int _safety_bits_x_right | ||
| 1189 | 7 | ) | |
| 1190 | : | ||
| 1191 | 7 | useHalocolor(_useHalocolor), vi_width(_vi_width), vi_height(_vi_height), | |
| 1192 | 7 | safety_bits_x_left(_safety_bits_x_left), | |
| 1193 | 7 | safety_bits_x_right(_safety_bits_x_right) | |
| 1194 | { | ||
| 1195 | 7 | len = (int)s.size(); | |
| 1196 | 7 | x = _x; | |
| 1197 | 7 | y = _y; | |
| 1198 | 7 | xstart = 0; | |
| 1199 | 7 | ystart = 0; | |
| 1200 | 7 | yend = 0; | |
| 1201 | 7 | text_width = 0; | |
| 1202 | |||
| 1203 | 7 | int startindex = 0; | |
| 1204 | |||
| 1205 | // optional two additional lines for top and bottom for outline | ||
| 1206 |
1/2✓ Branch 5 → 6 taken 7 times.
✗ Branch 5 → 7 not taken.
|
7 | stringbitmap_height = useHalocolor ? FONT_HEIGHT + 2 : FONT_HEIGHT; |
| 1207 | |||
| 1208 | 7 | adjustWriteLimits(s, // s is modified in-place | |
| 1209 | bbx_array, // bounding boxes for each character | ||
| 1210 | 7 | vi_width, vi_height, | |
| 1211 | FONT_WIDTH, // not used, bbx_array contains per-character widths, but must be passed | ||
| 1212 | FONT_HEIGHT, // extra top and bottom for halo | ||
| 1213 | align, | ||
| 1214 | 7 | useHalocolor, | |
| 1215 | // adjusted parameters | ||
| 1216 |
1/2✓ Branch 8 → 9 taken 7 times.
✗ Branch 8 → 111 not taken.
|
7 | x, y, len, startindex, xstart, ystart, yend |
| 1217 | ); | ||
| 1218 | |||
| 1219 |
1/2✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 7 times.
|
7 | if (len <= 0) |
| 1220 | ✗ | return; | |
| 1221 | |||
| 1222 | // prepare font mask and outline mask | ||
| 1223 | |||
| 1224 | // instead of FONT_WIDTH * len we have to calculate the total width of the string dynamically, | ||
| 1225 | // because characters can have different widths, so we use bbx_array[s[i]].width | ||
| 1226 | 7 | int total_font_width = 0; | |
| 1227 |
2/2✓ Branch 15 → 12 taken 368 times.
✓ Branch 15 → 16 taken 7 times.
|
375 | for (int i = 0; i < len; i++) { |
| 1228 | // bbx_array is the array of bounding boxes for each character | ||
| 1229 | // s[i] is the index to the fontbitmap array | ||
| 1230 | // total_font_width += bbx_array[s[i]].width; | ||
| 1231 | 368 | total_font_width += bbx_array[s[i]].width; // this is the total width of the string | |
| 1232 | } | ||
| 1233 | |||
| 1234 | // left-right safety bits for horizontal subsampled cases | ||
| 1235 |
1/2✓ Branch 16 → 17 taken 7 times.
✗ Branch 16 → 18 not taken.
|
7 | const int stringbitmap_width = safety_bits_x_left + total_font_width + (useHalocolor ? 2 : 0) + safety_bits_x_right; |
| 1236 | 7 | const int stringbitmapline_bytes = (stringbitmap_width + 7) / 8; | |
| 1237 | |||
| 1238 | // allocate actual space | ||
| 1239 |
1/2✓ Branch 19 → 20 taken 7 times.
✗ Branch 19 → 111 not taken.
|
7 | stringbitmap.resize(stringbitmap_height); |
| 1240 |
3/4✓ Branch 24 → 25 taken 98 times.
✗ Branch 24 → 109 not taken.
✓ Branch 34 → 22 taken 98 times.
✓ Branch 34 → 35 taken 7 times.
|
210 | for (auto& subarray : stringbitmap) subarray.resize(stringbitmapline_bytes); |
| 1241 |
1/2✓ Branch 35 → 36 taken 7 times.
✗ Branch 35 → 53 not taken.
|
7 | if (useHalocolor) { |
| 1242 |
1/2✓ Branch 36 → 37 taken 7 times.
✗ Branch 36 → 111 not taken.
|
7 | stringbitmap_outline.resize(stringbitmap_height); |
| 1243 |
3/4✓ Branch 41 → 42 taken 98 times.
✗ Branch 41 → 110 not taken.
✓ Branch 51 → 39 taken 98 times.
✓ Branch 51 → 52 taken 7 times.
|
210 | for (auto& subarray : stringbitmap_outline) subarray.resize(stringbitmapline_bytes); |
| 1244 | } | ||
| 1245 | |||
| 1246 | // fill matrix with fonts | ||
| 1247 | // optionally leave spare left-right-top-bottom pixel lines for out-of-matrix halo pixels | ||
| 1248 | // plus a final zero-cost bit column for safely drawing unaligned horizontal subsampling cases | ||
| 1249 | 7 | uint8_t zerobyte[1] = { 0 }; | |
| 1250 | 7 | int bitcounter = 0; | |
| 1251 | |||
| 1252 | // safety columns for horizontal subsampling cases | ||
| 1253 | // fill another column with 0 | ||
| 1254 |
2/2✓ Branch 58 → 54 taken 98 times.
✓ Branch 58 → 59 taken 7 times.
|
105 | for (int ty = 0; ty < stringbitmap_height; ty++) { |
| 1255 | 98 | insert_from_msb_bit(&stringbitmap[ty][0], bitcounter, &zerobyte[0], 1, safety_bits_x_left); | |
| 1256 | } | ||
| 1257 | 7 | bitcounter += safety_bits_x_left; | |
| 1258 | |||
| 1259 |
1/2✓ Branch 59 → 60 taken 7 times.
✗ Branch 59 → 67 not taken.
|
7 | if (useHalocolor) { |
| 1260 | // fill leftmost 1 bitcolumn with 0 | ||
| 1261 |
2/2✓ Branch 65 → 61 taken 98 times.
✓ Branch 65 → 66 taken 7 times.
|
105 | for (int ty = 0; ty < stringbitmap_height; ty++) { |
| 1262 | 98 | uint8_t zerobyte[1] = { 0 }; | |
| 1263 | 98 | insert_from_msb_bit(&stringbitmap[ty][0], 0, &zerobyte[0], 1, 1); | |
| 1264 | } | ||
| 1265 | 7 | bitcounter++; | |
| 1266 | } | ||
| 1267 | |||
| 1268 | // if outline needed, leave place for top outline, copy actual character to the second row | ||
| 1269 |
1/2✓ Branch 67 → 68 taken 7 times.
✗ Branch 67 → 69 not taken.
|
7 | const int ypos_of_char_in_bitmap = useHalocolor ? 1 : 0; |
| 1270 | |||
| 1271 |
2/2✓ Branch 80 → 71 taken 368 times.
✓ Branch 80 → 81 taken 7 times.
|
375 | for (int i = 0; i < len; i++) { |
| 1272 | 368 | int num = s[i]; | |
| 1273 | 368 | int actual_font_width = bbx_array[num].width; // per character width, instead of font-level constant FONT_WIDTH; | |
| 1274 | 368 | const uint8_t* fontlinebuf = &fonts[num * FONT_HEIGHT * fontline_bytes_storage]; | |
| 1275 |
2/2✓ Branch 78 → 74 taken 4416 times.
✓ Branch 78 → 79 taken 368 times.
|
4784 | for (int ty = 0; ty < FONT_HEIGHT; ty++) { |
| 1276 | // stuff FONT_WIDTH bits from fontline into bitcounter_th bit of target line | ||
| 1277 | 4416 | insert_from_msb_bit(&stringbitmap[ty + ypos_of_char_in_bitmap][0], bitcounter, fontlinebuf, fontline_bytes_storage, actual_font_width); | |
| 1278 | 4416 | fontlinebuf += fontline_bytes_storage; | |
| 1279 | } | ||
| 1280 | 368 | bitcounter += actual_font_width; | |
| 1281 | } | ||
| 1282 |
1/2✓ Branch 81 → 82 taken 7 times.
✗ Branch 81 → 89 not taken.
|
7 | if (useHalocolor) { |
| 1283 | // fill rightmost 'safety_bits' bitcolumn with 0 | ||
| 1284 |
2/2✓ Branch 87 → 83 taken 98 times.
✓ Branch 87 → 88 taken 7 times.
|
105 | for (int ty = 0; ty < stringbitmap_height; ty++) { |
| 1285 | 98 | insert_from_msb_bit(&stringbitmap[ty][0], bitcounter, &zerobyte[0], 1, 1); | |
| 1286 | } | ||
| 1287 | 7 | bitcounter++; | |
| 1288 | } | ||
| 1289 | |||
| 1290 | // safety columns for horizontal subsampling cases | ||
| 1291 | // fill another column with 0 | ||
| 1292 |
2/2✓ Branch 94 → 90 taken 98 times.
✓ Branch 94 → 95 taken 7 times.
|
105 | for (int ty = 0; ty < stringbitmap_height; ty++) { |
| 1293 | 98 | insert_from_msb_bit(&stringbitmap[ty][0], bitcounter, &zerobyte[0], 1, safety_bits_x_right); | |
| 1294 | } | ||
| 1295 | 7 | bitcounter += safety_bits_x_right; | |
| 1296 | |||
| 1297 |
1/2✗ Branch 95 → 96 not taken.
✓ Branch 95 → 97 taken 7 times.
|
7 | assert(bitcounter == stringbitmap_width); |
| 1298 | |||
| 1299 |
1/2✓ Branch 97 → 98 taken 7 times.
✗ Branch 97 → 99 not taken.
|
7 | if (useHalocolor) |
| 1300 |
1/2✓ Branch 98 → 99 taken 7 times.
✗ Branch 98 → 111 not taken.
|
7 | make_outline(); |
| 1301 | |||
| 1302 | // recalculate the text width with assuming variable character widths | ||
| 1303 | |||
| 1304 | // actual visible pixel count | ||
| 1305 | // Instead of (len - 1) * FONT_WIDTH, we must calculate the text width based on the actual character widths | ||
| 1306 | 7 | text_width = total_font_width - xstart; | |
| 1307 |
2/2✓ Branch 99 → 100 taken 6 times.
✓ Branch 99 → 101 taken 1 time.
|
7 | if (x + text_width > vi_width) text_width -= (x + text_width - vi_width); |
| 1308 | |||
| 1309 |
1/2✓ Branch 101 → 102 taken 7 times.
✗ Branch 101 → 107 not taken.
|
7 | if (useHalocolor) { |
| 1310 | // x was calculated w/o the extra left-right padding | ||
| 1311 | 7 | xstart += 1; // worst case, skip leftmost extra halo column | |
| 1312 |
2/4✓ Branch 102 → 103 taken 7 times.
✗ Branch 102 → 105 not taken.
✓ Branch 103 → 104 taken 7 times.
✗ Branch 103 → 105 not taken.
|
7 | if (x + xstart - 1 >= 0 && x > 0) { |
| 1313 | 7 | x -= 1; | |
| 1314 | 7 | xstart -= 1; | |
| 1315 | 7 | text_width += 1; | |
| 1316 | } | ||
| 1317 | // still good an increased text_width for last halo column? | ||
| 1318 |
2/2✓ Branch 105 → 106 taken 1 time.
✓ Branch 105 → 107 taken 6 times.
|
7 | if (x + text_width + 1 < vi_width) |
| 1319 | 1 | text_width += 1; | |
| 1320 | } | ||
| 1321 | ✗ | } | |
| 1322 | |||
| 1323 | template<typename pixel_t> | ||
| 1324 | ✗ | static auto getHBDColor_UV(int color, int bits_per_pixel) | |
| 1325 | { | ||
| 1326 | ✗ | if (bits_per_pixel < 32) | |
| 1327 | ✗ | return (pixel_t)(color << (bits_per_pixel - 8)); | |
| 1328 | ✗ | constexpr float shift = 0.0f; | |
| 1329 | ✗ | return (pixel_t)((color - 128) / 255.0f + shift); | |
| 1330 | // FIXME: consistently using limited->fullscale conversion for float | ||
| 1331 | } | ||
| 1332 | |||
| 1333 | template<typename pixel_t> | ||
| 1334 | ✗ | static auto getHBDColor_Y(int color, int bits_per_pixel) | |
| 1335 | { | ||
| 1336 | ✗ | if (bits_per_pixel < 32) | |
| 1337 | ✗ | return (pixel_t)(color << (bits_per_pixel - 8)); | |
| 1338 | ✗ | return (pixel_t)(color / 255.0f); // 0..255 -> 0..1.0 | |
| 1339 | // FIXME: consistently using limited->fullscale conversion for float | ||
| 1340 | } | ||
| 1341 | |||
| 1342 | template<typename pixel_t> | ||
| 1343 | 42 | static auto getHBDColor_RGB(int color, int bits_per_pixel) | |
| 1344 | { | ||
| 1345 |
1/6auto getHBDColor_RGB<float>(int, int):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
auto getHBDColor_RGB<unsigned char>(int, int):
✓ Branch 2 → 3 taken 42 times.
✗ Branch 2 → 4 not taken.
auto getHBDColor_RGB<unsigned short>(int, int):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
|
42 | if (bits_per_pixel <= 16) { |
| 1346 | 42 | const int max_pixel_value = (1 << (bits_per_pixel & 31)) - 1; | |
| 1347 | 42 | return (pixel_t)((float)color * max_pixel_value / 255); // 0..255 --> 0..1023,4095,16383,65535 | |
| 1348 | } | ||
| 1349 | ✗ | return (pixel_t)(color / 255.0f); // 0..255 -> 0..1.0 | |
| 1350 | } | ||
| 1351 | |||
| 1352 | |||
| 1353 | template<typename pixel_t, bool useHalocolor, bool fadeBackground, bool isRGB> | ||
| 1354 | ✗ | void Render1by1Planes(int bits_per_pixel, int color, int halocolor, int* pitches, BYTE** dstps, PreRendered& pre, | |
| 1355 | const int planeCount, const bool is444) | ||
| 1356 | { | ||
| 1357 | // 1:1 planes, Y or planar RGB or 4:4:4 U/V | ||
| 1358 | |||
| 1359 | ✗ | int planes_y[4] = { PLANAR_Y, PLANAR_U, PLANAR_V, PLANAR_A }; | |
| 1360 | ✗ | int planes_r[4] = { PLANAR_G, PLANAR_B, PLANAR_R, PLANAR_A }; | |
| 1361 | ✗ | int* planes = isRGB ? planes_r : planes_y; | |
| 1362 | |||
| 1363 | ✗ | for (int p = 0; p < planeCount; p++) | |
| 1364 | { | ||
| 1365 | ✗ | const int plane = planes[p]; | |
| 1366 | |||
| 1367 | ✗ | if (!(isRGB || plane == PLANAR_Y || ((plane == PLANAR_U || plane == PLANAR_V) && is444))) | |
| 1368 | ✗ | continue; // Y, R, G, B is O.K. U, V is OK if 444 | |
| 1369 | |||
| 1370 | pixel_t val_color; | ||
| 1371 | pixel_t val_color_outline; | ||
| 1372 | |||
| 1373 | ✗ | const int planecolor = getColorForPlane(plane, color); | |
| 1374 | ✗ | const int planecolor_outline = getColorForPlane(plane, halocolor); | |
| 1375 | if (isRGB) { | ||
| 1376 | ✗ | val_color = getHBDColor_RGB<pixel_t>(planecolor, bits_per_pixel); | |
| 1377 | ✗ | val_color_outline = getHBDColor_RGB<pixel_t>(planecolor_outline, bits_per_pixel); | |
| 1378 | } | ||
| 1379 | ✗ | else if (plane == PLANAR_U || plane == PLANAR_V) { | |
| 1380 | ✗ | val_color = getHBDColor_UV<pixel_t>(planecolor, bits_per_pixel); | |
| 1381 | ✗ | val_color_outline = getHBDColor_UV<pixel_t>(planecolor_outline, bits_per_pixel); | |
| 1382 | } | ||
| 1383 | else {// Y | ||
| 1384 | ✗ | val_color = getHBDColor_Y<pixel_t>(planecolor, bits_per_pixel); | |
| 1385 | ✗ | val_color_outline = getHBDColor_Y<pixel_t>(planecolor_outline, bits_per_pixel); | |
| 1386 | } | ||
| 1387 | |||
| 1388 | ✗ | const int pitch = pitches[p]; | |
| 1389 | ✗ | BYTE* dstp = dstps[p] + pre.x * sizeof(pixel_t) + pre.y * pitch; | |
| 1390 | |||
| 1391 | // Start rendering | ||
| 1392 | ✗ | for (int ty = pre.ystart; ty < pre.yend; ty++) { | |
| 1393 | ✗ | pixel_t* _dstp = reinterpret_cast<pixel_t*>(dstp); | |
| 1394 | ✗ | uint8_t* fontline_ptr = pre.stringbitmap[ty].data(); | |
| 1395 | [[maybe_unused]] uint8_t* fontoutline_ptr; | ||
| 1396 | if constexpr(useHalocolor) | ||
| 1397 | ✗ | fontoutline_ptr = pre.stringbitmap_outline[ty].data(); | |
| 1398 | ✗ | int j = 0; | |
| 1399 | ✗ | const int shifted_xstart = pre.safety_bits_x_left + pre.xstart; | |
| 1400 | ✗ | for (int tx = shifted_xstart; tx < shifted_xstart + pre.text_width; tx++) | |
| 1401 | { | ||
| 1402 | ✗ | const bool lightIt = 0 != get_bit(fontline_ptr, tx); | |
| 1403 | ✗ | LightOnePixel<pixel_t, fadeBackground, isRGB>(lightIt, _dstp, j, val_color, bits_per_pixel); | |
| 1404 | if constexpr(useHalocolor) { | ||
| 1405 | ✗ | if (!lightIt) | |
| 1406 | { | ||
| 1407 | ✗ | const bool lightIt_outline = 0 != get_bit(fontoutline_ptr, tx); | |
| 1408 | ✗ | LightOnePixel<pixel_t, fadeBackground, isRGB>(lightIt_outline, _dstp, j, val_color_outline, bits_per_pixel); | |
| 1409 | } | ||
| 1410 | } | ||
| 1411 | ✗ | j += 1; | |
| 1412 | } | ||
| 1413 | ✗ | dstp += pitch; | |
| 1414 | } | ||
| 1415 | } | ||
| 1416 | ✗ | } | |
| 1417 | |||
| 1418 | template<typename pixel_t, bool useHalocolor, bool fadeBackground, int logXRatioUV, int logYRatioUV, ChromaLocationMode chromaMode> | ||
| 1419 | ✗ | void RenderUV(int bits_per_pixel, int color, int halocolor, int* pitches, BYTE** dstps, PreRendered& pre) | |
| 1420 | { | ||
| 1421 | // some optimization hint | ||
| 1422 | if constexpr (sizeof(pixel_t) == 1) | ||
| 1423 | ✗ | bits_per_pixel = 8; | |
| 1424 | else if constexpr (sizeof(pixel_t) == 4) | ||
| 1425 | ✗ | bits_per_pixel = 32; | |
| 1426 | |||
| 1427 | // draw U and V in one step | ||
| 1428 | ✗ | pixel_t color_u = getHBDColor_UV<pixel_t>(getColorForPlane(PLANAR_U, color), bits_per_pixel); | |
| 1429 | ✗ | pixel_t color_v = getHBDColor_UV<pixel_t>(getColorForPlane(PLANAR_V, color), bits_per_pixel); | |
| 1430 | ✗ | pixel_t color_outline_u = getHBDColor_UV<pixel_t>(getColorForPlane(PLANAR_U, halocolor), bits_per_pixel); | |
| 1431 | ✗ | pixel_t color_outline_v = getHBDColor_UV<pixel_t>(getColorForPlane(PLANAR_V, halocolor), bits_per_pixel); | |
| 1432 | |||
| 1433 | ✗ | const int pitchUV = pitches[1]; | |
| 1434 | ✗ | const int offset = (pre.x >> logXRatioUV) * sizeof(pixel_t) + (pre.y >> logYRatioUV) * pitchUV; | |
| 1435 | ✗ | BYTE* dstpU = dstps[1] + offset; | |
| 1436 | ✗ | BYTE* dstpV = dstps[2] + offset; | |
| 1437 | |||
| 1438 | // .SubS = 1, 2 or 4 | ||
| 1439 | ✗ | constexpr int xSubS = 1 << logXRatioUV; | |
| 1440 | ✗ | constexpr int ySubS = 1 << logYRatioUV; | |
| 1441 | |||
| 1442 | /* | ||
| 1443 | U and V handling, multiple luma/outline/background source for a given chroma point | ||
| 1444 | resulting chroma is a weighted sum of the three pixel kinds (font/outline/background) | ||
| 1445 | 012345678901 | ||
| 1446 | ...#OOO#.... | ||
| 1447 | ..#O###O#... | ||
| 1448 | ..#O#.#O#... | ||
| 1449 | ..#O#.#O#... | ||
| 1450 | ..#O#.#O#... | ||
| 1451 | */ | ||
| 1452 | |||
| 1453 | // unaligned x: for horizontal subsampling 420, 422 and 411: | ||
| 1454 | // 420, 422, 411 horizontal subsampling: one more loop because of the leftmost orphan pixel(s) | ||
| 1455 | // we can overaddress on the right, additional safety bit column(s) were added for the bitmap | ||
| 1456 | ✗ | const bool unaligned_x_start = logXRatioUV > 0 && 0 != pre.x % xSubS; | |
| 1457 | ✗ | const int xplus = unaligned_x_start ? xSubS : 0; // extra orphan bits affecting rightmost chroma | |
| 1458 | ✗ | const int xshift = pre.x % xSubS; // when aligned --> 0 | |
| 1459 | // unaligned y: vertical subsampling 420 | ||
| 1460 | ✗ | const bool odd_y_start = logYRatioUV == 1 && 0 != pre.y % 2; | |
| 1461 | ✗ | const int yshift = odd_y_start ? 1 : 0; | |
| 1462 | |||
| 1463 | ✗ | constexpr bool hasVerticalSubsample = logYRatioUV > 0; | |
| 1464 | |||
| 1465 | // safe zero array for vertical subsampled 4:2:0 case for orphan top/bottom | ||
| 1466 | ✗ | std::vector<uint8_t> zeros; | |
| 1467 | if constexpr (hasVerticalSubsample) | ||
| 1468 | ✗ | zeros.resize(pre.stringbitmap[0].size()); | |
| 1469 | |||
| 1470 | // second array element is only valid for vertically subsampled 4:2:0 | ||
| 1471 | ✗ | uint8_t* fontlines_ptr[2] = { nullptr }; | |
| 1472 | ✗ | uint8_t* fontoutlines_ptr[2] = { nullptr }; | |
| 1473 | |||
| 1474 | ✗ | for (int ty = pre.ystart; ty < pre.yend; ty += ySubS) { | |
| 1475 | |||
| 1476 | ✗ | pixel_t* _dstpU = reinterpret_cast<pixel_t*>(dstpU); | |
| 1477 | ✗ | pixel_t* _dstpV = reinterpret_cast<pixel_t*>(dstpV); | |
| 1478 | |||
| 1479 | ✗ | if (hasVerticalSubsample && odd_y_start && ty == pre.ystart) { | |
| 1480 | // top font line on odd y position + vertically subsampled (420) | ||
| 1481 | ✗ | fontlines_ptr[0] = zeros.data(); | |
| 1482 | ✗ | fontlines_ptr[1] = pre.stringbitmap[ty].data(); | |
| 1483 | ✗ | if constexpr(useHalocolor) { | |
| 1484 | ✗ | fontoutlines_ptr[0] = zeros.data(); | |
| 1485 | ✗ | fontoutlines_ptr[1] = pre.stringbitmap_outline[ty].data(); | |
| 1486 | } | ||
| 1487 | } | ||
| 1488 | ✗ | else if (hasVerticalSubsample && ty + 1 - yshift >= pre.stringbitmap_height) { | |
| 1489 | // bottom font line on even y position | ||
| 1490 | ✗ | fontlines_ptr[0] = pre.stringbitmap[ty - yshift].data(); | |
| 1491 | ✗ | fontlines_ptr[1] = zeros.data(); | |
| 1492 | if constexpr(useHalocolor) { | ||
| 1493 | ✗ | fontoutlines_ptr[0] = pre.stringbitmap_outline[ty - yshift].data(); | |
| 1494 | ✗ | fontoutlines_ptr[1] = zeros.data(); | |
| 1495 | } | ||
| 1496 | } | ||
| 1497 | else { | ||
| 1498 | // all font lines contributing to chroma can safely be used | ||
| 1499 | ✗ | for (int m = 0; m < ySubS; m++) | |
| 1500 | ✗ | fontlines_ptr[m] = pre.stringbitmap[ty + m - yshift].data(); | |
| 1501 | |||
| 1502 | if constexpr(useHalocolor) { | ||
| 1503 | ✗ | for (int m = 0; m < ySubS; m++) | |
| 1504 | ✗ | fontoutlines_ptr[m] = pre.stringbitmap_outline[ty + m - yshift].data(); | |
| 1505 | } | ||
| 1506 | } | ||
| 1507 | |||
| 1508 | // render a horizontal line | ||
| 1509 | ✗ | int j = 0; | |
| 1510 | // (pre.xstart - xshift) is always on horizontal subsample boundary | ||
| 1511 | ✗ | const int shifted_xstart = pre.safety_bits_x_left + pre.xstart - xshift; | |
| 1512 | |||
| 1513 | // left (mpeg2) location: | ||
| 1514 | ✗ | int fontpixels_right = 0; // used for left (mpeg2) chroma location case | |
| 1515 | ✗ | int halopixels_right = 0; | |
| 1516 | // For the very first chroma pixel there is no previous rightside. | ||
| 1517 | // Use index -1, safe because of safety columns | ||
| 1518 | if constexpr (chromaMode == LEFT_420 || chromaMode == LEFT_422) { | ||
| 1519 | ✗ | for (int yy = 0; yy < ySubS; yy++) { | |
| 1520 | ✗ | fontpixels_right += get_bits(fontlines_ptr[yy], shifted_xstart - 1, 1); | |
| 1521 | if constexpr (useHalocolor) | ||
| 1522 | ✗ | halopixels_right += get_bits(fontoutlines_ptr[yy], shifted_xstart - 1, 1); | |
| 1523 | } | ||
| 1524 | } | ||
| 1525 | |||
| 1526 | ✗ | for (int tx = shifted_xstart; tx < shifted_xstart + pre.text_width + xplus; tx += xSubS) { | |
| 1527 | ✗ | int fontpixels = 0; | |
| 1528 | ✗ | int halopixels = 0; | |
| 1529 | |||
| 1530 | // 411 | ||
| 1531 | // +------+------+------+------+ | ||
| 1532 | // | 0.25 | 0.25 | 0.25 | 0.25 | | ||
| 1533 | // +------+------+------+------+ | ||
| 1534 | // 420 center (mpeg1, jpeg) | ||
| 1535 | // +------+------+ | ||
| 1536 | // | 0.25 | 0.25 | | ||
| 1537 | // |------+------| | ||
| 1538 | // | 0.25 | 0.25 | | ||
| 1539 | // +------+------+ | ||
| 1540 | // 422 center | ||
| 1541 | // +------+------+ | ||
| 1542 | // | 0.5 | 0.5 | | ||
| 1543 | // +------+------+ | ||
| 1544 | // 420 left (mpeg2) | ||
| 1545 | // ------+------+-------+ | ||
| 1546 | // 0.125 | 0.25 | 0.125 | | ||
| 1547 | // ------|------+-------| | ||
| 1548 | // 0.125 | 0.25 | 0.125 | | ||
| 1549 | // ------+------+-------+ | ||
| 1550 | // 422 left (mpeg2) | ||
| 1551 | // ------+------+-------+ | ||
| 1552 | // 0.25 | 0.5 | 0.25 | | ||
| 1553 | // ------+------+-------+ | ||
| 1554 | |||
| 1555 | if constexpr (chromaMode == LEFT_420 || chromaMode == LEFT_422) { | ||
| 1556 | ✗ | int fontpixels_left = 0; | |
| 1557 | ✗ | int halopixels_left = 0; | |
| 1558 | ✗ | int fontpixels_mid = 0; | |
| 1559 | ✗ | int halopixels_mid = 0; | |
| 1560 | |||
| 1561 | // shift variables | ||
| 1562 | ✗ | fontpixels_left = fontpixels_right; | |
| 1563 | if constexpr (useHalocolor) | ||
| 1564 | ✗ | halopixels_left = halopixels_right; | |
| 1565 | // gather counts | ||
| 1566 | ✗ | fontpixels_mid = get_bits(fontlines_ptr[0], tx, 1); | |
| 1567 | ✗ | fontpixels_right = get_bits(fontlines_ptr[0], tx + 1, 1); | |
| 1568 | if constexpr (useHalocolor) { | ||
| 1569 | ✗ | halopixels_mid = get_bits(fontoutlines_ptr[0], tx, 1); | |
| 1570 | ✗ | halopixels_right = get_bits(fontoutlines_ptr[0], tx + 1, 1); | |
| 1571 | } | ||
| 1572 | if constexpr (chromaMode == LEFT_420) { | ||
| 1573 | ✗ | fontpixels_mid += get_bits(fontlines_ptr[1], tx, 1); | |
| 1574 | ✗ | fontpixels_right += get_bits(fontlines_ptr[1], tx + 1, 1); | |
| 1575 | if constexpr (useHalocolor) { | ||
| 1576 | ✗ | halopixels_mid += get_bits(fontoutlines_ptr[1], tx, 1); | |
| 1577 | ✗ | halopixels_right += get_bits(fontoutlines_ptr[1], tx + 1, 1); | |
| 1578 | } | ||
| 1579 | } | ||
| 1580 | // 1-2-1 weight | ||
| 1581 | ✗ | fontpixels = fontpixels_left + 2 * fontpixels_mid + fontpixels_right; | |
| 1582 | if constexpr (useHalocolor) | ||
| 1583 | ✗ | halopixels = halopixels_left + 2 * halopixels_mid + halopixels_right; | |
| 1584 | } | ||
| 1585 | else { | ||
| 1586 | // center, equal weights | ||
| 1587 | ✗ | for (int yy = 0; yy < ySubS; yy++) { | |
| 1588 | ✗ | fontpixels += get_bits(fontlines_ptr[yy], tx, xSubS); | |
| 1589 | if constexpr (useHalocolor) | ||
| 1590 | ✗ | halopixels += get_bits(fontoutlines_ptr[yy], tx, xSubS); | |
| 1591 | } | ||
| 1592 | } | ||
| 1593 | ✗ | LightOneUVPixel<pixel_t, logXRatioUV, logYRatioUV, fadeBackground, chromaMode>(_dstpU, j, _dstpV, | |
| 1594 | color_u, color_v, color_outline_u, color_outline_v, | ||
| 1595 | fontpixels, halopixels, | ||
| 1596 | bits_per_pixel | ||
| 1597 | ); | ||
| 1598 | |||
| 1599 | ✗ | j += 1; | |
| 1600 | } | ||
| 1601 | |||
| 1602 | ✗ | dstpU += pitchUV; | |
| 1603 | ✗ | dstpV += pitchUV; | |
| 1604 | } | ||
| 1605 | ✗ | } | |
| 1606 | |||
| 1607 | template<typename pixel_t, bool fadeBackground, bool isRGB> | ||
| 1608 | ✗ | void do_DrawStringPlanar( | |
| 1609 | const int width, const int height, BYTE** dstps, int* pitches, const int logXRatioUV, const int logYRatioUV, const int planeCount, | ||
| 1610 | int bits_per_pixel, | ||
| 1611 | const BitmapFont* bmfont, int x, int y, std::vector<int>& s, int color, int halocolor, int align, bool useHalocolor, int chromalocation) | ||
| 1612 | { | ||
| 1613 | // some optimization hint | ||
| 1614 | if constexpr (sizeof(pixel_t) == 1) | ||
| 1615 | ✗ | bits_per_pixel = 8; | |
| 1616 | else if constexpr (sizeof(pixel_t) == 4) | ||
| 1617 | ✗ | bits_per_pixel = 32; | |
| 1618 | |||
| 1619 | // Chroma 411 would require 3 extra bits on both left and right. | ||
| 1620 | // Chroma 420 and 422 need 1 bits on both left and right | ||
| 1621 | // Left (mpeg2) chroma placement (420, 422) requires an additional one on the left. | ||
| 1622 | ✗ | const bool isLeftStyleChromaLoc = (logXRatioUV == 1) && | |
| 1623 | ✗ | ((chromalocation == ChromaLocation_e::AVS_CHROMA_LEFT) || | |
| 1624 | ✗ | (chromalocation == ChromaLocation_e::AVS_CHROMA_TOP_LEFT) || // not supported yet; for the sake of completeness | |
| 1625 | (chromalocation == ChromaLocation_e::AVS_CHROMA_BOTTOM_LEFT)); // not supported yet; for the sake of completeness | ||
| 1626 | ✗ | const int safety_bits_x_left = (1 << logXRatioUV) - 1 + (isLeftStyleChromaLoc ? 1 : 0); | |
| 1627 | ✗ | const int safety_bits_x_right = (1 << logXRatioUV) - 1; | |
| 1628 | |||
| 1629 | ✗ | PreRendered pre(bmfont->font_bitmaps.data(), bmfont->fontline_bytes, width, height, x, y, s, bmfont->bbx_array, align, useHalocolor, | |
| 1630 | ✗ | bmfont->global_bbx.width, bmfont->global_bbx.height, safety_bits_x_left, safety_bits_x_right); | |
| 1631 | |||
| 1632 | ✗ | if (pre.len <= 0) | |
| 1633 | ✗ | return; | |
| 1634 | |||
| 1635 | ✗ | const bool is444 = !isRGB && (planeCount >= 3) && (logXRatioUV == 0) && (logYRatioUV == 0); | |
| 1636 | |||
| 1637 | ✗ | if (useHalocolor) | |
| 1638 | ✗ | Render1by1Planes<pixel_t, true, fadeBackground, isRGB>(bits_per_pixel, color, halocolor, pitches, dstps, pre, planeCount, is444); | |
| 1639 | else | ||
| 1640 | ✗ | Render1by1Planes<pixel_t, false, fadeBackground, isRGB>(bits_per_pixel, color, halocolor, pitches, dstps, pre, planeCount, is444); | |
| 1641 | |||
| 1642 | if constexpr (isRGB) | ||
| 1643 | ✗ | return; | |
| 1644 | |||
| 1645 | ✗ | if (is444) | |
| 1646 | ✗ | return; | |
| 1647 | |||
| 1648 | ✗ | if (planeCount < 3) | |
| 1649 | ✗ | return; // Y | |
| 1650 | |||
| 1651 | // Subsampled cases, templates help a lot | ||
| 1652 | // for 420 and 422 center and left supported only, what is not "center", we do the "left" method | ||
| 1653 | ✗ | if (logXRatioUV == 2 && logYRatioUV == 0) {// 411 | |
| 1654 | // ignore chromalocation | ||
| 1655 | ✗ | if (useHalocolor) | |
| 1656 | ✗ | RenderUV<pixel_t, true, fadeBackground, 2, 0, ChromaLocationMode::CENTER_411>(bits_per_pixel, color, halocolor, pitches, dstps, pre); | |
| 1657 | else | ||
| 1658 | ✗ | RenderUV<pixel_t, false, fadeBackground, 2, 0, ChromaLocationMode::CENTER_411>(bits_per_pixel, color, halocolor, pitches, dstps, pre); | |
| 1659 | } | ||
| 1660 | ✗ | else if (logXRatioUV == 1 && logYRatioUV == 0) { | |
| 1661 | ✗ | if (chromalocation == ChromaLocation_e::AVS_CHROMA_CENTER) { | |
| 1662 | ✗ | if (useHalocolor) | |
| 1663 | ✗ | RenderUV<pixel_t, true, fadeBackground, 1, 0, ChromaLocationMode::CENTER_422>(bits_per_pixel, color, halocolor, pitches, dstps, pre); | |
| 1664 | else | ||
| 1665 | ✗ | RenderUV<pixel_t, false, fadeBackground, 1, 0, ChromaLocationMode::CENTER_422>(bits_per_pixel, color, halocolor, pitches, dstps, pre); | |
| 1666 | } | ||
| 1667 | else { | ||
| 1668 | ✗ | if (useHalocolor) | |
| 1669 | ✗ | RenderUV<pixel_t, true, fadeBackground, 1, 0, ChromaLocationMode::LEFT_422>(bits_per_pixel, color, halocolor, pitches, dstps, pre); | |
| 1670 | else | ||
| 1671 | ✗ | RenderUV<pixel_t, false, fadeBackground, 1, 0, ChromaLocationMode::LEFT_422>(bits_per_pixel, color, halocolor, pitches, dstps, pre); | |
| 1672 | } | ||
| 1673 | } | ||
| 1674 | ✗ | else if (logXRatioUV == 1 && logYRatioUV == 1) { | |
| 1675 | ✗ | if (chromalocation == ChromaLocation_e::AVS_CHROMA_CENTER) { | |
| 1676 | ✗ | if (useHalocolor) | |
| 1677 | ✗ | RenderUV<pixel_t, true, fadeBackground, 1, 1, ChromaLocationMode::CENTER_420>(bits_per_pixel, color, halocolor, pitches, dstps, pre); | |
| 1678 | else | ||
| 1679 | ✗ | RenderUV<pixel_t, false, fadeBackground, 1, 1, ChromaLocationMode::CENTER_420>(bits_per_pixel, color, halocolor, pitches, dstps, pre); | |
| 1680 | } | ||
| 1681 | else { | ||
| 1682 | ✗ | if (useHalocolor) | |
| 1683 | ✗ | RenderUV<pixel_t, true, fadeBackground, 1, 1, ChromaLocationMode::LEFT_420>(bits_per_pixel, color, halocolor, pitches, dstps, pre); | |
| 1684 | else | ||
| 1685 | ✗ | RenderUV<pixel_t, false, fadeBackground, 1, 1, ChromaLocationMode::LEFT_420>(bits_per_pixel, color, halocolor, pitches, dstps, pre); | |
| 1686 | |||
| 1687 | } | ||
| 1688 | } | ||
| 1689 | else | ||
| 1690 | ✗ | assert(0); | |
| 1691 | ✗ | } | |
| 1692 | |||
| 1693 | template<bool useHalocolor, bool fadeBackground, ChromaLocationMode chromaMode> | ||
| 1694 | ✗ | void RenderYUY2(int color, int halocolor, int pitch, BYTE* _dstp, PreRendered& pre) | |
| 1695 | { | ||
| 1696 | ✗ | BYTE* dstp = _dstp + pre.x * 2 + pre.y * pitch; | |
| 1697 | ✗ | BYTE* dstpUV = _dstp + (pre.x / 2) * 4 + 1 + pre.y * pitch; // always points to U of a YUYV block | |
| 1698 | |||
| 1699 | typedef uint8_t pixel_t; | ||
| 1700 | |||
| 1701 | ✗ | pixel_t val_color = getColorForPlane(PLANAR_Y, color); | |
| 1702 | ✗ | pixel_t val_color_outline = getColorForPlane(PLANAR_Y, halocolor); | |
| 1703 | ✗ | pixel_t color_u = getColorForPlane(PLANAR_U, color); | |
| 1704 | ✗ | pixel_t color_outline_u = getColorForPlane(PLANAR_U, halocolor); | |
| 1705 | ✗ | pixel_t color_v = getColorForPlane(PLANAR_V, color); | |
| 1706 | ✗ | pixel_t color_outline_v = getColorForPlane(PLANAR_V, halocolor); | |
| 1707 | |||
| 1708 | // YUY2 like 422 | ||
| 1709 | ✗ | constexpr int logXRatioUV = 1; | |
| 1710 | ✗ | constexpr int logYRatioUV = 0; | |
| 1711 | ✗ | constexpr int xSubS = 2; | |
| 1712 | |||
| 1713 | // unaligned x: for horizontal subsampling 420, 422 (YUY2) and 411: | ||
| 1714 | // 420, 422, 411, YUY2 horizontal subsampling: one more loop because of the leftmost orphan pixel(s) | ||
| 1715 | // we can overaddress on the right, additional safety bit column(s) were added for the bitmap | ||
| 1716 | ✗ | const bool unaligned_x_start = 0 != pre.x % xSubS; | |
| 1717 | ✗ | const int xplus = unaligned_x_start ? xSubS : 0; // extra orphan bits affecting rightmost chroma | |
| 1718 | ✗ | const int xshift = pre.x % xSubS; // when aligned --> 0 | |
| 1719 | |||
| 1720 | ✗ | for (int ty = pre.ystart; ty < pre.yend; ty++) { | |
| 1721 | ✗ | BYTE* dp = dstp; | |
| 1722 | ✗ | BYTE* dpUV = dstpUV; | |
| 1723 | ✗ | uint8_t* fontline_ptr = pre.stringbitmap[ty].data(); | |
| 1724 | [[maybe_unused]] uint8_t* fontoutline_ptr; | ||
| 1725 | if constexpr (useHalocolor) | ||
| 1726 | ✗ | fontoutline_ptr = pre.stringbitmap_outline[ty].data(); | |
| 1727 | |||
| 1728 | // first Y, like in 4:4:4 | ||
| 1729 | ✗ | int j = 0; | |
| 1730 | ✗ | int shifted_xstart = pre.safety_bits_x_left + pre.xstart; | |
| 1731 | ✗ | for (int tx = shifted_xstart; tx < shifted_xstart + pre.text_width; tx++) { | |
| 1732 | ✗ | const bool lightIt = 0 != get_bit(fontline_ptr, tx); | |
| 1733 | ✗ | LightOnePixel<uint8_t, fadeBackground, false>(lightIt, dp, j, val_color, 8); | |
| 1734 | if constexpr (useHalocolor) { | ||
| 1735 | ✗ | if (!lightIt) | |
| 1736 | { | ||
| 1737 | ✗ | const bool lightIt_outline = 0 != get_bit(fontoutline_ptr, tx); | |
| 1738 | ✗ | LightOnePixel<uint8_t, fadeBackground, false>(lightIt_outline, dp, j, val_color_outline, 8); | |
| 1739 | } | ||
| 1740 | } | ||
| 1741 | ✗ | j += 2; // next Y | |
| 1742 | } | ||
| 1743 | |||
| 1744 | // then chroma | ||
| 1745 | ✗ | j = 0; | |
| 1746 | // (pre.xstart - xshift) is always on horizontal subsample boundary | ||
| 1747 | ✗ | shifted_xstart = pre.safety_bits_x_left + pre.xstart - xshift; | |
| 1748 | |||
| 1749 | // left (mpeg2) location: | ||
| 1750 | ✗ | int fontpixels_right = 0; // used for left (mpeg2) chroma location case | |
| 1751 | ✗ | int halopixels_right = 0; | |
| 1752 | // For the very first chroma pixel there is no previous rightside. | ||
| 1753 | // Use index -1, safe because of safety columns | ||
| 1754 | if constexpr (chromaMode == LEFT_422) { | ||
| 1755 | ✗ | fontpixels_right = get_bits(fontline_ptr, shifted_xstart - 1, 1); | |
| 1756 | if constexpr (useHalocolor) | ||
| 1757 | ✗ | halopixels_right = get_bits(fontoutline_ptr, shifted_xstart - 1, 1); | |
| 1758 | } | ||
| 1759 | |||
| 1760 | ✗ | for (int tx = shifted_xstart; tx < shifted_xstart + pre.text_width + xplus; tx += xSubS) { | |
| 1761 | ✗ | int fontpixels = 0; | |
| 1762 | ✗ | int halopixels = 0; | |
| 1763 | // 422 center (mpeg1, jpeg) | ||
| 1764 | // +------+------+ | ||
| 1765 | // | 0.5 | 0.5 | | ||
| 1766 | // +------+------+ | ||
| 1767 | // 422 left (mpeg2) | ||
| 1768 | // ------+------+-------+ | ||
| 1769 | // 0.25 | 0.5 | 0.25 | | ||
| 1770 | // ------+------+-------+ | ||
| 1771 | |||
| 1772 | if constexpr (chromaMode == LEFT_422) { | ||
| 1773 | ✗ | int fontpixels_left = 0; | |
| 1774 | ✗ | int halopixels_left = 0; | |
| 1775 | ✗ | int fontpixels_mid = 0; | |
| 1776 | ✗ | int halopixels_mid = 0; | |
| 1777 | |||
| 1778 | // shift variables | ||
| 1779 | ✗ | fontpixels_left = fontpixels_right; | |
| 1780 | if constexpr (useHalocolor) | ||
| 1781 | ✗ | halopixels_left = halopixels_right; | |
| 1782 | // gather counts | ||
| 1783 | ✗ | fontpixels_mid = get_bits(fontline_ptr, tx, 1); | |
| 1784 | ✗ | fontpixels_right = get_bits(fontline_ptr, tx + 1, 1); | |
| 1785 | if constexpr (useHalocolor) { | ||
| 1786 | ✗ | halopixels_mid = get_bits(fontoutline_ptr, tx, 1); | |
| 1787 | ✗ | halopixels_right = get_bits(fontoutline_ptr, tx + 1, 1); | |
| 1788 | } | ||
| 1789 | // 1-2-1 weight | ||
| 1790 | ✗ | fontpixels = fontpixels_left + 2 * fontpixels_mid + fontpixels_right; | |
| 1791 | if constexpr (useHalocolor) | ||
| 1792 | ✗ | halopixels = halopixels_left + 2 * halopixels_mid + halopixels_right; | |
| 1793 | } | ||
| 1794 | else { | ||
| 1795 | // center, equal weights | ||
| 1796 | ✗ | fontpixels += get_bits(fontline_ptr, tx, xSubS); | |
| 1797 | if constexpr (useHalocolor) | ||
| 1798 | ✗ | halopixels += get_bits(fontoutline_ptr, tx, xSubS); | |
| 1799 | } | ||
| 1800 | |||
| 1801 | ✗ | LightOneUVPixel<uint8_t, logXRatioUV, logYRatioUV, fadeBackground, chromaMode>(dpUV /*U*/, j, dpUV + 2 /*V*/, | |
| 1802 | color_u, color_v, color_outline_u, color_outline_v, | ||
| 1803 | fontpixels, halopixels, | ||
| 1804 | 8 | ||
| 1805 | ); | ||
| 1806 | ✗ | j += 4; // YUYV | |
| 1807 | } | ||
| 1808 | |||
| 1809 | ✗ | dstp += pitch; | |
| 1810 | ✗ | dstpUV += pitch; | |
| 1811 | } | ||
| 1812 | ✗ | } | |
| 1813 | |||
| 1814 | template<bool fadeBackground> | ||
| 1815 | ✗ | static void do_DrawStringYUY2( | |
| 1816 | const int width, const int height, BYTE* _dstp, int pitch, const BitmapFont* bmfont, int x, int y, std::vector<int>& s, | ||
| 1817 | int color, int halocolor, int align, bool useHalocolor, int chromalocation) | ||
| 1818 | { | ||
| 1819 | ✗ | const bool isLeftStyleChromaLoc = chromalocation == ChromaLocation_e::AVS_CHROMA_LEFT; | |
| 1820 | // Like 422. Chroma subsampling would require 1 extra bit playground on both left and right | ||
| 1821 | ✗ | const int safety_bits_x_left = 1 + (isLeftStyleChromaLoc ? 1 : 0); | |
| 1822 | ✗ | const int safety_bits_x_right = 1; | |
| 1823 | |||
| 1824 | ✗ | PreRendered pre(bmfont->font_bitmaps.data(), bmfont->fontline_bytes, width, height, x, y, s, bmfont->bbx_array, align, useHalocolor, | |
| 1825 | ✗ | bmfont->global_bbx.width, bmfont->global_bbx.height, | |
| 1826 | safety_bits_x_left, safety_bits_x_right); | ||
| 1827 | |||
| 1828 | ✗ | if (pre.len <= 0) | |
| 1829 | ✗ | return; | |
| 1830 | |||
| 1831 | ✗ | if (useHalocolor) { | |
| 1832 | ✗ | if (chromalocation == ChromaLocation_e::AVS_CHROMA_CENTER) | |
| 1833 | ✗ | RenderYUY2<true, fadeBackground, ChromaLocationMode::CENTER_422>(color, halocolor, pitch, _dstp, pre); | |
| 1834 | else | ||
| 1835 | ✗ | RenderYUY2<true, fadeBackground, ChromaLocationMode::LEFT_422>(color, halocolor, pitch, _dstp, pre); | |
| 1836 | } | ||
| 1837 | else { | ||
| 1838 | ✗ | if (chromalocation == ChromaLocation_e::AVS_CHROMA_CENTER) | |
| 1839 | ✗ | RenderYUY2<false, fadeBackground, ChromaLocationMode::CENTER_422>(color, halocolor, pitch, _dstp, pre); | |
| 1840 | else | ||
| 1841 | ✗ | RenderYUY2<false, fadeBackground, ChromaLocationMode::LEFT_422>(color, halocolor, pitch, _dstp, pre); | |
| 1842 | } | ||
| 1843 | ✗ | } | |
| 1844 | |||
| 1845 | template<typename pixel_t, bool useHalocolor, bool fadeBackground, int rgbstep> | ||
| 1846 | 7 | static void RenderPackedRGB(int color, int halocolor, BYTE* _dstp, int pitch, int height, PreRendered& pre) | |
| 1847 | { | ||
| 1848 | // packed: only 8 and 16 bits | ||
| 1849 | 7 | int bits_per_pixel = 0; | |
| 1850 | if constexpr (sizeof(pixel_t) == 1) | ||
| 1851 | 7 | bits_per_pixel = 8; | |
| 1852 | else if constexpr (sizeof(pixel_t) == 2) | ||
| 1853 | ✗ | bits_per_pixel = 16; | |
| 1854 | |||
| 1855 | 7 | const int val_color_R = getHBDColor_RGB<pixel_t>(getColorForPlane(PLANAR_R, color), bits_per_pixel); | |
| 1856 | 7 | const int val_color_R_outline = getHBDColor_RGB<pixel_t>(getColorForPlane(PLANAR_R, halocolor), bits_per_pixel); | |
| 1857 | 7 | const int val_color_G = getHBDColor_RGB<pixel_t>(getColorForPlane(PLANAR_G, color), bits_per_pixel); | |
| 1858 | 7 | const int val_color_G_outline = getHBDColor_RGB<pixel_t>(getColorForPlane(PLANAR_G, halocolor), bits_per_pixel); | |
| 1859 | 7 | const int val_color_B = getHBDColor_RGB<pixel_t>(getColorForPlane(PLANAR_B, color), bits_per_pixel); | |
| 1860 | 7 | const int val_color_B_outline = getHBDColor_RGB<pixel_t>(getColorForPlane(PLANAR_B, halocolor), bits_per_pixel); | |
| 1861 | |||
| 1862 | // upside down | ||
| 1863 | 7 | BYTE* dstp = _dstp + pre.x * rgbstep + (height - 1 - pre.y) * pitch; | |
| 1864 | |||
| 1865 | // Start rendering | ||
| 1866 |
2/32void RenderPackedRGB<unsigned char, false, false, 3>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 25 → 15 not taken.
✗ Branch 25 → 26 not taken.
void RenderPackedRGB<unsigned char, false, false, 4>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 25 → 15 not taken.
✗ Branch 25 → 26 not taken.
void RenderPackedRGB<unsigned char, false, true, 3>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 26 → 15 not taken.
✗ Branch 26 → 27 not taken.
void RenderPackedRGB<unsigned char, false, true, 4>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 26 → 15 not taken.
✗ Branch 26 → 27 not taken.
void RenderPackedRGB<unsigned char, true, false, 3>(int, int, unsigned char*, int, int, PreRendered&):
✓ Branch 33 → 15 taken 98 times.
✓ Branch 33 → 34 taken 7 times.
void RenderPackedRGB<unsigned char, true, false, 4>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 33 → 15 not taken.
✗ Branch 33 → 34 not taken.
void RenderPackedRGB<unsigned char, true, true, 3>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 35 → 15 not taken.
✗ Branch 35 → 36 not taken.
void RenderPackedRGB<unsigned char, true, true, 4>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 35 → 15 not taken.
✗ Branch 35 → 36 not taken.
void RenderPackedRGB<unsigned short, false, false, 6>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 25 → 15 not taken.
✗ Branch 25 → 26 not taken.
void RenderPackedRGB<unsigned short, false, false, 8>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 25 → 15 not taken.
✗ Branch 25 → 26 not taken.
void RenderPackedRGB<unsigned short, false, true, 6>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 26 → 15 not taken.
✗ Branch 26 → 27 not taken.
void RenderPackedRGB<unsigned short, false, true, 8>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 26 → 15 not taken.
✗ Branch 26 → 27 not taken.
void RenderPackedRGB<unsigned short, true, false, 6>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 33 → 15 not taken.
✗ Branch 33 → 34 not taken.
void RenderPackedRGB<unsigned short, true, false, 8>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 33 → 15 not taken.
✗ Branch 33 → 34 not taken.
void RenderPackedRGB<unsigned short, true, true, 6>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 35 → 15 not taken.
✗ Branch 35 → 36 not taken.
void RenderPackedRGB<unsigned short, true, true, 8>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 35 → 15 not taken.
✗ Branch 35 → 36 not taken.
|
105 | for (int ty = pre.ystart; ty < pre.yend; ty++) { |
| 1867 | 98 | uint8_t* dp = dstp; | |
| 1868 | 98 | uint8_t* fontline_ptr = pre.stringbitmap[ty].data(); | |
| 1869 | [[maybe_unused]] uint8_t* fontoutline_ptr; | ||
| 1870 | if constexpr(useHalocolor) | ||
| 1871 | 98 | fontoutline_ptr = pre.stringbitmap_outline[ty].data(); | |
| 1872 | |||
| 1873 | 98 | const int shifted_xstart = pre.safety_bits_x_left + pre.xstart; // though safety bit count must be 0 here | |
| 1874 |
2/32void RenderPackedRGB<unsigned char, false, false, 3>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 23 → 18 not taken.
✗ Branch 23 → 24 not taken.
void RenderPackedRGB<unsigned char, false, false, 4>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 23 → 18 not taken.
✗ Branch 23 → 24 not taken.
void RenderPackedRGB<unsigned char, false, true, 3>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 24 → 18 not taken.
✗ Branch 24 → 25 not taken.
void RenderPackedRGB<unsigned char, false, true, 4>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 24 → 18 not taken.
✗ Branch 24 → 25 not taken.
void RenderPackedRGB<unsigned char, true, false, 3>(int, int, unsigned char*, int, int, PreRendered&):
✓ Branch 31 → 20 taken 30856 times.
✓ Branch 31 → 32 taken 98 times.
void RenderPackedRGB<unsigned char, true, false, 4>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 31 → 20 not taken.
✗ Branch 31 → 32 not taken.
void RenderPackedRGB<unsigned char, true, true, 3>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 33 → 20 not taken.
✗ Branch 33 → 34 not taken.
void RenderPackedRGB<unsigned char, true, true, 4>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 33 → 20 not taken.
✗ Branch 33 → 34 not taken.
void RenderPackedRGB<unsigned short, false, false, 6>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 23 → 18 not taken.
✗ Branch 23 → 24 not taken.
void RenderPackedRGB<unsigned short, false, false, 8>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 23 → 18 not taken.
✗ Branch 23 → 24 not taken.
void RenderPackedRGB<unsigned short, false, true, 6>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 24 → 18 not taken.
✗ Branch 24 → 25 not taken.
void RenderPackedRGB<unsigned short, false, true, 8>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 24 → 18 not taken.
✗ Branch 24 → 25 not taken.
void RenderPackedRGB<unsigned short, true, false, 6>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 31 → 20 not taken.
✗ Branch 31 → 32 not taken.
void RenderPackedRGB<unsigned short, true, false, 8>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 31 → 20 not taken.
✗ Branch 31 → 32 not taken.
void RenderPackedRGB<unsigned short, true, true, 6>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 33 → 20 not taken.
✗ Branch 33 → 34 not taken.
void RenderPackedRGB<unsigned short, true, true, 8>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 33 → 20 not taken.
✗ Branch 33 → 34 not taken.
|
30954 | for (int tx = shifted_xstart; tx < shifted_xstart + pre.text_width; tx++) |
| 1875 | { | ||
| 1876 | 30856 | const bool lightIt = 0 != get_bit(fontline_ptr, tx); | |
| 1877 |
2/32void RenderPackedRGB<unsigned char, false, false, 3>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 21 not taken.
void RenderPackedRGB<unsigned char, false, false, 4>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 21 not taken.
void RenderPackedRGB<unsigned char, false, true, 3>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 21 not taken.
void RenderPackedRGB<unsigned char, false, true, 4>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 21 not taken.
void RenderPackedRGB<unsigned char, true, false, 3>(int, int, unsigned char*, int, int, PreRendered&):
✓ Branch 21 → 22 taken 2285 times.
✓ Branch 21 → 23 taken 28571 times.
void RenderPackedRGB<unsigned char, true, false, 4>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 23 not taken.
void RenderPackedRGB<unsigned char, true, true, 3>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 23 not taken.
void RenderPackedRGB<unsigned char, true, true, 4>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 23 not taken.
void RenderPackedRGB<unsigned short, false, false, 6>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 21 not taken.
void RenderPackedRGB<unsigned short, false, false, 8>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 21 not taken.
void RenderPackedRGB<unsigned short, false, true, 6>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 21 not taken.
void RenderPackedRGB<unsigned short, false, true, 8>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 21 not taken.
void RenderPackedRGB<unsigned short, true, false, 6>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 23 not taken.
void RenderPackedRGB<unsigned short, true, false, 8>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 23 not taken.
void RenderPackedRGB<unsigned short, true, true, 6>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 23 not taken.
void RenderPackedRGB<unsigned short, true, true, 8>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 23 not taken.
|
30856 | LightOnePixelPackedRGB<pixel_t, fadeBackground>(lightIt, dp, val_color_R, val_color_G, val_color_B); |
| 1878 | if constexpr(useHalocolor) { | ||
| 1879 |
2/16void RenderPackedRGB<unsigned char, true, false, 3>(int, int, unsigned char*, int, int, PreRendered&):
✓ Branch 24 → 25 taken 28571 times.
✓ Branch 24 → 30 taken 2285 times.
void RenderPackedRGB<unsigned char, true, false, 4>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 30 not taken.
void RenderPackedRGB<unsigned char, true, true, 3>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 32 not taken.
void RenderPackedRGB<unsigned char, true, true, 4>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 32 not taken.
void RenderPackedRGB<unsigned short, true, false, 6>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 30 not taken.
void RenderPackedRGB<unsigned short, true, false, 8>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 30 not taken.
void RenderPackedRGB<unsigned short, true, true, 6>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 32 not taken.
void RenderPackedRGB<unsigned short, true, true, 8>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 32 not taken.
|
30856 | if (!lightIt) { |
| 1880 | 28571 | const bool lightIt_outline = 0 != get_bit(fontoutline_ptr, tx); | |
| 1881 |
2/16void RenderPackedRGB<unsigned char, true, false, 3>(int, int, unsigned char*, int, int, PreRendered&):
✓ Branch 26 → 27 taken 5617 times.
✓ Branch 26 → 28 taken 22954 times.
void RenderPackedRGB<unsigned char, true, false, 4>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 28 not taken.
void RenderPackedRGB<unsigned char, true, true, 3>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 29 not taken.
void RenderPackedRGB<unsigned char, true, true, 4>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 29 not taken.
void RenderPackedRGB<unsigned short, true, false, 6>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 28 not taken.
void RenderPackedRGB<unsigned short, true, false, 8>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 28 not taken.
void RenderPackedRGB<unsigned short, true, true, 6>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 29 not taken.
void RenderPackedRGB<unsigned short, true, true, 8>(int, int, unsigned char*, int, int, PreRendered&):
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 29 not taken.
|
28571 | LightOnePixelPackedRGB<pixel_t, fadeBackground>(lightIt_outline, dp, val_color_R_outline, val_color_G_outline, val_color_B_outline); |
| 1882 | } | ||
| 1883 | } | ||
| 1884 | 30856 | dp += rgbstep; | |
| 1885 | } | ||
| 1886 | 98 | dstp -= pitch; | |
| 1887 | } | ||
| 1888 | 7 | } | |
| 1889 | |||
| 1890 | template<typename pixel_t, int rgbstep, bool fadeBackground> | ||
| 1891 | 7 | static void do_DrawStringPackedRGB( | |
| 1892 | const int width, const int height, BYTE* _dstp, int pitch, | ||
| 1893 | const BitmapFont* bmfont, int x, int y, std::vector<int>& s, int color, int halocolor, int align, bool useHalocolor) | ||
| 1894 | { | ||
| 1895 | 7 | const int safety_bits_x_left = 0; // no horizontal subsampling | |
| 1896 | 7 | const int safety_bits_x_right = 0; // no horizontal subsampling | |
| 1897 |
1/16void do_DrawStringPackedRGB<unsigned char, 3, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✓ Branch 3 → 4 taken 7 times.
✗ Branch 3 → 18 not taken.
void do_DrawStringPackedRGB<unsigned char, 3, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 18 not taken.
void do_DrawStringPackedRGB<unsigned char, 4, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 18 not taken.
void do_DrawStringPackedRGB<unsigned char, 4, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 18 not taken.
void do_DrawStringPackedRGB<unsigned short, 6, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 18 not taken.
void do_DrawStringPackedRGB<unsigned short, 6, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 18 not taken.
void do_DrawStringPackedRGB<unsigned short, 8, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 18 not taken.
void do_DrawStringPackedRGB<unsigned short, 8, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 18 not taken.
|
7 | PreRendered pre(bmfont->font_bitmaps.data(), bmfont->fontline_bytes, width, height, x, y, s, bmfont->bbx_array, align, useHalocolor, |
| 1898 | 7 | bmfont->global_bbx.width, bmfont->global_bbx.height, | |
| 1899 | safety_bits_x_left, safety_bits_x_right); | ||
| 1900 | |||
| 1901 |
1/16void do_DrawStringPackedRGB<unsigned char, 3, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 7 times.
void do_DrawStringPackedRGB<unsigned char, 3, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
void do_DrawStringPackedRGB<unsigned char, 4, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
void do_DrawStringPackedRGB<unsigned char, 4, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
void do_DrawStringPackedRGB<unsigned short, 6, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
void do_DrawStringPackedRGB<unsigned short, 6, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
void do_DrawStringPackedRGB<unsigned short, 8, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
void do_DrawStringPackedRGB<unsigned short, 8, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
|
7 | if (pre.len <= 0) |
| 1902 | ✗ | return; | |
| 1903 | |||
| 1904 |
1/16void do_DrawStringPackedRGB<unsigned char, 3, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✓ Branch 6 → 7 taken 7 times.
✗ Branch 6 → 8 not taken.
void do_DrawStringPackedRGB<unsigned char, 3, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
void do_DrawStringPackedRGB<unsigned char, 4, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
void do_DrawStringPackedRGB<unsigned char, 4, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
void do_DrawStringPackedRGB<unsigned short, 6, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
void do_DrawStringPackedRGB<unsigned short, 6, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
void do_DrawStringPackedRGB<unsigned short, 8, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
void do_DrawStringPackedRGB<unsigned short, 8, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
|
7 | if (useHalocolor) |
| 1905 |
1/16void do_DrawStringPackedRGB<unsigned char, 3, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✓ Branch 7 → 9 taken 7 times.
✗ Branch 7 → 16 not taken.
void do_DrawStringPackedRGB<unsigned char, 3, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 7 → 9 not taken.
✗ Branch 7 → 16 not taken.
void do_DrawStringPackedRGB<unsigned char, 4, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 7 → 9 not taken.
✗ Branch 7 → 16 not taken.
void do_DrawStringPackedRGB<unsigned char, 4, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 7 → 9 not taken.
✗ Branch 7 → 16 not taken.
void do_DrawStringPackedRGB<unsigned short, 6, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 7 → 9 not taken.
✗ Branch 7 → 16 not taken.
void do_DrawStringPackedRGB<unsigned short, 6, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 7 → 9 not taken.
✗ Branch 7 → 16 not taken.
void do_DrawStringPackedRGB<unsigned short, 8, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 7 → 9 not taken.
✗ Branch 7 → 16 not taken.
void do_DrawStringPackedRGB<unsigned short, 8, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 7 → 9 not taken.
✗ Branch 7 → 16 not taken.
|
7 | RenderPackedRGB<pixel_t, true, fadeBackground, rgbstep>(color, halocolor, _dstp, pitch, height, pre); |
| 1906 | else | ||
| 1907 | ✗ | RenderPackedRGB<pixel_t, false, fadeBackground, rgbstep>(color, halocolor, _dstp, pitch, height, pre); | |
| 1908 |
1/16void do_DrawStringPackedRGB<unsigned char, 3, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✓ Branch 11 → 12 taken 7 times.
✗ Branch 11 → 14 not taken.
void do_DrawStringPackedRGB<unsigned char, 3, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 14 not taken.
void do_DrawStringPackedRGB<unsigned char, 4, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 14 not taken.
void do_DrawStringPackedRGB<unsigned char, 4, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 14 not taken.
void do_DrawStringPackedRGB<unsigned short, 6, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 14 not taken.
void do_DrawStringPackedRGB<unsigned short, 6, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 14 not taken.
void do_DrawStringPackedRGB<unsigned short, 8, false>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 14 not taken.
void do_DrawStringPackedRGB<unsigned short, 8, true>(int, int, unsigned char*, int, BitmapFont const*, int, int, std::vector<int, std::allocator<int> >&, int, int, int, bool):
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 14 not taken.
|
7 | } |
| 1909 | |||
| 1910 | |||
| 1911 | 16 | static bool strequals_i(const std::string& a, const std::string& b) | |
| 1912 | { | ||
| 1913 | 16 | return std::equal(a.begin(), a.end(), | |
| 1914 | b.begin(), b.end(), | ||
| 1915 | 120 | [](char a, char b) { | |
| 1916 | 120 | return tolower(a) == tolower(b); | |
| 1917 | 16 | }); | |
| 1918 | } | ||
| 1919 | |||
| 1920 | // in fixedfonts.cpp | ||
| 1921 | extern const uint16_t *font_bitmaps[]; | ||
| 1922 | extern const uint16_t *font_codepoints[]; | ||
| 1923 | extern const FixedFont_info_t *font_infos[]; | ||
| 1924 | |||
| 1925 | 7 | std::unique_ptr<BitmapFont> GetBitmapFont(int size, const char *name, bool bold, bool debugSave) { | |
| 1926 | |||
| 1927 | 7 | BitmapFont* current_font = nullptr; | |
| 1928 | |||
| 1929 | // check internal embedded fonts | ||
| 1930 | 7 | bool found = false; | |
| 1931 | |||
| 1932 | // find font in internal list | ||
| 1933 |
2/2✓ Branch 44 → 3 taken 50 times.
✓ Branch 44 → 45 taken 1 time.
|
51 | for (int i = 0; i < PREDEFINED_FONT_COUNT; i++) |
| 1934 | { | ||
| 1935 | 50 | const FixedFont_info_t* fi = font_infos[i]; | |
| 1936 |
17/30✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 14 taken 44 times.
✓ Branch 4 → 5 taken 6 times.
✗ Branch 4 → 14 not taken.
✓ Branch 7 → 8 taken 6 times.
✗ Branch 7 → 132 not taken.
✓ Branch 10 → 11 taken 6 times.
✗ Branch 10 → 132 not taken.
✓ Branch 11 → 12 taken 6 times.
✗ Branch 11 → 132 not taken.
✓ Branch 12 → 13 taken 6 times.
✗ Branch 12 → 14 not taken.
✓ Branch 15 → 16 taken 6 times.
✓ Branch 15 → 17 taken 44 times.
✓ Branch 17 → 18 taken 6 times.
✓ Branch 17 → 20 taken 44 times.
✓ Branch 20 → 21 taken 6 times.
✓ Branch 20 → 22 taken 44 times.
✓ Branch 22 → 23 taken 6 times.
✓ Branch 22 → 25 taken 44 times.
✓ Branch 25 → 26 taken 6 times.
✓ Branch 25 → 43 taken 44 times.
✗ Branch 132 → 133 not taken.
✗ Branch 132 → 134 not taken.
✗ Branch 136 → 137 not taken.
✗ Branch 136 → 139 not taken.
✗ Branch 141 → 142 not taken.
✗ Branch 141 → 143 not taken.
✗ Branch 145 → 146 not taken.
✗ Branch 145 → 148 not taken.
|
74 | if (fi->height == size && fi->bold == bold && strequals_i(fi->fontname, name)) { |
| 1937 | 6 | BBX global_bbx = BBX{ fi->width, fi->height, fi->offset_x, fi->offset_y }; // BBX from FONTBOUNDINGBOX | |
| 1938 | // max WIDTH, max HEIGHT, offset_x, offset_y | ||
| 1939 | ✗ | current_font = new BitmapFont( | |
| 1940 | 6 | fi->charcount, | |
| 1941 | font_bitmaps[i], // internal one | ||
| 1942 | nullptr, // not a byte array from external BDF | ||
| 1943 | sizeof(uint16_t), // sizeof(*font_bitmaps) 2: uint16_t | ||
| 1944 | font_codepoints[i], | ||
| 1945 | nullptr, // Individual BBX for each character. For our internal characters it comes from global bbx | ||
| 1946 | global_bbx, | ||
| 1947 |
1/2✓ Branch 32 → 33 taken 6 times.
✗ Branch 32 → 152 not taken.
|
12 | fi->fontname, |
| 1948 |
2/4✓ Branch 29 → 30 taken 6 times.
✗ Branch 29 → 158 not taken.
✗ Branch 38 → 39 not taken.
✓ Branch 38 → 41 taken 6 times.
|
18 | "", |
| 1949 | 6 | fi->bold, | |
| 1950 |
2/4✓ Branch 26 → 27 taken 6 times.
✗ Branch 26 → 166 not taken.
✓ Branch 33 → 34 taken 6 times.
✗ Branch 33 → 150 not taken.
|
12 | false); |
| 1951 | 6 | found = true; | |
| 1952 | 6 | break; | |
| 1953 | } | ||
| 1954 | } | ||
| 1955 | // pass #2 when size does not match exactly, find nearest, but still smaller font. | ||
| 1956 |
2/2✓ Branch 45 → 46 taken 1 time.
✓ Branch 45 → 93 taken 6 times.
|
7 | if (!found) { |
| 1957 | // find font i internal list | ||
| 1958 | 1 | int last_good_size = 0; | |
| 1959 | 1 | int found_index = -1; | |
| 1960 |
2/2✓ Branch 75 → 47 taken 20 times.
✓ Branch 75 → 76 taken 1 time.
|
21 | for (int i = 0; i < PREDEFINED_FONT_COUNT; i++) |
| 1961 | { | ||
| 1962 | 20 | const FixedFont_info_t* fi = font_infos[i]; | |
| 1963 |
17/28✓ Branch 47 → 48 taken 10 times.
✓ Branch 47 → 57 taken 10 times.
✓ Branch 50 → 51 taken 10 times.
✗ Branch 50 → 167 not taken.
✓ Branch 53 → 54 taken 10 times.
✗ Branch 53 → 167 not taken.
✓ Branch 54 → 55 taken 10 times.
✗ Branch 54 → 167 not taken.
✓ Branch 55 → 56 taken 9 times.
✓ Branch 55 → 57 taken 1 time.
✓ Branch 58 → 59 taken 10 times.
✓ Branch 58 → 60 taken 10 times.
✓ Branch 60 → 61 taken 10 times.
✓ Branch 60 → 63 taken 10 times.
✓ Branch 63 → 64 taken 10 times.
✓ Branch 63 → 65 taken 10 times.
✓ Branch 65 → 66 taken 10 times.
✓ Branch 65 → 68 taken 10 times.
✓ Branch 68 → 69 taken 9 times.
✓ Branch 68 → 74 taken 11 times.
✗ Branch 167 → 168 not taken.
✗ Branch 167 → 169 not taken.
✗ Branch 171 → 172 not taken.
✗ Branch 171 → 174 not taken.
✗ Branch 176 → 177 not taken.
✗ Branch 176 → 178 not taken.
✗ Branch 180 → 181 not taken.
✗ Branch 180 → 183 not taken.
|
60 | if (fi->bold == bold && strequals_i(fi->fontname, name)) { |
| 1964 |
2/2✓ Branch 69 → 70 taken 1 time.
✓ Branch 69 → 71 taken 8 times.
|
9 | if (last_good_size == 0) { |
| 1965 | 1 | found_index = i; | |
| 1966 | 1 | last_good_size = fi->height; | |
| 1967 | } | ||
| 1968 |
1/4✗ Branch 71 → 72 not taken.
✓ Branch 71 → 74 taken 8 times.
✗ Branch 72 → 73 not taken.
✗ Branch 72 → 74 not taken.
|
8 | else if (std::abs(fi->height - size) < std::abs(last_good_size - size) && fi->height <= size) { |
| 1969 | // has better size match and is not larger | ||
| 1970 | ✗ | found_index = i; | |
| 1971 | ✗ | last_good_size = fi->height; | |
| 1972 | } | ||
| 1973 | } | ||
| 1974 | } | ||
| 1975 |
1/2✓ Branch 76 → 77 taken 1 time.
✗ Branch 76 → 93 not taken.
|
1 | if (found_index >= 0) { |
| 1976 | 1 | const FixedFont_info_t* fi = font_infos[found_index]; | |
| 1977 | 1 | BBX global_bbx = BBX{ fi->width, fi->height, fi->offset_x, fi->offset_y }; // BBX from FONTBOUNDINGBOX | |
| 1978 | ✗ | current_font = new BitmapFont( | |
| 1979 | 1 | fi->charcount, | |
| 1980 | font_bitmaps[found_index], // internal one | ||
| 1981 | nullptr, // not a byte array from external BDF | ||
| 1982 | sizeof(uint16_t), // sizeof(*font_bitmaps) 2: uint16_t | ||
| 1983 | font_codepoints[found_index], | ||
| 1984 | nullptr, // Individual BBX for each character. For our internal characters it comes from global bbx | ||
| 1985 | global_bbx, | ||
| 1986 |
1/2✓ Branch 83 → 84 taken 1 time.
✗ Branch 83 → 187 not taken.
|
2 | fi->fontname, |
| 1987 |
2/4✓ Branch 80 → 81 taken 1 time.
✗ Branch 80 → 193 not taken.
✗ Branch 89 → 90 not taken.
✓ Branch 89 → 92 taken 1 time.
|
3 | "", |
| 1988 | 1 | fi->bold, | |
| 1989 |
2/4✓ Branch 77 → 78 taken 1 time.
✗ Branch 77 → 201 not taken.
✓ Branch 84 → 85 taken 1 time.
✗ Branch 84 → 185 not taken.
|
2 | false); |
| 1990 | 1 | found = true; | |
| 1991 | } | ||
| 1992 | } | ||
| 1993 | |||
| 1994 |
1/2✗ Branch 93 → 94 not taken.
✓ Branch 93 → 130 taken 7 times.
|
7 | if (!found) { |
| 1995 | // fixme: make cache | ||
| 1996 | ✗ | BdfFont bdf; | |
| 1997 | ✗ | bdf = LoadBMF(name, bold); | |
| 1998 | ✗ | if (bdf.codepoints_array.size() == 0) | |
| 1999 | ✗ | return nullptr; | |
| 2000 | |||
| 2001 | ✗ | current_font = new BitmapFont( | |
| 2002 | bdf.font_info.chars, | ||
| 2003 | nullptr, // not an internal one | ||
| 2004 | ✗ | bdf.font_bitmaps.data(), // a byte array from external BDF | |
| 2005 | bdf.font_info.fontline_bytes, | ||
| 2006 | ✗ | bdf.codepoints_array.data(), | |
| 2007 | &bdf.bbx_array, // Individual BBX for each character, nullptr if not available for our internal fonts | ||
| 2008 | bdf.font_info.bbx, // from FONTBOUNDINGBOX, max WIDTH, HEIGHT, offset_x, offset_y | ||
| 2009 | bdf.font_info.font, | ||
| 2010 | bdf.font_filename, | ||
| 2011 | ✗ | strequals_i(bdf.font_properties.Weight_name, "bold"), | |
| 2012 | ✗ | debugSave); | |
| 2013 | ✗ | } | |
| 2014 | 7 | return std::unique_ptr<BitmapFont>(current_font); | |
| 2015 | } | ||
| 2016 | |||
| 2017 | 7 | static void DrawString_internal(BitmapFont* current_font, const VideoInfo& vi, PVideoFrame& dst, int x, int y, std::string& s_utf8, | |
| 2018 | int color, int halocolor, bool useHalocolor, int align, bool fadeBackground, int chromalocation) | ||
| 2019 | { | ||
| 2020 | //static BitmapFont_10_20 infoFont1020; // constructor runs once, single instance | ||
| 2021 | |||
| 2022 | // map an utf8 string to a sequence of character map indexes | ||
| 2023 |
1/2✓ Branch 2 → 3 taken 7 times.
✗ Branch 2 → 135 not taken.
|
7 | auto s_remapped = current_font->remap(s_utf8); // array of font table indexes |
| 2024 | |||
| 2025 | //SaveBitmapSource(); // debug to generate source from original table | ||
| 2026 | |||
| 2027 |
1/2✓ Branch 3 → 4 taken 7 times.
✗ Branch 3 → 133 not taken.
|
7 | const bool isRGB = vi.IsRGB(); |
| 2028 | 7 | const int planes_y[4] = { PLANAR_Y, PLANAR_U, PLANAR_V, PLANAR_A }; | |
| 2029 | 7 | const int planes_r[4] = { PLANAR_G, PLANAR_B, PLANAR_R, PLANAR_A }; | |
| 2030 |
1/2✓ Branch 4 → 5 taken 7 times.
✗ Branch 4 → 6 not taken.
|
7 | const int* planes = isRGB ? planes_r : planes_y; |
| 2031 | |||
| 2032 | 7 | int logXRatioUV = 0; | |
| 2033 | 7 | int logYRatioUV = 0; | |
| 2034 |
5/10✓ Branch 7 → 8 taken 7 times.
✗ Branch 7 → 133 not taken.
✓ Branch 8 → 9 taken 7 times.
✗ Branch 8 → 12 not taken.
✓ Branch 9 → 10 taken 7 times.
✗ Branch 9 → 133 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 7 times.
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 24 taken 7 times.
|
7 | if (!vi.IsY() && !vi.IsRGB()) { |
| 2035 | ✗ | logXRatioUV = vi.IsYUY2() ? 1 : vi.GetPlaneWidthSubsampling(PLANAR_U); | |
| 2036 | ✗ | logYRatioUV = vi.IsYUY2() ? 0 : vi.GetPlaneHeightSubsampling(PLANAR_U); | |
| 2037 | } | ||
| 2038 |
3/6✓ Branch 24 → 25 taken 7 times.
✗ Branch 24 → 133 not taken.
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 27 taken 7 times.
✓ Branch 27 → 28 taken 7 times.
✗ Branch 27 → 131 not taken.
|
7 | const int planecount = vi.IsYUY2() ? 1 : std::min(vi.NumComponents(), 3); |
| 2039 | 7 | BYTE* dstps[3] = { nullptr }; | |
| 2040 | 7 | int pitches[3] = { 0 }; | |
| 2041 | |||
| 2042 |
2/2✓ Branch 36 → 31 taken 21 times.
✓ Branch 36 → 37 taken 7 times.
|
28 | for (int i = 0; i < planecount; i++) |
| 2043 | { | ||
| 2044 | 21 | int plane = planes[i]; | |
| 2045 |
1/2✓ Branch 32 → 33 taken 21 times.
✗ Branch 32 → 133 not taken.
|
21 | dstps[i] = dst->GetWritePtr(plane); |
| 2046 |
1/2✓ Branch 34 → 35 taken 21 times.
✗ Branch 34 → 133 not taken.
|
21 | pitches[i] = dst->GetPitch(plane); |
| 2047 | } | ||
| 2048 | |||
| 2049 | 7 | const int width = vi.width; | |
| 2050 | 7 | const int height = vi.height; | |
| 2051 | |||
| 2052 |
1/2✓ Branch 37 → 38 taken 7 times.
✗ Branch 37 → 133 not taken.
|
7 | const int bits_per_pixel = vi.BitsPerComponent(); |
| 2053 | |||
| 2054 | // narrow down valid chroma choices, ignoring and moving to default what is not supported at the moment | ||
| 2055 |
2/4✓ Branch 38 → 39 taken 7 times.
✗ Branch 38 → 133 not taken.
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 41 taken 7 times.
|
7 | if (vi.IsYV411()) { |
| 2056 | // ignored, always left | ||
| 2057 | ✗ | chromalocation = ChromaLocation_e::AVS_CHROMA_LEFT; | |
| 2058 | } | ||
| 2059 |
7/14✓ Branch 41 → 42 taken 7 times.
✗ Branch 41 → 133 not taken.
✓ Branch 42 → 43 taken 7 times.
✗ Branch 42 → 47 not taken.
✓ Branch 43 → 44 taken 7 times.
✗ Branch 43 → 133 not taken.
✓ Branch 44 → 45 taken 7 times.
✗ Branch 44 → 47 not taken.
✓ Branch 45 → 46 taken 7 times.
✗ Branch 45 → 133 not taken.
✗ Branch 46 → 47 not taken.
✓ Branch 46 → 48 taken 7 times.
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 52 taken 7 times.
|
7 | else if (vi.Is420() || vi.Is422() || vi.IsYUY2()) { |
| 2060 | ✗ | if (chromalocation != ChromaLocation_e::AVS_CHROMA_CENTER) | |
| 2061 | ✗ | chromalocation = ChromaLocation_e::AVS_CHROMA_LEFT; | |
| 2062 | // When CENTER is specified, do "center", all other cases fall back | ||
| 2063 | // to "left" (mpeg2). Option is meaningful only 420 or 422 formats, otherwise ignored. | ||
| 2064 | } | ||
| 2065 | |||
| 2066 | // YUY2 | ||
| 2067 |
2/4✓ Branch 52 → 53 taken 7 times.
✗ Branch 52 → 133 not taken.
✗ Branch 53 → 54 not taken.
✓ Branch 53 → 58 taken 7 times.
|
7 | if (vi.IsYUY2()) { |
| 2068 | ✗ | if (fadeBackground) | |
| 2069 | ✗ | do_DrawStringYUY2<true>(width, height, dstps[0], pitches[0], current_font, x, y, s_remapped, color, halocolor, align, useHalocolor, chromalocation); | |
| 2070 | else | ||
| 2071 | ✗ | do_DrawStringYUY2<false>(width, height, dstps[0], pitches[0], current_font, x, y, s_remapped, color, halocolor, align, useHalocolor, chromalocation); | |
| 2072 | ✗ | return; | |
| 2073 | } | ||
| 2074 | |||
| 2075 | // Packed RGB24/32/48/64 | ||
| 2076 |
4/8✓ Branch 58 → 59 taken 7 times.
✗ Branch 58 → 62 not taken.
✓ Branch 59 → 60 taken 7 times.
✗ Branch 59 → 133 not taken.
✓ Branch 60 → 61 taken 7 times.
✗ Branch 60 → 62 not taken.
✓ Branch 63 → 64 taken 7 times.
✗ Branch 63 → 90 not taken.
|
7 | if (isRGB && !vi.IsPlanar()) { |
| 2077 |
1/2✗ Branch 64 → 65 not taken.
✓ Branch 64 → 77 taken 7 times.
|
7 | if (fadeBackground) { |
| 2078 | ✗ | if (vi.IsRGB24()) | |
| 2079 | ✗ | do_DrawStringPackedRGB<uint8_t, 3, true>(width, height, dstps[0], pitches[0], current_font, x, y, s_remapped, color, halocolor, align, useHalocolor); | |
| 2080 | ✗ | else if (vi.IsRGB32()) | |
| 2081 | ✗ | do_DrawStringPackedRGB<uint8_t, 4, true>(width, height, dstps[0], pitches[0], current_font, x, y, s_remapped, color, halocolor, align, useHalocolor); | |
| 2082 | ✗ | else if (vi.IsRGB48()) | |
| 2083 | ✗ | do_DrawStringPackedRGB<uint16_t, 6, true>(width, height, dstps[0], pitches[0], current_font, x, y, s_remapped, color, halocolor, align, useHalocolor); | |
| 2084 | ✗ | else if (vi.IsRGB64()) | |
| 2085 | ✗ | do_DrawStringPackedRGB<uint16_t, 8, true>(width, height, dstps[0], pitches[0], current_font, x, y, s_remapped, color, halocolor, align, useHalocolor); | |
| 2086 | } | ||
| 2087 | else { | ||
| 2088 |
2/4✓ Branch 77 → 78 taken 7 times.
✗ Branch 77 → 133 not taken.
✓ Branch 78 → 79 taken 7 times.
✗ Branch 78 → 80 not taken.
|
7 | if (vi.IsRGB24()) |
| 2089 |
1/2✓ Branch 79 → 89 taken 7 times.
✗ Branch 79 → 133 not taken.
|
7 | do_DrawStringPackedRGB<uint8_t, 3, false>(width, height, dstps[0], pitches[0], current_font, x, y, s_remapped, color, halocolor, align, useHalocolor); |
| 2090 | ✗ | else if (vi.IsRGB32()) | |
| 2091 | ✗ | do_DrawStringPackedRGB<uint8_t, 4, false>(width, height, dstps[0], pitches[0], current_font, x, y, s_remapped, color, halocolor, align, useHalocolor); | |
| 2092 | ✗ | else if (vi.IsRGB48()) | |
| 2093 | ✗ | do_DrawStringPackedRGB<uint16_t, 6, false>(width, height, dstps[0], pitches[0], current_font, x, y, s_remapped, color, halocolor, align, useHalocolor); | |
| 2094 | ✗ | else if (vi.IsRGB64()) | |
| 2095 | ✗ | do_DrawStringPackedRGB<uint16_t, 8, false>(width, height, dstps[0], pitches[0], current_font, x, y, s_remapped, color, halocolor, align, useHalocolor); | |
| 2096 | } | ||
| 2097 | 7 | return; | |
| 2098 | } | ||
| 2099 | |||
| 2100 | // planar and Y | ||
| 2101 | ✗ | if (fadeBackground) { | |
| 2102 | ✗ | if (isRGB) { | |
| 2103 | ✗ | switch (bits_per_pixel) | |
| 2104 | { | ||
| 2105 | ✗ | case 8: | |
| 2106 | ✗ | do_DrawStringPlanar<uint8_t, true, true>(width, height, dstps, pitches, logXRatioUV, logYRatioUV, planecount, bits_per_pixel, current_font, x, y, s_remapped, color, halocolor, align, useHalocolor, chromalocation); | |
| 2107 | ✗ | break; | |
| 2108 | ✗ | case 10: | |
| 2109 | case 12: | ||
| 2110 | case 14: | ||
| 2111 | case 16: | ||
| 2112 | ✗ | do_DrawStringPlanar<uint16_t, true, true>(width, height, dstps, pitches, logXRatioUV, logYRatioUV, planecount, bits_per_pixel, current_font, x, y, s_remapped, color, halocolor, align, useHalocolor, chromalocation); | |
| 2113 | ✗ | break; | |
| 2114 | ✗ | case 32: | |
| 2115 | ✗ | do_DrawStringPlanar<float, true, true>(width, height, dstps, pitches, logXRatioUV, logYRatioUV, planecount, bits_per_pixel, current_font, x, y, s_remapped, color, halocolor, align, useHalocolor, chromalocation); | |
| 2116 | ✗ | break; | |
| 2117 | } | ||
| 2118 | } | ||
| 2119 | else { | ||
| 2120 | ✗ | switch (bits_per_pixel) | |
| 2121 | { | ||
| 2122 | ✗ | case 8: | |
| 2123 | ✗ | do_DrawStringPlanar<uint8_t, true, false>(width, height, dstps, pitches, logXRatioUV, logYRatioUV, planecount, bits_per_pixel, current_font, x, y, s_remapped, color, halocolor, align, useHalocolor, chromalocation); | |
| 2124 | ✗ | break; | |
| 2125 | ✗ | case 10: | |
| 2126 | case 12: | ||
| 2127 | case 14: | ||
| 2128 | case 16: | ||
| 2129 | ✗ | do_DrawStringPlanar<uint16_t, true, false>(width, height, dstps, pitches, logXRatioUV, logYRatioUV, planecount, bits_per_pixel, current_font, x, y, s_remapped, color, halocolor, align, useHalocolor, chromalocation); | |
| 2130 | ✗ | break; | |
| 2131 | ✗ | case 32: | |
| 2132 | ✗ | do_DrawStringPlanar<float, true, false>(width, height, dstps, pitches, logXRatioUV, logYRatioUV, planecount, bits_per_pixel, current_font, x, y, s_remapped, color, halocolor, align, useHalocolor, chromalocation); | |
| 2133 | ✗ | break; | |
| 2134 | } | ||
| 2135 | } | ||
| 2136 | } | ||
| 2137 | else { | ||
| 2138 | ✗ | if (isRGB) { | |
| 2139 | ✗ | switch (bits_per_pixel) | |
| 2140 | { | ||
| 2141 | ✗ | case 8: | |
| 2142 | ✗ | do_DrawStringPlanar<uint8_t, false, true>(width, height, dstps, pitches, logXRatioUV, logYRatioUV, planecount, bits_per_pixel, current_font, x, y, s_remapped, color, halocolor, align, useHalocolor, chromalocation); | |
| 2143 | ✗ | break; | |
| 2144 | ✗ | case 10: | |
| 2145 | case 12: | ||
| 2146 | case 14: | ||
| 2147 | case 16: | ||
| 2148 | ✗ | do_DrawStringPlanar<uint16_t, false, true>(width, height, dstps, pitches, logXRatioUV, logYRatioUV, planecount, bits_per_pixel, current_font, x, y, s_remapped, color, halocolor, align, useHalocolor, chromalocation); | |
| 2149 | ✗ | break; | |
| 2150 | ✗ | case 32: | |
| 2151 | ✗ | do_DrawStringPlanar<float, false, true>(width, height, dstps, pitches, logXRatioUV, logYRatioUV, planecount, bits_per_pixel, current_font, x, y, s_remapped, color, halocolor, align, useHalocolor, chromalocation); | |
| 2152 | ✗ | break; | |
| 2153 | } | ||
| 2154 | } | ||
| 2155 | else { | ||
| 2156 | ✗ | switch (bits_per_pixel) | |
| 2157 | { | ||
| 2158 | ✗ | case 8: | |
| 2159 | ✗ | do_DrawStringPlanar<uint8_t, false, false>(width, height, dstps, pitches, logXRatioUV, logYRatioUV, planecount, bits_per_pixel, current_font, x, y, s_remapped, color, halocolor, align, useHalocolor, chromalocation); | |
| 2160 | ✗ | break; | |
| 2161 | ✗ | case 10: | |
| 2162 | case 12: | ||
| 2163 | case 14: | ||
| 2164 | case 16: | ||
| 2165 | ✗ | do_DrawStringPlanar<uint16_t, false, false>(width, height, dstps, pitches, logXRatioUV, logYRatioUV, planecount, bits_per_pixel, current_font, x, y, s_remapped, color, halocolor, align, useHalocolor, chromalocation); | |
| 2166 | ✗ | break; | |
| 2167 | ✗ | case 32: | |
| 2168 | ✗ | do_DrawStringPlanar<float, false, false>(width, height, dstps, pitches, logXRatioUV, logYRatioUV, planecount, bits_per_pixel, current_font, x, y, s_remapped, color, halocolor, align, useHalocolor, chromalocation); | |
| 2169 | ✗ | break; | |
| 2170 | } | ||
| 2171 | } | ||
| 2172 | } | ||
| 2173 |
1/2✗ Branch 126 → 127 not taken.
✓ Branch 126 → 129 taken 7 times.
|
7 | } |
| 2174 | |||
| 2175 | 7 | void SimpleTextOutW(BitmapFont *current_font, const VideoInfo& vi, PVideoFrame& frame, int real_x, int real_y, std::string& text_utf8, | |
| 2176 | bool fadeBackground, int textcolor, int halocolor, bool useHaloColor, int align, int chromalocation) | ||
| 2177 | { | ||
| 2178 | 7 | DrawString_internal(current_font, vi, frame, real_x, real_y, text_utf8, textcolor, halocolor, useHaloColor, align, fadeBackground, chromalocation); // fully transparent background | |
| 2179 | 7 | } | |
| 2180 | |||
| 2181 | // additional parameter: lsp line spacing | ||
| 2182 | 1 | void SimpleTextOutW_multi(BitmapFont *current_font, const VideoInfo& vi, PVideoFrame& frame, int real_x, int real_y, std::string& text_utf8, | |
| 2183 | bool fadeBackground, int textcolor, int halocolor, bool useHaloColor, | ||
| 2184 | int align, int lsp, int chromalocation) | ||
| 2185 | { | ||
| 2186 | |||
| 2187 | // make list governed by LF separator | ||
| 2188 | 1 | std::string temp; | |
| 2189 | 1 | std::vector<std::string> parts; | |
| 2190 |
1/2✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 44 not taken.
|
1 | std::stringstream ss(text_utf8); |
| 2191 |
4/6✓ Branch 8 → 9 taken 8 times.
✗ Branch 8 → 42 not taken.
✓ Branch 9 → 10 taken 8 times.
✗ Branch 9 → 42 not taken.
✓ Branch 10 → 7 taken 7 times.
✓ Branch 10 → 11 taken 1 time.
|
8 | while (std::getline(ss, temp, '\n')) |
| 2192 |
1/2✓ Branch 7 → 8 taken 7 times.
✗ Branch 7 → 42 not taken.
|
7 | parts.push_back(temp); // still in utf8 |
| 2193 | // It doesn't result in a new line if the last character is \n and is followed by nothing. | ||
| 2194 | // "Line1\nLine2" is the same as "Line1\nLine2\n" | ||
| 2195 | // Like in SubTitle | ||
| 2196 | /* | ||
| 2197 | if(!text.empty()) | ||
| 2198 | { | ||
| 2199 | if( *text.rbegin() == '\n') | ||
| 2200 | parts.push_back(""); | ||
| 2201 | } | ||
| 2202 | */ | ||
| 2203 | 1 | const int fontSize = current_font->global_bbx.height; | |
| 2204 | |||
| 2205 | // when multiline, bottom and vertically centered cases affect starting y | ||
| 2206 | // lsp units are in 1/8 pixels by definition | ||
| 2207 | 1 | int al = alignToBitmask(align); | |
| 2208 |
1/2✗ Branch 12 → 13 not taken.
✓ Branch 12 → 15 taken 1 time.
|
1 | if (al & ATA_BOTTOM) |
| 2209 | ✗ | real_y -= (int)((fontSize + lsp / 8.0) * ((int)parts.size() - 1) + 0.5); | |
| 2210 |
1/2✗ Branch 15 → 16 not taken.
✓ Branch 15 → 18 taken 1 time.
|
1 | else if (al & ATA_BASELINE) |
| 2211 | ✗ | real_y -= (int)((fontSize + lsp / 8.0) * (int)(parts.size() - 1) / 2.0 + 0.5); | |
| 2212 | |||
| 2213 | 1 | const int orig_real_y = real_y; | |
| 2214 | 1 | int linecount = 0; | |
| 2215 |
3/4✓ Branch 22 → 23 taken 7 times.
✗ Branch 22 → 41 not taken.
✓ Branch 34 → 20 taken 7 times.
✓ Branch 34 → 35 taken 1 time.
|
16 | for (auto s_utf8 : parts) { |
| 2216 | 7 | real_y = orig_real_y + fontSize * linecount + (int)(lsp / 8.0 * linecount + 0.5); | |
| 2217 |
1/2✓ Branch 23 → 24 taken 7 times.
✗ Branch 23 → 39 not taken.
|
7 | SimpleTextOutW(current_font, vi, frame, real_x, real_y, s_utf8, fadeBackground, textcolor, halocolor, useHaloColor, align, chromalocation); |
| 2218 | 7 | linecount++; | |
| 2219 | 7 | } | |
| 2220 | 1 | } | |
| 2221 | |||
| 2222 | // Old legacy info.h functions, but with utf8 mode | ||
| 2223 | // w/o outline, originally with ASCII input, background fading | ||
| 2224 | // Despite name Planar, it works for all formats | ||
| 2225 | ✗ | void DrawStringPlanar(VideoInfo& vi, PVideoFrame& dst, int x, int y, const char* s) | |
| 2226 | { | ||
| 2227 | int color; | ||
| 2228 | ✗ | if (vi.IsRGB()) | |
| 2229 | ✗ | color = (250 << 16) + (250 << 8) + (250); | |
| 2230 | else | ||
| 2231 | ✗ | color = (230 << 16) + (128 << 8) + (128); | |
| 2232 | |||
| 2233 | // fadeBackground = true: background letter area is faded instead not being untouched. | ||
| 2234 | |||
| 2235 | ✗ | std::string s_utf8 = charToUtf8(s, false); | |
| 2236 | |||
| 2237 | ✗ | int halocolor = 0; | |
| 2238 | |||
| 2239 | ✗ | std::unique_ptr<BitmapFont> current_font = GetBitmapFont(20, "info_h", false, false); // 10x20 | |
| 2240 | |||
| 2241 | ✗ | if (current_font == nullptr) | |
| 2242 | ✗ | return; | |
| 2243 | |||
| 2244 | ✗ | DrawString_internal(current_font.get(), vi, dst, x, y, s_utf8, | |
| 2245 | color, | ||
| 2246 | halocolor, | ||
| 2247 | false, // don't use halocolor | ||
| 2248 | 0 /* no align */, | ||
| 2249 | true, // fadeBackGround | ||
| 2250 | ChromaLocation_e::AVS_CHROMA_LEFT | ||
| 2251 | ); | ||
| 2252 | |||
| 2253 | ✗ | } | |
| 2254 | |||
| 2255 | ✗ | void DrawStringYUY2(VideoInfo& vi, PVideoFrame& dst, int x, int y, const char* s) | |
| 2256 | { | ||
| 2257 | ✗ | DrawStringPlanar(vi, dst, x, y, s); | |
| 2258 | ✗ | } | |
| 2259 | |||
| 2260 | // legacy function w/o outline, originally with ASCII input, background fading | ||
| 2261 | ✗ | void DrawStringRGB24(VideoInfo &vi, PVideoFrame& dst, int x, int y, const char* s) | |
| 2262 | { | ||
| 2263 | ✗ | DrawStringPlanar(vi, dst, x, y, s); | |
| 2264 | ✗ | } | |
| 2265 | |||
| 2266 | // legacy function w/o outline, originally with ASCII input, background fading | ||
| 2267 | ✗ | void DrawStringRGB32(VideoInfo& vi, PVideoFrame& dst, int x, int y, const char* s) | |
| 2268 | { | ||
| 2269 | ✗ | DrawStringPlanar(vi, dst, x, y, s); | |
| 2270 | ✗ | } | |
| 2271 |