Charlie Jiang pushed to branch gsoc-2022-chariri-3 at FreeType / FreeType Demo Programs
Commits:
-
ef14bfd2
by Charlie Jiang at 2022-08-19T16:54:23+08:00
-
6b689304
by Charlie Jiang at 2022-08-19T22:38:19+08:00
9 changed files:
- src/ftinspect/engine/engine.cpp
- src/ftinspect/engine/engine.hpp
- src/ftinspect/engine/fontinfo.cpp
- src/ftinspect/engine/mmgx.cpp
- src/ftinspect/engine/stringrenderer.cpp
- src/ftinspect/panels/info.cpp
- src/ftinspect/rendering/glyphcontinuous.cpp
- src/ftinspect/rendering/glyphcontinuous.hpp
- src/ftinspect/widgets/tripletselector.cpp
Changes:
... | ... | @@ -124,6 +124,7 @@ faceRequester(FTC_FaceID ftcFaceID, |
124 | 124 | Engine::Engine()
|
125 | 125 | {
|
126 | 126 | ftSize_ = NULL;
|
127 | + ftFallbackFace_ = NULL;
|
|
127 | 128 | // we reserve value 0 for the `invalid face ID'
|
128 | 129 | faceCounter_ = 1;
|
129 | 130 | |
... | ... | @@ -292,8 +293,18 @@ Engine::loadFont(int fontIndex, |
292 | 293 | if (scaler_.face_id)
|
293 | 294 | {
|
294 | 295 | // found
|
295 | - if (!FTC_Manager_LookupSize(cacheManager_, &scaler_, &ftSize_))
|
|
296 | - numGlyphs = ftSize_->face->num_glyphs;
|
|
296 | + if (!FTC_Manager_LookupFace(cacheManager_, scaler_.face_id,
|
|
297 | + &ftFallbackFace_))
|
|
298 | + {
|
|
299 | + numGlyphs = ftFallbackFace_->num_glyphs;
|
|
300 | + if (FTC_Manager_LookupSize(cacheManager_, &scaler_, &ftSize_))
|
|
301 | + ftSize_ = NULL; // Good font, bad size.
|
|
302 | + }
|
|
303 | + else
|
|
304 | + {
|
|
305 | + ftFallbackFace_ = NULL;
|
|
306 | + ftSize_ = NULL;
|
|
307 | + }
|
|
297 | 308 | }
|
298 | 309 | else if (fontIndex >= 0)
|
299 | 310 | {
|
... | ... | @@ -305,12 +316,19 @@ Engine::loadFont(int fontIndex, |
305 | 316 | scaler_.face_id = reinterpret_cast<FTC_FaceID>(faceCounter_);
|
306 | 317 | faceIDMap_.insert(id, faceCounter_++);
|
307 | 318 | |
308 | - if (!FTC_Manager_LookupSize(cacheManager_, &scaler_, &ftSize_))
|
|
309 | - numGlyphs = ftSize_->face->num_glyphs;
|
|
319 | + if (!FTC_Manager_LookupFace(cacheManager_, scaler_.face_id,
|
|
320 | + &ftFallbackFace_))
|
|
321 | + {
|
|
322 | + numGlyphs = ftFallbackFace_->num_glyphs;
|
|
323 | + if (FTC_Manager_LookupSize(cacheManager_, &scaler_, &ftSize_))
|
|
324 | + ftSize_ = NULL; // Good font, bad size.
|
|
325 | + }
|
|
310 | 326 | else
|
311 | 327 | {
|
312 | 328 | faceIDMap_.remove(id);
|
313 | 329 | faceCounter_--;
|
330 | + ftFallbackFace_ = NULL;
|
|
331 | + ftSize_ = NULL;
|
|
314 | 332 | }
|
315 | 333 | }
|
316 | 334 | |
... | ... | @@ -318,6 +336,7 @@ Engine::loadFont(int fontIndex, |
318 | 336 | |
319 | 337 | if (numGlyphs < 0)
|
320 | 338 | {
|
339 | + ftFallbackFace_ = NULL;
|
|
321 | 340 | ftSize_ = NULL;
|
322 | 341 | curFamilyName_ = QString();
|
323 | 342 | curStyleName_ = QString();
|
... | ... | @@ -328,11 +347,10 @@ Engine::loadFont(int fontIndex, |
328 | 347 | }
|
329 | 348 | else
|
330 | 349 | {
|
331 | - auto face = ftSize_->face;
|
|
332 | - curFamilyName_ = QString(face->family_name);
|
|
333 | - curStyleName_ = QString(face->style_name);
|
|
350 | + curFamilyName_ = QString(ftFallbackFace_->family_name);
|
|
351 | + curStyleName_ = QString(ftFallbackFace_->style_name);
|
|
334 | 352 | |
335 | - const char* moduleName = FT_FACE_DRIVER_NAME( face );
|
|
353 | + const char* moduleName = FT_FACE_DRIVER_NAME(ftFallbackFace_);
|
|
336 | 354 | |
337 | 355 | // XXX cover all available modules
|
338 | 356 | if (!strcmp(moduleName, "cff"))
|
... | ... | @@ -341,9 +359,9 @@ Engine::loadFont(int fontIndex, |
341 | 359 | fontType_ = FontType_TrueType;
|
342 | 360 | |
343 | 361 | curCharMaps_.clear();
|
344 | - curCharMaps_.reserve(face->num_charmaps);
|
|
345 | - for (int i = 0; i < face->num_charmaps; i++)
|
|
346 | - curCharMaps_.emplace_back(i, face->charmaps[i]);
|
|
362 | + curCharMaps_.reserve(ftFallbackFace_->num_charmaps);
|
|
363 | + for (int i = 0; i < ftFallbackFace_->num_charmaps; i++)
|
|
364 | + curCharMaps_.emplace_back(i, ftFallbackFace_->charmaps[i]);
|
|
347 | 365 | |
348 | 366 | SFNTName::get(this, curSFNTNames_);
|
349 | 367 | loadPaletteInfos();
|
... | ... | @@ -362,6 +380,7 @@ Engine::reloadFont() |
362 | 380 | if (!scaler_.face_id)
|
363 | 381 | return;
|
364 | 382 | imageType_.face_id = scaler_.face_id;
|
383 | + FTC_Manager_LookupFace(cacheManager_, scaler_.face_id, &ftFallbackFace_);
|
|
365 | 384 | FTC_Manager_LookupSize(cacheManager_, &scaler_, &ftSize_);
|
366 | 385 | }
|
367 | 386 | |
... | ... | @@ -375,6 +394,9 @@ Engine::loadPalette() |
375 | 394 | || paletteData_.num_palettes <= paletteIndex_)
|
376 | 395 | return;
|
377 | 396 | |
397 | + if (!ftSize_)
|
|
398 | + return;
|
|
399 | + |
|
378 | 400 | FT_Palette_Select(ftSize_->face,
|
379 | 401 | static_cast<FT_UShort>(paletteIndex_),
|
380 | 402 | &palette_);
|
... | ... | @@ -436,6 +458,9 @@ Engine::currentFaceSlot() |
436 | 458 | FT_Pos
|
437 | 459 | Engine::currentFontTrackingKerning(int degree)
|
438 | 460 | {
|
461 | + if (!ftSize_)
|
|
462 | + return 0;
|
|
463 | + |
|
439 | 464 | FT_Pos result;
|
440 | 465 | // this function needs and returns points, not pixels
|
441 | 466 | if (!FT_Get_Track_Kerning(ftSize_->face,
|
... | ... | @@ -513,16 +538,14 @@ Engine::glyphName(int index) |
513 | 538 | if (index < 0)
|
514 | 539 | throw std::runtime_error("Invalid glyph index");
|
515 | 540 | |
516 | - if (!ftSize_)
|
|
517 | - return "";
|
|
518 | -
|
|
519 | - if (!FTC_Manager_LookupSize(cacheManager_, &scaler_, &ftSize_))
|
|
541 | + FT_Face face = NULL;
|
|
542 | + if (FTC_Manager_LookupFace(cacheManager_, scaler_.face_id, &face))
|
|
520 | 543 | return name;
|
521 | 544 | |
522 | - if (ftSize_ && FT_HAS_GLYPH_NAMES(ftSize_->face))
|
|
545 | + if (face && FT_HAS_GLYPH_NAMES(face))
|
|
523 | 546 | {
|
524 | 547 | char buffer[256];
|
525 | - if (!FT_Get_Glyph_Name(ftSize_->face,
|
|
548 | + if (!FT_Get_Glyph_Name(face,
|
|
526 | 549 | static_cast<unsigned int>(index),
|
527 | 550 | buffer,
|
528 | 551 | sizeof(buffer)))
|
... | ... | @@ -649,6 +672,20 @@ Engine::convertBitmapTo8Bpp(FT_Bitmap* bitmap) |
649 | 672 | }
|
650 | 673 | |
651 | 674 | |
675 | +bool
|
|
676 | +Engine::renderReady()
|
|
677 | +{
|
|
678 | + return ftSize_ != NULL;
|
|
679 | +}
|
|
680 | + |
|
681 | + |
|
682 | +bool
|
|
683 | +Engine::fontValid()
|
|
684 | +{
|
|
685 | + return ftFallbackFace_ != NULL;
|
|
686 | +}
|
|
687 | + |
|
688 | + |
|
652 | 689 | int
|
653 | 690 | Engine::numberOfOpenedFonts()
|
654 | 691 | {
|
... | ... | @@ -709,6 +746,7 @@ Engine::setCFFHintingMode(int mode) |
709 | 746 | {
|
710 | 747 | // reset the cache
|
711 | 748 | FTC_Manager_Reset(cacheManager_);
|
749 | + ftFallbackFace_ = NULL;
|
|
712 | 750 | ftSize_ = NULL;
|
713 | 751 | }
|
714 | 752 | }
|
... | ... | @@ -725,6 +763,7 @@ Engine::setTTInterpreterVersion(int version) |
725 | 763 | {
|
726 | 764 | // reset the cache
|
727 | 765 | FTC_Manager_Reset(cacheManager_);
|
766 | + ftFallbackFace_ = NULL;
|
|
728 | 767 | ftSize_ = NULL;
|
729 | 768 | }
|
730 | 769 | }
|
... | ... | @@ -753,6 +792,7 @@ Engine::setStemDarkening(bool darkening) |
753 | 792 | &noDarkening);
|
754 | 793 | // reset the cache
|
755 | 794 | FTC_Manager_Reset(cacheManager_);
|
795 | + ftFallbackFace_ = NULL;
|
|
756 | 796 | ftSize_ = NULL;
|
757 | 797 | }
|
758 | 798 | |
... | ... | @@ -931,7 +971,7 @@ Engine::loadPaletteInfos() |
931 | 971 | {
|
932 | 972 | curPaletteInfos_.clear();
|
933 | 973 | |
934 | - if (FT_Palette_Data_Get(ftSize_->face, &paletteData_))
|
|
974 | + if (FT_Palette_Data_Get(ftFallbackFace_, &paletteData_))
|
|
935 | 975 | {
|
936 | 976 | // XXX Error handling
|
937 | 977 | paletteData_.num_palettes = 0;
|
... | ... | @@ -941,7 +981,7 @@ Engine::loadPaletteInfos() |
941 | 981 | // size never exceeds max val of ushort.
|
942 | 982 | curPaletteInfos_.reserve(paletteData_.num_palettes);
|
943 | 983 | for (int i = 0; i < paletteData_.num_palettes; ++i)
|
944 | - curPaletteInfos_.emplace_back(ftSize_->face, paletteData_, i,
|
|
984 | + curPaletteInfos_.emplace_back(ftFallbackFace_, paletteData_, i,
|
|
945 | 985 | &curSFNTNames_);
|
946 | 986 | }
|
947 | 987 | |
... | ... | @@ -987,18 +1027,70 @@ Engine::calculateForegroundTable() |
987 | 1027 | void
|
988 | 1028 | convertLCDToARGB(FT_Bitmap& bitmap,
|
989 | 1029 | QImage& image,
|
990 | - bool isBGR)
|
|
1030 | + bool isBGR,
|
|
1031 | + QVector<QRgb>& colorTable)
|
|
991 | 1032 | {
|
992 | - // TODO to be implemented
|
|
1033 | + int height = bitmap.rows;
|
|
1034 | + int width = bitmap.width / 3;
|
|
1035 | + int width3 = bitmap.width;
|
|
1036 | + |
|
1037 | + unsigned char* srcPtr = bitmap.buffer;
|
|
1038 | + unsigned* dstPtr = reinterpret_cast<unsigned*>(image.bits());
|
|
1039 | + |
|
1040 | + int offR = !isBGR ? 0 : 2;
|
|
1041 | + int offG = 1;
|
|
1042 | + int offB = isBGR ? 0 : 2;
|
|
1043 | + for (int i = 0; i < height; i++)
|
|
1044 | + {
|
|
1045 | + for (int j = 0; j < width3; j += 3)
|
|
1046 | + {
|
|
1047 | + unsigned char ar = srcPtr[j + offR];
|
|
1048 | + unsigned char ag = srcPtr[j + offG];
|
|
1049 | + unsigned char ab = srcPtr[j + offB];
|
|
1050 | + unsigned dr = colorTable[ar] & 0xFF;
|
|
1051 | + unsigned dg = colorTable[ag] & 0xFF;
|
|
1052 | + unsigned db = colorTable[ab] & 0xFF;
|
|
1053 | + *dstPtr = (0xFFu << 24) | (dr << 16) | (dg << 8) | db;
|
|
1054 | + dstPtr++;
|
|
1055 | + }
|
|
1056 | + srcPtr += bitmap.pitch;
|
|
1057 | + dstPtr += image.bytesPerLine() / 4 - width; // skip blank area
|
|
1058 | + }
|
|
993 | 1059 | }
|
994 | 1060 | |
995 | 1061 | |
996 | 1062 | void
|
997 | 1063 | convertLCDVToARGB(FT_Bitmap& bitmap,
|
998 | 1064 | QImage& image,
|
999 | - bool isBGR)
|
|
1065 | + bool isBGR,
|
|
1066 | + QVector<QRgb>& colorTable)
|
|
1000 | 1067 | {
|
1001 | - // TODO to be implemented
|
|
1068 | + int height = bitmap.rows / 3;
|
|
1069 | + int width = bitmap.width;
|
|
1070 | + int srcPitch = bitmap.pitch;
|
|
1071 | + |
|
1072 | + unsigned char* srcPtr = bitmap.buffer;
|
|
1073 | + unsigned* dstPtr = reinterpret_cast<unsigned*>(image.bits());
|
|
1074 | + |
|
1075 | + int offR = !isBGR ? 0 : 2 * srcPitch;
|
|
1076 | + int offG = srcPitch;
|
|
1077 | + int offB = isBGR ? 0 : 2 * srcPitch;
|
|
1078 | + for (int i = 0; i < height; i++)
|
|
1079 | + {
|
|
1080 | + for (int j = 0; j < width; j++)
|
|
1081 | + {
|
|
1082 | + unsigned char ar = srcPtr[j + offR];
|
|
1083 | + unsigned char ag = srcPtr[j + offG];
|
|
1084 | + unsigned char ab = srcPtr[j + offB];
|
|
1085 | + unsigned dr = colorTable[ar] & 0xFF;
|
|
1086 | + unsigned dg = colorTable[ag] & 0xFF;
|
|
1087 | + unsigned db = colorTable[ab] & 0xFF;
|
|
1088 | + *dstPtr = (0xFFu << 24) | (dr << 16) | (dg << 8) | db;
|
|
1089 | + dstPtr++;
|
|
1090 | + }
|
|
1091 | + srcPtr += 3ull * srcPitch; // move 3 lines
|
|
1092 | + dstPtr += image.bytesPerLine() / 4 - width; // skip blank area
|
|
1093 | + }
|
|
1002 | 1094 | }
|
1003 | 1095 | |
1004 | 1096 | |
... | ... | @@ -1076,11 +1168,11 @@ Engine::convertBitmapToQImage(FT_Bitmap* src) |
1076 | 1168 | break;
|
1077 | 1169 | case FT_PIXEL_MODE_LCD:;
|
1078 | 1170 | result = new QImage(width, height, format);
|
1079 | - convertLCDToARGB(bmap, *result, lcdUsesBGR_);
|
|
1171 | + convertLCDToARGB(bmap, *result, lcdUsesBGR_, foregroundTable_);
|
|
1080 | 1172 | break;
|
1081 | 1173 | case FT_PIXEL_MODE_LCD_V:;
|
1082 | 1174 | result = new QImage(width, height, format);
|
1083 | - convertLCDVToARGB(bmap, *result, lcdUsesBGR_);
|
|
1175 | + convertLCDVToARGB(bmap, *result, lcdUsesBGR_, foregroundTable_);
|
|
1084 | 1176 | break;
|
1085 | 1177 | }
|
1086 | 1178 |
... | ... | @@ -131,9 +131,12 @@ public: |
131 | 131 | int dpi() { return dpi_; }
|
132 | 132 | double pointSize() { return pointSize_; }
|
133 | 133 | |
134 | + bool renderReady();
|
|
135 | + bool fontValid();
|
|
134 | 136 | int numberOfOpenedFonts();
|
135 | 137 | int currentFontIndex() { return curFontIndex_; }
|
136 | - FT_Size currentFtSize() { return ftSize_; }
|
|
138 | + FT_Face currentFallbackFtFace() { return ftFallbackFace_; }
|
|
139 | + // FT_Size currentFtSize() { return ftSize_; }
|
|
137 | 140 | int currentFontType() const { return fontType_; }
|
138 | 141 | const QString& currentFamilyName() { return curFamilyName_; }
|
139 | 142 | const QString& currentStyleName() { return curStyleName_; }
|
... | ... | @@ -247,6 +250,7 @@ private: |
247 | 250 | |
248 | 251 | FTC_ScalerRec scaler_ = {};
|
249 | 252 | FTC_ImageTypeRec imageType_;
|
253 | + FT_Face ftFallbackFace_; // Never perform rendering or write to this!
|
|
250 | 254 | FT_Size ftSize_;
|
251 | 255 | FT_Palette_Data paletteData_ = {};
|
252 | 256 | FT_Color* palette_ = NULL;
|
... | ... | @@ -32,14 +32,13 @@ void |
32 | 32 | SFNTName::get(Engine* engine,
|
33 | 33 | std::vector<SFNTName>& list)
|
34 | 34 | {
|
35 | - auto size = engine->currentFtSize();
|
|
36 | - if (!size || !FT_IS_SFNT(size->face))
|
|
35 | + auto face = engine->currentFallbackFtFace();
|
|
36 | + if (!face || !FT_IS_SFNT(face))
|
|
37 | 37 | {
|
38 | 38 | list.clear();
|
39 | 39 | return;
|
40 | 40 | }
|
41 | - |
|
42 | - auto face = size->face;
|
|
41 | +
|
|
43 | 42 | auto newSize = FT_Get_Sfnt_Name_Count(face);
|
44 | 43 | if (list.size() != static_cast<size_t>(newSize))
|
45 | 44 | list.resize(newSize);
|
... | ... | @@ -184,11 +183,10 @@ FontBasicInfo::get(Engine* engine) |
184 | 183 | result.numFaces = engine->numberOfFaces(fontIndex);
|
185 | 184 | |
186 | 185 | engine->reloadFont();
|
187 | - auto size = engine->currentFtSize();
|
|
188 | - if (!size)
|
|
186 | + auto face = engine->currentFallbackFtFace();
|
|
187 | + if (!face)
|
|
189 | 188 | return result;
|
190 | 189 | |
191 | - auto face = size->face;
|
|
192 | 190 | if (face->family_name)
|
193 | 191 | result.familyName = QString(face->family_name);
|
194 | 192 | if (face->style_name)
|
... | ... | @@ -228,12 +226,10 @@ FontTypeEntries |
228 | 226 | FontTypeEntries::get(Engine* engine)
|
229 | 227 | {
|
230 | 228 | engine->reloadFont();
|
231 | - auto size = engine->currentFtSize();
|
|
232 | - if (!size)
|
|
229 | + auto face = engine->currentFallbackFtFace();
|
|
230 | + if (!face)
|
|
233 | 231 | return {};
|
234 | - |
|
235 | - auto face = size->face;
|
|
236 | - |
|
232 | +
|
|
237 | 233 | FontTypeEntries result = {};
|
238 | 234 | result.driverName = QString(FT_FACE_DRIVER_NAME(face));
|
239 | 235 | result.sfnt = FT_IS_SFNT(face);
|
... | ... | @@ -332,8 +328,8 @@ FontFixedSize::get(Engine* engine, |
332 | 328 | const std::function<void()>& onUpdateNeeded)
|
333 | 329 | {
|
334 | 330 | engine->reloadFont();
|
335 | - auto size = engine->currentFtSize();
|
|
336 | - if (!size)
|
|
331 | + auto face = engine->currentFallbackFtFace();
|
|
332 | + if (!face)
|
|
337 | 333 | {
|
338 | 334 | if (list.empty())
|
339 | 335 | return false;
|
... | ... | @@ -342,8 +338,7 @@ FontFixedSize::get(Engine* engine, |
342 | 338 | list.clear();
|
343 | 339 | return true;
|
344 | 340 | }
|
345 | - |
|
346 | - auto face = size->face;
|
|
341 | +
|
|
347 | 342 | auto changed = false;
|
348 | 343 | if (list.size() != static_cast<size_t>(face->num_fixed_sizes))
|
349 | 344 | {
|
... | ... | @@ -510,8 +505,8 @@ SFNTTableInfo::getForAll(Engine* engine, |
510 | 505 | std::vector<SFNTTableInfo>& infos)
|
511 | 506 | {
|
512 | 507 | infos.clear();
|
513 | - auto size = engine->currentFtSize();
|
|
514 | - if (!size || !FT_IS_SFNT(size->face))
|
|
508 | + auto face = engine->currentFallbackFtFace();
|
|
509 | + if (!face || !FT_IS_SFNT(face))
|
|
515 | 510 | return;
|
516 | 511 | |
517 | 512 | auto index = engine->currentFontIndex();
|
... | ... | @@ -13,13 +13,12 @@ MMGXState |
13 | 13 | MMGXAxisInfo::get(Engine* engine,
|
14 | 14 | std::vector<MMGXAxisInfo>& infos)
|
15 | 15 | {
|
16 | - auto size = engine->currentFtSize();
|
|
17 | - if (!size)
|
|
16 | + auto face = engine->currentFallbackFtFace();
|
|
17 | + if (!face)
|
|
18 | 18 | {
|
19 | 19 | infos.clear();
|
20 | 20 | return MMGXState::NoMMGX;
|
21 | 21 | }
|
22 | - auto face = size->face;
|
|
23 | 22 | |
24 | 23 | if (!FT_HAS_MULTIPLE_MASTERS(face))
|
25 | 24 | {
|
... | ... | @@ -150,6 +150,8 @@ void |
150 | 150 | StringRenderer::prepareRendering()
|
151 | 151 | {
|
152 | 152 | engine_->reloadFont();
|
153 | + if (!engine_->renderReady())
|
|
154 | + return;
|
|
153 | 155 | engine_->loadPalette();
|
154 | 156 | if (kerningDegree_ != KD_None)
|
155 | 157 | trackingKerning_ = engine_->currentFontTrackingKerning(kerningDegree_);
|
... | ... | @@ -346,11 +348,13 @@ StringRenderer::render(int width, |
346 | 348 | int height,
|
347 | 349 | int offset)
|
348 | 350 | {
|
351 | + engine_->reloadFont();
|
|
352 | + |
|
349 | 353 | if (usingString_)
|
350 | 354 | offset = 0;
|
351 | 355 | if (!usingString_ && limitIndex_ <= 0)
|
352 | 356 | return 0;
|
353 | - if (engine_->currentFontNumberOfGlyphs() <= 0)
|
|
357 | + if (!engine_->fontValid())
|
|
354 | 358 | return 0;
|
355 | 359 | |
356 | 360 | // Separated into 3 modes:
|
... | ... | @@ -379,6 +383,8 @@ StringRenderer::render(int width, |
379 | 383 | // 64.0 is somewhat a magic reference number
|
380 | 384 | engine_->setSizeByPoint(64.0);
|
381 | 385 | engine_->reloadFont();
|
386 | + if (!engine_->renderReady())
|
|
387 | + return -1; // TODO: Handle bitmap-only fonts
|
|
382 | 388 | auto pixelActual = engine_->currentFontMetrics().height >> 6;
|
383 | 389 | |
384 | 390 | auto heightPt = height * 64.0 / pixelActual;
|
... | ... | @@ -441,6 +447,8 @@ StringRenderer::render(int width, |
441 | 447 | // Fill the whole canvas
|
442 | 448 | |
443 | 449 | prepareRendering();
|
450 | + if (!engine_->renderReady())
|
|
451 | + return 0;
|
|
444 | 452 | auto& metrics = engine_->currentFontMetrics();
|
445 | 453 | auto y = 4 + static_cast<int>(metrics.ascender >> 6);
|
446 | 454 | auto stepY = static_cast<int>(metrics.height >> 6) + 1;
|
... | ... | @@ -459,6 +467,9 @@ StringRenderer::render(int width, |
459 | 467 | |
460 | 468 | // Single string
|
461 | 469 | prepareRendering();
|
470 | + if (!engine_->renderReady())
|
|
471 | + return 0;
|
|
472 | + |
|
462 | 473 | auto& metrics = engine_->currentFontMetrics();
|
463 | 474 | auto x = static_cast<int>(width * position_);
|
464 | 475 | // Anchor at top-left in vertical mode, at the center in horizontal mode
|
... | ... | @@ -414,8 +414,8 @@ void |
414 | 414 | SFNTInfoTab::reloadFont()
|
415 | 415 | {
|
416 | 416 | engine_->reloadFont();
|
417 | - auto size = engine_->currentFtSize();
|
|
418 | - if (!size || !FT_IS_SFNT(size->face))
|
|
417 | + auto face = engine_->currentFallbackFtFace();
|
|
418 | + if (!face || !FT_IS_SFNT(face))
|
|
419 | 419 | setEnabled(false);
|
420 | 420 | |
421 | 421 | if (engine_->currentFontSFNTNames() != sfntNamesModel_->storage())
|
... | ... | @@ -252,27 +252,30 @@ GlyphContinuous::paintByRenderer() |
252 | 252 | void
|
253 | 253 | GlyphContinuous::transformGlyphFancy(FT_Glyph glyph)
|
254 | 254 | {
|
255 | + auto& metrics = engine_->currentFontMetrics();
|
|
256 | + auto emboldeningX = (FT_Pos)(metrics.y_ppem * 64 * boldX_);
|
|
257 | + auto emboldeningY = (FT_Pos)(metrics.y_ppem * 64 * boldY_);
|
|
255 | 258 | // adopted from ftview.c:289
|
256 | 259 | if (glyph->format == FT_GLYPH_FORMAT_OUTLINE)
|
257 | 260 | {
|
258 | 261 | auto outline = reinterpret_cast<FT_OutlineGlyph>(glyph)->outline;
|
259 | 262 | FT_Glyph_Transform(glyph, &shearMatrix_, NULL);
|
260 | - if (FT_Outline_EmboldenXY(&outline, emboldeningX_, emboldeningY_))
|
|
263 | + if (FT_Outline_EmboldenXY(&outline, emboldeningX, emboldeningY))
|
|
261 | 264 | {
|
262 | 265 | // XXX error handling?
|
263 | 266 | return;
|
264 | 267 | }
|
265 | 268 | |
266 | 269 | if (glyph->advance.x)
|
267 | - glyph->advance.x += emboldeningX_;
|
|
270 | + glyph->advance.x += emboldeningX;
|
|
268 | 271 | |
269 | 272 | if (glyph->advance.y)
|
270 | - glyph->advance.y += emboldeningY_;
|
|
273 | + glyph->advance.y += emboldeningY;
|
|
271 | 274 | }
|
272 | 275 | else if (glyph->format == FT_GLYPH_FORMAT_BITMAP)
|
273 | 276 | {
|
274 | - auto xstr = emboldeningX_ & ~63;
|
|
275 | - auto ystr = emboldeningY_ & ~63;
|
|
277 | + auto xstr = emboldeningX & ~63;
|
|
278 | + auto ystr = emboldeningY & ~63;
|
|
276 | 279 | |
277 | 280 | auto bitmap = &reinterpret_cast<FT_BitmapGlyph>(glyph)->bitmap;
|
278 | 281 | // No shearing support for bitmap
|
... | ... | @@ -326,13 +329,6 @@ void |
326 | 329 | GlyphContinuous::prePaint()
|
327 | 330 | {
|
328 | 331 | displayingCount_ = 0;
|
329 | - engine_->reloadFont();
|
|
330 | - if (engine_->currentFontNumberOfGlyphs() > 0)
|
|
331 | - metrics_ = engine_->currentFontMetrics();
|
|
332 | - x_ = 0;
|
|
333 | - // See ftview.c:42
|
|
334 | - y_ = ((metrics_.ascender - metrics_.descender + 63) >> 6) + 4;
|
|
335 | - stepY_ = ((metrics_.height + 63) >> 6) + 4;
|
|
336 | 332 | |
337 | 333 | // Used by fancy:
|
338 | 334 | // adopted from ftview.c:289
|
... | ... | @@ -355,18 +351,22 @@ GlyphContinuous::prePaint() |
355 | 351 | shearMatrix_.xy = static_cast<FT_Fixed>(slant_ * (1 << 16));
|
356 | 352 | shearMatrix_.yx = 0;
|
357 | 353 | shearMatrix_.yy = 1 << 16;
|
354 | +}
|
|
358 | 355 | |
359 | - emboldeningX_ = (FT_Pos)(metrics_.y_ppem * 64 * boldX_);
|
|
360 | - emboldeningY_ = (FT_Pos)(metrics_.y_ppem * 64 * boldY_);
|
|
361 | 356 | |
362 | - if (mode_ == M_Stroked)
|
|
363 | - {
|
|
364 | - auto radius = static_cast<FT_Fixed>(metrics_.y_ppem * 64 * strokeRadius_);
|
|
365 | - FT_Stroker_Set(stroker_, radius,
|
|
366 | - FT_STROKER_LINECAP_ROUND,
|
|
367 | - FT_STROKER_LINEJOIN_ROUND,
|
|
368 | - 0);
|
|
369 | - }
|
|
357 | +void
|
|
358 | +GlyphContinuous::updateStroke()
|
|
359 | +{
|
|
360 | + if (mode_ != M_Stroked || !engine_->renderReady())
|
|
361 | + return;
|
|
362 | + |
|
363 | + auto& metrics = engine_->currentFontMetrics();
|
|
364 | + auto radius = static_cast<FT_Fixed>(metrics.y_ppem * 64 * strokeRadius_);
|
|
365 | + strokeRadiusForSize_ = radius;
|
|
366 | + FT_Stroker_Set(stroker_, radius,
|
|
367 | + FT_STROKER_LINECAP_ROUND,
|
|
368 | + FT_STROKER_LINEJOIN_ROUND,
|
|
369 | + 0);
|
|
370 | 370 | }
|
371 | 371 | |
372 | 372 | |
... | ... | @@ -452,6 +452,7 @@ GlyphContinuous::saveSingleGlyphImage(QImage* image, |
452 | 452 | entry.glyphIndex = gctx.glyphIndex;
|
453 | 453 | entry.advance = advance;
|
454 | 454 | entry.penPos = penPosPoint;
|
455 | + entry.yPpem = engine_->currentFontMetrics().y_ppem;
|
|
455 | 456 | }
|
456 | 457 | |
457 | 458 | |
... | ... | @@ -486,7 +487,7 @@ GlyphContinuous::drawCacheGlyph(QPainter* painter, |
486 | 487 | // ftview.c:557
|
487 | 488 | // Well, metrics is also part of the cache...
|
488 | 489 | int width = entry.advance.x ? entry.advance.x >> 16
|
489 | - : metrics_.y_ppem / 2;
|
|
490 | + : entry.yPpem / 2;
|
|
490 | 491 | |
491 | 492 | if (entry.advance.x == 0 && !stringRenderer_.isWaterfall())
|
492 | 493 | {
|
... | ... | @@ -26,6 +26,7 @@ struct GlyphCacheEntry |
26 | 26 | QPoint penPos = {};
|
27 | 27 | int charCode = -1;
|
28 | 28 | int glyphIndex = -1;
|
29 | + unsigned yPpem = 0;
|
|
29 | 30 | |
30 | 31 | FT_Vector advance = {};
|
31 | 32 | |
... | ... | @@ -123,10 +124,7 @@ private: |
123 | 124 | |
124 | 125 | bool mouseOperationEnabled_ = true;
|
125 | 126 | int displayingCount_ = 0;
|
126 | - FT_Size_Metrics metrics_;
|
|
127 | - int x_ = 0, y_ = 0;
|
|
128 | - int stepY_ = 0;
|
|
129 | - FT_Pos emboldeningX_, emboldeningY_;
|
|
127 | + FT_Fixed strokeRadiusForSize_ = 0;
|
|
130 | 128 | FT_Matrix shearMatrix_;
|
131 | 129 | |
132 | 130 | FT_Stroker stroker_;
|
... | ... | @@ -152,6 +150,7 @@ private: |
152 | 150 | void paintCache(QPainter* painter);
|
153 | 151 | void fillCache();
|
154 | 152 | void prePaint();
|
153 | + void updateStroke();
|
|
155 | 154 | void updateRendererText();
|
156 | 155 | void preprocessGlyph(FT_Glyph* glyphPtr);
|
157 | 156 | void beginSaveLine(FT_Vector pos,
|
... | ... | @@ -436,8 +436,9 @@ TripletSelector::loadTriplet() |
436 | 436 | }
|
437 | 437 | |
438 | 438 | auto number = engine_->loadFont(fontIndex, faceIndex, instanceIndex);
|
439 | - |
|
440 | - if (number < 0)
|
|
439 | +
|
|
440 | + // TODO: This may messes up with bitmap-only fonts.
|
|
441 | + if (!engine_->fontValid())
|
|
441 | 442 | {
|
442 | 443 | // there might be various reasons why the current
|
443 | 444 | // (file, face, instance) triplet is invalid or missing;
|