freetype-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Git][freetype/freetype-demos][gsoc-2022-chariri-3] [ftinspect] Extract


From: Charlie Jiang (@cqjjjzr)
Subject: [Git][freetype/freetype-demos][gsoc-2022-chariri-3] [ftinspect] Extract out rendering-related code from `Engine`.
Date: Tue, 23 Aug 2022 16:02:39 +0000

Charlie Jiang pushed to branch gsoc-2022-chariri-3 at FreeType / FreeType Demo Programs

Commits:

  • e9fcd920
    by Charlie Jiang at 2022-08-24T00:00:06+08:00
    [ftinspect] Extract out rendering-related code from `Engine`.
    
    The current `Engine` class is too huge, so moving rendering code out
    to a new class `RenderingEngine`.
    
    * src/ftinspect/engine/rendering.cpp, src/ftinspect/engine/rendering.hpp:
      New file.
    
    * src/ftinspect/engine/engine.cpp, src/ftinspect/engine/engine.hpp:
      Move out code. Add getters for the rendering engine to use.
    
    * src/ftinspect/CMakeLists.txt, src/ftinspect/meson.build: Updated.
    
    * src/ftinspect/**: Updated to incorporate the refactoring.
    

11 changed files:

Changes:

  • src/ftinspect/CMakeLists.txt
    ... ... @@ -28,6 +28,7 @@ add_executable(ftinspect
    28 28
       "engine/fontinfo.cpp"
    
    29 29
       "engine/fontinfonamesmapping.cpp"
    
    30 30
       "engine/mmgx.cpp"
    
    31
    +  "engine/rendering.cpp"
    
    31 32
       "engine/renderutils.cpp"
    
    32 33
     
    
    33 34
       "glyphcomponents/glyphbitmap.cpp"
    

  • src/ftinspect/engine/engine.cpp
    ... ... @@ -163,9 +163,7 @@ Engine::Engine()
    163 163
       }
    
    164 164
       
    
    165 165
       queryEngine();
    
    166
    -
    
    167
    -  setForeground(QColor(Qt::black).rgba());
    
    168
    -  setBackground(QColor(Qt::white).rgba());
    
    166
    +  renderingEngine_ = std::make_unique<RenderingEngine>(this);
    
    169 167
     }
    
    170 168
     
    
    171 169
     
    
    ... ... @@ -649,57 +647,6 @@ Engine::loadGlyphWithoutUpdate(int glyphIndex,
    649 647
     }
    
    650 648
     
    
    651 649
     
    
    652
    -bool
    
    653
    -Engine::convertGlyphToBitmapGlyph(FT_Glyph src,
    
    654
    -                      FT_Glyph* out)
    
    655
    -{
    
    656
    -  if (src->format == FT_GLYPH_FORMAT_BITMAP)
    
    657
    -  {
    
    658
    -    *out = src;
    
    659
    -    return false;
    
    660
    -  }
    
    661
    -  if (src->format != FT_GLYPH_FORMAT_OUTLINE)
    
    662
    -  {
    
    663
    -    *out = NULL;
    
    664
    -    return false;
    
    665
    -    // TODO support SVG
    
    666
    -  }
    
    667
    -
    
    668
    -  if (src->format == FT_GLYPH_FORMAT_OUTLINE)
    
    669
    -  {
    
    670
    -    FT_Glyph out2 = src;
    
    671
    -    auto error = FT_Glyph_To_Bitmap(&out2, 
    
    672
    -                                    static_cast<FT_Render_Mode>(renderMode_),
    
    673
    -                                    nullptr,
    
    674
    -                                    false);
    
    675
    -    if (error)
    
    676
    -    {
    
    677
    -      *out = NULL;
    
    678
    -      return false;
    
    679
    -    }
    
    680
    -    *out = out2;
    
    681
    -    return true;
    
    682
    -  }
    
    683
    -
    
    684
    -  *out = NULL;
    
    685
    -  return false;
    
    686
    -}
    
    687
    -
    
    688
    -
    
    689
    -FT_Bitmap
    
    690
    -Engine::convertBitmapTo8Bpp(FT_Bitmap* bitmap)
    
    691
    -{
    
    692
    -  FT_Bitmap out;
    
    693
    -  out.buffer = NULL;
    
    694
    -  auto error = FT_Bitmap_Convert(library_, bitmap, &out, 1);
    
    695
    -  if (error)
    
    696
    -  {
    
    697
    -    // XXX handling?
    
    698
    -  }
    
    699
    -  return out;
    
    700
    -}
    
    701
    -
    
    702
    -
    
    703 650
     bool
    
    704 651
     Engine::renderReady()
    
    705 652
     {
    
    ... ... @@ -751,7 +698,7 @@ Engine::setGamma(double gamma)
    751 698
       if (gamma_ != gamma)
    
    752 699
       {
    
    753 700
         gamma_ = gamma;
    
    754
    -    calculateForegroundTable();
    
    701
    +    renderingEngine_->calculateForegroundTable();
    
    755 702
       }
    
    756 703
     }
    
    757 704
     
    
    ... ... @@ -824,28 +771,6 @@ Engine::applyMMGXDesignCoords(FT_Fixed* coords,
    824 771
     }
    
    825 772
     
    
    826 773
     
    
    827
    -void
    
    828
    -Engine::setForeground(QRgb foreground)
    
    829
    -{
    
    830
    -  if (foregroundTable_.size() != 256 || foreground != foregroundColor_)
    
    831
    -  {
    
    832
    -    foregroundColor_ = foreground;
    
    833
    -    calculateForegroundTable();
    
    834
    -  }
    
    835
    -}
    
    836
    -
    
    837
    -
    
    838
    -void
    
    839
    -Engine::setBackground(QRgb background)
    
    840
    -{
    
    841
    -  if (foregroundTable_.size() != 256 || background != backgroundColor_)
    
    842
    -  {
    
    843
    -    backgroundColor_ = background;
    
    844
    -    calculateForegroundTable();
    
    845
    -  }
    
    846
    -}
    
    847
    -
    
    848
    -
    
    849 774
     void
    
    850 775
     Engine::update()
    
    851 776
     {
    
    ... ... @@ -1023,400 +948,6 @@ Engine::loadPaletteInfos()
    1023 948
     }
    
    1024 949
     
    
    1025 950
     
    
    1026
    -void
    
    1027
    -Engine::calculateForegroundTable()
    
    1028
    -{
    
    1029
    -  foregroundTable_.resize(256);
    
    1030
    -
    
    1031
    -  // Yes I know this is horribly slow, but we're only calculating the table once
    
    1032
    -  // and can use it for all rendering if the color and gamma isn't changing.
    
    1033
    -
    
    1034
    -  double br = std::pow(qRed(backgroundColor_) / 255.0, gamma_);
    
    1035
    -  double bg = std::pow(qGreen(backgroundColor_) / 255.0, gamma_);
    
    1036
    -  double bb = std::pow(qBlue(backgroundColor_) / 255.0, gamma_);
    
    1037
    -  double invGamma = 1 / gamma_;
    
    1038
    -
    
    1039
    -  for (int i = 0; i <= 0xFF; i++)
    
    1040
    -  {
    
    1041
    -    double foreAlpha = i * qAlpha(foregroundColor_) / 255.0 / 255.0;
    
    1042
    -    double backAlpha = 1 - foreAlpha;
    
    1043
    -    double r = std::pow(qRed(foregroundColor_) / 255.0, gamma_);
    
    1044
    -    double g = std::pow(qGreen(foregroundColor_) / 255.0, gamma_);
    
    1045
    -    double b = std::pow(qBlue(foregroundColor_) / 255.0, gamma_);
    
    1046
    -
    
    1047
    -    r = br * backAlpha + r * foreAlpha;
    
    1048
    -    g = bg * backAlpha + g * foreAlpha;
    
    1049
    -    b = bb * backAlpha + b * foreAlpha;
    
    1050
    -
    
    1051
    -    r = std::pow(r, invGamma);
    
    1052
    -    g = std::pow(g, invGamma);
    
    1053
    -    b = std::pow(b, invGamma);
    
    1054
    -
    
    1055
    -    foregroundTable_[i]
    
    1056
    -        = qRgba(static_cast<int>(r * 255), 
    
    1057
    -                static_cast<int>(g * 255),
    
    1058
    -                static_cast<int>(b * 255), 
    
    1059
    -                255);
    
    1060
    -  }
    
    1061
    -}
    
    1062
    -
    
    1063
    -
    
    1064
    -void
    
    1065
    -convertLCDToARGB(FT_Bitmap& bitmap,
    
    1066
    -                 QImage& image,
    
    1067
    -                 bool isBGR,
    
    1068
    -                 QVector<QRgb>& colorTable)
    
    1069
    -{
    
    1070
    -  int height = bitmap.rows;
    
    1071
    -  int width = bitmap.width / 3;
    
    1072
    -  int width3 = bitmap.width;
    
    1073
    -
    
    1074
    -  unsigned char* srcPtr = bitmap.buffer;
    
    1075
    -  unsigned* dstPtr = reinterpret_cast<unsigned*>(image.bits());
    
    1076
    -
    
    1077
    -  int offR = !isBGR ? 0 : 2;
    
    1078
    -  int offG = 1;
    
    1079
    -  int offB = isBGR ? 0 : 2;
    
    1080
    -  for (int i = 0; i < height; i++)
    
    1081
    -  {
    
    1082
    -    for (int j = 0; j < width3; j += 3)
    
    1083
    -    {
    
    1084
    -      unsigned char ar = srcPtr[j + offR];
    
    1085
    -      unsigned char ag = srcPtr[j + offG];
    
    1086
    -      unsigned char ab = srcPtr[j + offB];
    
    1087
    -      unsigned dr = colorTable[ar] & 0xFF;
    
    1088
    -      unsigned dg = colorTable[ag] & 0xFF;
    
    1089
    -      unsigned db = colorTable[ab] & 0xFF;
    
    1090
    -      *dstPtr = (0xFFu << 24) | (dr << 16) | (dg << 8) | db;
    
    1091
    -      dstPtr++;
    
    1092
    -    }
    
    1093
    -    srcPtr += bitmap.pitch;
    
    1094
    -    dstPtr += image.bytesPerLine() / 4 - width; // skip blank area
    
    1095
    -  }
    
    1096
    -}
    
    1097
    -
    
    1098
    -
    
    1099
    -void
    
    1100
    -convertLCDVToARGB(FT_Bitmap& bitmap,
    
    1101
    -                  QImage& image,
    
    1102
    -                  bool isBGR,
    
    1103
    -                  QVector<QRgb>& colorTable)
    
    1104
    -{
    
    1105
    -  int height = bitmap.rows / 3;
    
    1106
    -  int width = bitmap.width;
    
    1107
    -  int srcPitch = bitmap.pitch;
    
    1108
    -
    
    1109
    -  unsigned char* srcPtr = bitmap.buffer;
    
    1110
    -  unsigned* dstPtr = reinterpret_cast<unsigned*>(image.bits());
    
    1111
    -
    
    1112
    -  int offR = !isBGR ? 0 : 2 * srcPitch;
    
    1113
    -  int offG = srcPitch;
    
    1114
    -  int offB = isBGR ? 0 : 2 * srcPitch;
    
    1115
    -  for (int i = 0; i < height; i++)
    
    1116
    -  {
    
    1117
    -    for (int j = 0; j < width; j++)
    
    1118
    -    {
    
    1119
    -      unsigned char ar = srcPtr[j + offR];
    
    1120
    -      unsigned char ag = srcPtr[j + offG];
    
    1121
    -      unsigned char ab = srcPtr[j + offB];
    
    1122
    -      unsigned dr = colorTable[ar] & 0xFF;
    
    1123
    -      unsigned dg = colorTable[ag] & 0xFF;
    
    1124
    -      unsigned db = colorTable[ab] & 0xFF;
    
    1125
    -      *dstPtr = (0xFFu << 24) | (dr << 16) | (dg << 8) | db;
    
    1126
    -      dstPtr++;
    
    1127
    -    }
    
    1128
    -    srcPtr += 3ull * srcPitch;                  // move 3 lines
    
    1129
    -    dstPtr += image.bytesPerLine() / 4 - width; // skip blank area
    
    1130
    -  }
    
    1131
    -}
    
    1132
    -
    
    1133
    -
    
    1134
    -QImage*
    
    1135
    -Engine::convertBitmapToQImage(FT_Bitmap* src)
    
    1136
    -{
    
    1137
    -  QImage* result = NULL;
    
    1138
    -  
    
    1139
    -  auto& bmap = *src;
    
    1140
    -  bool ownBitmap = false;
    
    1141
    -
    
    1142
    -  int width = INT_MAX, height = INT_MAX;
    
    1143
    -  if (bmap.width < INT_MAX)
    
    1144
    -    width = static_cast<int>(bmap.width);
    
    1145
    -  if (bmap.rows < INT_MAX)
    
    1146
    -    height = static_cast<int>(bmap.rows);
    
    1147
    -  auto format = QImage::Format_Indexed8; // goto crossing init
    
    1148
    -
    
    1149
    -  if (bmap.pixel_mode == FT_PIXEL_MODE_GRAY2
    
    1150
    -      || bmap.pixel_mode == FT_PIXEL_MODE_GRAY4)
    
    1151
    -  {
    
    1152
    -    bmap = convertBitmapTo8Bpp(&bmap);
    
    1153
    -    if (!bmap.buffer)
    
    1154
    -      goto cleanup;
    
    1155
    -    ownBitmap = true;
    
    1156
    -  }
    
    1157
    -
    
    1158
    -  if (bmap.pixel_mode == FT_PIXEL_MODE_LCD)
    
    1159
    -    width /= 3;
    
    1160
    -  else if (bmap.pixel_mode == FT_PIXEL_MODE_LCD_V)
    
    1161
    -    height /= 3;
    
    1162
    -
    
    1163
    -  switch (bmap.pixel_mode)
    
    1164
    -  {
    
    1165
    -  case FT_PIXEL_MODE_MONO:
    
    1166
    -    format = QImage::Format_Mono;
    
    1167
    -    break;
    
    1168
    -  case FT_PIXEL_MODE_GRAY:
    
    1169
    -    format = QImage::Format_Indexed8;
    
    1170
    -    break;
    
    1171
    -  case FT_PIXEL_MODE_BGRA:
    
    1172
    -    // XXX "ARGB" here means BGRA due to endianness - may be problematic
    
    1173
    -    // on big-endian machines
    
    1174
    -    format = QImage::Format_ARGB32_Premultiplied;
    
    1175
    -    break;
    
    1176
    -  case FT_PIXEL_MODE_LCD:
    
    1177
    -  case FT_PIXEL_MODE_LCD_V:
    
    1178
    -    format = QImage::Format_ARGB32;
    
    1179
    -    break;
    
    1180
    -  default:
    
    1181
    -    goto cleanup;
    
    1182
    -  }
    
    1183
    -
    
    1184
    -  switch (bmap.pixel_mode) 
    
    1185
    -  {
    
    1186
    -  case FT_PIXEL_MODE_MONO:
    
    1187
    -  case FT_PIXEL_MODE_GRAY:
    
    1188
    -  case FT_PIXEL_MODE_BGRA:
    
    1189
    -    {
    
    1190
    -      QImage image(bmap.buffer, 
    
    1191
    -                   width, height, 
    
    1192
    -                   bmap.pitch, 
    
    1193
    -                   format);
    
    1194
    -      if (bmap.pixel_mode == FT_PIXEL_MODE_GRAY)
    
    1195
    -        image.setColorTable(foregroundTable_);
    
    1196
    -      else if (bmap.pixel_mode == FT_PIXEL_MODE_MONO)
    
    1197
    -      {
    
    1198
    -        image.setColorCount(2);
    
    1199
    -        image.setColor(0, static_cast<QRgb>(0)); // transparent
    
    1200
    -        image.setColor(1, foregroundTable_[0xFF]);
    
    1201
    -      }
    
    1202
    -      result = new QImage(image.copy());
    
    1203
    -      // Don't directly use `image` since we're destroying the image
    
    1204
    -    }
    
    1205
    -    break;
    
    1206
    -  case FT_PIXEL_MODE_LCD:;
    
    1207
    -    result = new QImage(width, height, format);
    
    1208
    -    convertLCDToARGB(bmap, *result, lcdUsesBGR_, foregroundTable_);
    
    1209
    -    break;
    
    1210
    -  case FT_PIXEL_MODE_LCD_V:;
    
    1211
    -    result = new QImage(width, height, format);
    
    1212
    -    convertLCDVToARGB(bmap, *result, lcdUsesBGR_, foregroundTable_);
    
    1213
    -    break;
    
    1214
    -  }
    
    1215
    -
    
    1216
    -cleanup:
    
    1217
    -  if (ownBitmap)
    
    1218
    -    FT_Bitmap_Done(library_, &bmap);
    
    1219
    -
    
    1220
    -  return result;
    
    1221
    -}
    
    1222
    -
    
    1223
    -
    
    1224
    -QImage*
    
    1225
    -Engine::convertGlyphToQImage(FT_Glyph src,
    
    1226
    -                             QRect* outRect,
    
    1227
    -                             bool inverseRectY)
    
    1228
    -{
    
    1229
    -  FT_BitmapGlyph bitmapGlyph;
    
    1230
    -  bool ownBitmapGlyph
    
    1231
    -    = convertGlyphToBitmapGlyph(src, reinterpret_cast<FT_Glyph*>(&bitmapGlyph));
    
    1232
    -  if (!bitmapGlyph)
    
    1233
    -    return NULL;
    
    1234
    -
    
    1235
    -  auto result = convertBitmapToQImage(&bitmapGlyph->bitmap);
    
    1236
    -
    
    1237
    -  if (result && outRect)
    
    1238
    -  {
    
    1239
    -    outRect->setLeft(bitmapGlyph->left);
    
    1240
    -    if (inverseRectY)
    
    1241
    -      outRect->setTop(-bitmapGlyph->top);
    
    1242
    -    else
    
    1243
    -      outRect->setTop(bitmapGlyph->top);
    
    1244
    -    if (bitmapGlyph->bitmap.width < INT_MAX)
    
    1245
    -      outRect->setWidth(static_cast<int>(bitmapGlyph->bitmap.width));
    
    1246
    -    else
    
    1247
    -      outRect->setWidth(INT_MAX);
    
    1248
    -
    
    1249
    -    if (bitmapGlyph->bitmap.rows < INT_MAX)
    
    1250
    -      outRect->setHeight(static_cast<int>(bitmapGlyph->bitmap.rows));
    
    1251
    -    else
    
    1252
    -      outRect->setHeight(INT_MAX);
    
    1253
    -  }
    
    1254
    -
    
    1255
    -  if (ownBitmapGlyph)
    
    1256
    -    FT_Done_Glyph(reinterpret_cast<FT_Glyph>(bitmapGlyph));
    
    1257
    -
    
    1258
    -  return result;
    
    1259
    -}
    
    1260
    -
    
    1261
    -
    
    1262
    -QPoint
    
    1263
    -Engine::computeGlyphOffset(FT_Glyph glyph, bool inverseY)
    
    1264
    -{
    
    1265
    -  if (glyph->format == FT_GLYPH_FORMAT_OUTLINE)
    
    1266
    -  {
    
    1267
    -    FT_BBox cbox;
    
    1268
    -    FT_Outline_Get_CBox(&reinterpret_cast<FT_OutlineGlyph>(glyph)->outline, 
    
    1269
    -                        &cbox);
    
    1270
    -    cbox.xMin &= ~63;
    
    1271
    -    cbox.yMin &= ~63;
    
    1272
    -    cbox.xMax = (cbox.xMax + 63) & ~63;
    
    1273
    -    cbox.yMax = (cbox.yMax + 63) & ~63;
    
    1274
    -    if (inverseY)
    
    1275
    -      cbox.yMax = -cbox.yMax;
    
    1276
    -    return { static_cast<int>(cbox.xMin / 64),
    
    1277
    -             static_cast<int>(cbox.yMax / 64) };
    
    1278
    -  }
    
    1279
    -  if (glyph->format == FT_GLYPH_FORMAT_BITMAP)
    
    1280
    -  {
    
    1281
    -    auto bg = reinterpret_cast<FT_BitmapGlyph>(glyph);
    
    1282
    -    if (inverseY)
    
    1283
    -      return { bg->left, -bg->top };
    
    1284
    -    return { bg->left, bg->top };
    
    1285
    -  }
    
    1286
    -
    
    1287
    -  return {};
    
    1288
    -}
    
    1289
    -
    
    1290
    -
    
    1291
    -QImage*
    
    1292
    -Engine::tryDirectRenderColorLayers(int glyphIndex,
    
    1293
    -                                   QRect* outRect,
    
    1294
    -                                   bool inverseRectY)
    
    1295
    -{
    
    1296
    -  if (palette_ == NULL 
    
    1297
    -      || !useColorLayer_ 
    
    1298
    -      || paletteIndex_ >= paletteData_.num_palettes)
    
    1299
    -    return NULL;
    
    1300
    -
    
    1301
    -  FT_LayerIterator iter = {};
    
    1302
    -  
    
    1303
    -  FT_UInt layerGlyphIdx = 0;
    
    1304
    -  FT_UInt layerColorIdx = 0;
    
    1305
    -
    
    1306
    -  bool next = FT_Get_Color_Glyph_Layer(ftSize_->face,
    
    1307
    -                                       glyphIndex,
    
    1308
    -                                       &layerGlyphIdx,
    
    1309
    -                                       &layerColorIdx,
    
    1310
    -                                       &iter);
    
    1311
    -  if (!next)
    
    1312
    -    return NULL;
    
    1313
    -
    
    1314
    -  // temporarily change lf
    
    1315
    -  auto oldLoadFlags = imageType_.flags;
    
    1316
    -  auto loadFlags = oldLoadFlags;
    
    1317
    -  loadFlags &= ~FT_LOAD_COLOR;
    
    1318
    -  loadFlags |= FT_LOAD_RENDER;
    
    1319
    -
    
    1320
    -  loadFlags &= ~FT_LOAD_TARGET_(0xF);
    
    1321
    -  loadFlags |= FT_LOAD_TARGET_NORMAL;
    
    1322
    -  imageType_.flags = loadFlags;
    
    1323
    -
    
    1324
    -  FT_Bitmap bitmap = {};
    
    1325
    -  FT_Bitmap_Init(&bitmap);
    
    1326
    -
    
    1327
    -  FT_Vector bitmapOffset = {};
    
    1328
    -  bool failed = false;
    
    1329
    -
    
    1330
    -  do
    
    1331
    -  {
    
    1332
    -    FT_Vector slotOffset;
    
    1333
    -    FT_Glyph glyph;
    
    1334
    -    if (FTC_ImageCache_Lookup(imageCache_,
    
    1335
    -                              &imageType_,
    
    1336
    -                              layerGlyphIdx,
    
    1337
    -                              &glyph,
    
    1338
    -                              NULL))
    
    1339
    -    {
    
    1340
    -      // XXX Error handling
    
    1341
    -      failed = true;
    
    1342
    -      break;
    
    1343
    -    }
    
    1344
    -
    
    1345
    -    if (glyph->format != FT_GLYPH_FORMAT_BITMAP)
    
    1346
    -      continue;
    
    1347
    -
    
    1348
    -    auto bitmapGlyph = reinterpret_cast<FT_BitmapGlyph>(glyph);
    
    1349
    -    slotOffset.x = bitmapGlyph->left << 6;
    
    1350
    -    slotOffset.y = bitmapGlyph->top << 6;
    
    1351
    -
    
    1352
    -    FT_Color color = {};
    
    1353
    -
    
    1354
    -    if (layerColorIdx == 0xFFFF)
    
    1355
    -    {
    
    1356
    -      // TODO: FT_Palette_Get_Foreground_Color: #1134
    
    1357
    -      if (paletteData_.palette_flags
    
    1358
    -          && (paletteData_.palette_flags[paletteIndex_] 
    
    1359
    -              & FT_PALETTE_FOR_DARK_BACKGROUND))
    
    1360
    -      {
    
    1361
    -        /* white opaque */
    
    1362
    -        color.blue = 0xFF;
    
    1363
    -        color.green = 0xFF;
    
    1364
    -        color.red = 0xFF;
    
    1365
    -        color.alpha = 0xFF;
    
    1366
    -      }
    
    1367
    -      else
    
    1368
    -      {
    
    1369
    -        /* black opaque */
    
    1370
    -        color.blue = 0x00;
    
    1371
    -        color.green = 0x00;
    
    1372
    -        color.red = 0x00;
    
    1373
    -        color.alpha = 0xFF;
    
    1374
    -      }
    
    1375
    -    }
    
    1376
    -    else if (layerColorIdx < paletteData_.num_palette_entries)
    
    1377
    -      color = palette_[layerColorIdx];
    
    1378
    -    else
    
    1379
    -      continue;
    
    1380
    -
    
    1381
    -    if (FT_Bitmap_Blend(library_,
    
    1382
    -                        &bitmapGlyph->bitmap, slotOffset,
    
    1383
    -                        &bitmap, &bitmapOffset,
    
    1384
    -                        color))
    
    1385
    -    {
    
    1386
    -      // XXX error
    
    1387
    -      failed = true;
    
    1388
    -      break;
    
    1389
    -    }
    
    1390
    -  } while (FT_Get_Color_Glyph_Layer(ftSize_->face,
    
    1391
    -                                    glyphIndex,
    
    1392
    -                                    &layerGlyphIdx,
    
    1393
    -                                    &layerColorIdx,
    
    1394
    -                                    &iter));
    
    1395
    -
    
    1396
    -  imageType_.flags = oldLoadFlags;
    
    1397
    -  if (failed)
    
    1398
    -  {
    
    1399
    -    FT_Bitmap_Done(library_, &bitmap);
    
    1400
    -    return NULL;
    
    1401
    -  }
    
    1402
    -
    
    1403
    -  auto img = convertBitmapToQImage(&bitmap);
    
    1404
    -  if (outRect)
    
    1405
    -  {
    
    1406
    -    outRect->moveLeft(static_cast<int>(bitmapOffset.x >> 6));
    
    1407
    -    if (inverseRectY)
    
    1408
    -      outRect->moveTop(static_cast<int>(-bitmapOffset.y >> 6));
    
    1409
    -    else
    
    1410
    -      outRect->moveTop(static_cast<int>(bitmapOffset.y >> 6));
    
    1411
    -    outRect->setSize(img->size());
    
    1412
    -  }
    
    1413
    -
    
    1414
    -  FT_Bitmap_Done(library_, &bitmap);
    
    1415
    -
    
    1416
    -  return img;
    
    1417
    -}
    
    1418
    -
    
    1419
    -
    
    1420 951
     QHash<FT_Glyph_Format, QString> glyphFormatNamesCache;
    
    1421 952
     QHash<FT_Glyph_Format, QString>&
    
    1422 953
     glyphFormatNames()
    

  • src/ftinspect/engine/engine.hpp
    ... ... @@ -10,8 +10,10 @@
    10 10
     #include "paletteinfo.hpp"
    
    11 11
     #include "fontinfo.hpp"
    
    12 12
     #include "mmgx.hpp"
    
    13
    +#include "rendering.hpp"
    
    13 14
     
    
    14 15
     #include <vector>
    
    16
    +#include <memory>
    
    15 17
     #include <utility>
    
    16 18
     #include <QString>
    
    17 19
     #include <QMap>
    
    ... ... @@ -90,29 +92,6 @@ public:
    90 92
                                       FTC_Node* outNode = NULL,
    
    91 93
                                       bool forceRender = false);
    
    92 94
     
    
    93
    -  // Return `true` if you need to free `out`
    
    94
    -  // `out` will be set to NULL in cases of error
    
    95
    -  bool convertGlyphToBitmapGlyph(FT_Glyph src, FT_Glyph* out);
    
    96
    -  FT_Bitmap convertBitmapTo8Bpp(FT_Bitmap* bitmap);
    
    97
    -  QImage* convertBitmapToQImage(FT_Bitmap* src);
    
    98
    -  QImage* convertGlyphToQImage(FT_Glyph src, 
    
    99
    -                               QRect* outRect,
    
    100
    -                               bool inverseRectY);
    
    101
    -  QPoint computeGlyphOffset(FT_Glyph glyph, bool inverseY);
    
    102
    -
    
    103
    -  /*
    
    104
    -   * Directly render the glyph at the specified index
    
    105
    -   * to a `QImage`. If you want to perform color-layer
    
    106
    -   * rendering, call this before trying to load the
    
    107
    -   * glyph and do normal rendering, If the returning
    
    108
    -   * value is non-NULL, then there's no need to
    
    109
    -   * load the glyph the normal way, just draw the `QImage`.
    
    110
    -   * Will return NULL if not enabled or color layers not available.
    
    111
    -   */
    
    112
    -  QImage* tryDirectRenderColorLayers(int glyphIndex,
    
    113
    -                                     QRect* outRect,
    
    114
    -                                     bool inverseRectY = false);
    
    115
    -
    
    116 95
       // reload current triplet, but with updated settings, useful for updating
    
    117 96
       // `ftSize_` only
    
    118 97
       void reloadFont();
    
    ... ... @@ -128,6 +107,7 @@ public:
    128 107
     
    
    129 108
       FT_Library ftLibrary() const { return library_; }
    
    130 109
       FTC_Manager cacheManager() { return cacheManager_; }
    
    110
    +  FTC_ImageCache imageCacheManager() { return imageCache_; }
    
    131 111
     
    
    132 112
       int dpi() { return dpi_; }
    
    133 113
       double pointSize() { return pointSize_; }
    
    ... ... @@ -137,7 +117,7 @@ public:
    137 117
       int numberOfOpenedFonts();
    
    138 118
       int currentFontIndex() { return curFontIndex_; }
    
    139 119
       FT_Face currentFallbackFtFace() { return ftFallbackFace_; }
    
    140
    -  // FT_Size currentFtSize() { return ftSize_; }
    
    120
    +  FT_Size currentFtSize() { return ftSize_; }
    
    141 121
       int currentFontType() const { return fontType_; }
    
    142 122
       const QString& currentFamilyName() { return curFamilyName_; }
    
    143 123
       const QString& currentStyleName() { return curStyleName_; }
    
    ... ... @@ -170,13 +150,26 @@ public:
    170 150
       std::vector<int> currentFontFixedSizes();
    
    171 151
       FontFileManager& fontFileManager() { return fontFileManager_; }
    
    172 152
       EngineDefaultValues& engineDefaults() { return engineDefaults_; }
    
    153
    +
    
    154
    +  double gamma() { return gamma_; }
    
    173 155
       bool antiAliasingEnabled() { return antiAliasingEnabled_; }
    
    174 156
       bool doHinting() { return doHinting_; }
    
    175 157
       bool embeddedBitmapEnabled() { return embeddedBitmap_; }
    
    176 158
       bool lcdUsingSubPixelPositioning() { return lcdSubPixelPositioning_; }
    
    159
    +  bool useColorLayer() { return useColorLayer_; }
    
    160
    +  bool lcdUsesBGR() { return lcdUsesBGR_; }
    
    161
    +  FT_Render_Mode
    
    162
    +  renderMode()
    
    163
    +  {
    
    164
    +    return static_cast<FT_Render_Mode>(renderMode_);
    
    165
    +  }
    
    166
    +  FTC_ImageType imageType() { return &imageType_; }
    
    167
    +
    
    168
    +  int paletteIndex() { return paletteIndex_; }
    
    169
    +  FT_Color* currentPalette() { return palette_; }
    
    170
    +  FT_Palette_Data& currentFontPaletteData() { return paletteData_; }
    
    177 171
     
    
    178
    -  QRgb foreground() { return foregroundColor_; }
    
    179
    -  QRgb background() { return backgroundColor_; }
    
    172
    +  RenderingEngine* renderingEngine() { return renderingEngine_.get(); }
    
    180 173
     
    
    181 174
       //////// Setters (direct or indirect)
    
    182 175
     
    
    ... ... @@ -217,9 +210,6 @@ public:
    217 210
       void setStemDarkening(bool darkening);
    
    218 211
       void applyMMGXDesignCoords(FT_Fixed* coords, size_t count);
    
    219 212
     
    
    220
    -  void setForeground(QRgb foreground);
    
    221
    -  void setBackground(QRgb background);
    
    222
    -
    
    223 213
       //////// Misc
    
    224 214
     
    
    225 215
       friend FT_Error faceRequester(FTC_FaceID,
    
    ... ... @@ -287,14 +277,10 @@ private:
    287 277
       double gamma_;
    
    288 278
       unsigned long loadFlags_;
    
    289 279
     
    
    290
    -  QRgb backgroundColor_;
    
    291
    -  QRgb foregroundColor_;
    
    292
    -  QRgb foregroundColorBlended_;
    
    293
    -  QVector<QRgb> foregroundTable_;
    
    280
    +  std::unique_ptr<RenderingEngine> renderingEngine_;
    
    294 281
     
    
    295 282
       void queryEngine();
    
    296 283
       void loadPaletteInfos();
    
    297
    -  void calculateForegroundTable();
    
    298 284
     
    
    299 285
       // Safe to put the impl to the cpp.
    
    300 286
       template <class Func>
    

  • src/ftinspect/engine/rendering.cpp
    1
    +// rendering.cpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#include "rendering.hpp"
    
    6
    +
    
    7
    +#include <cmath>
    
    8
    +#include <freetype/ftbitmap.h>
    
    9
    +
    
    10
    +#include "engine.hpp"
    
    11
    +
    
    12
    +
    
    13
    +RenderingEngine::RenderingEngine(Engine* engine)
    
    14
    +: engine_(engine)
    
    15
    +{
    
    16
    +  setForeground(QColor(Qt::black).rgba());
    
    17
    +  setBackground(QColor(Qt::white).rgba());
    
    18
    +}
    
    19
    +
    
    20
    +
    
    21
    +void
    
    22
    +RenderingEngine::setForeground(QRgb foreground)
    
    23
    +{
    
    24
    +  if (foregroundTable_.size() != 256 || foreground != foregroundColor_)
    
    25
    +  {
    
    26
    +    foregroundColor_ = foreground;
    
    27
    +    calculateForegroundTable();
    
    28
    +  }
    
    29
    +}
    
    30
    +
    
    31
    +
    
    32
    +void
    
    33
    +RenderingEngine::setBackground(QRgb background)
    
    34
    +{
    
    35
    +  if (foregroundTable_.size() != 256 || background != backgroundColor_)
    
    36
    +  {
    
    37
    +    backgroundColor_ = background;
    
    38
    +    calculateForegroundTable();
    
    39
    +  }
    
    40
    +}
    
    41
    +
    
    42
    +
    
    43
    +void
    
    44
    +RenderingEngine::calculateForegroundTable()
    
    45
    +{
    
    46
    +  foregroundTable_.resize(256);
    
    47
    +  auto gamma = engine_->gamma();
    
    48
    +
    
    49
    +  // Yes I know this is horribly slow, but we're only calculating the table once
    
    50
    +  // and can use it for all rendering if the color and gamma isn't changing.
    
    51
    +
    
    52
    +  double br = std::pow(qRed(backgroundColor_) / 255.0, gamma);
    
    53
    +  double bg = std::pow(qGreen(backgroundColor_) / 255.0, gamma);
    
    54
    +  double bb = std::pow(qBlue(backgroundColor_) / 255.0, gamma);
    
    55
    +  double invGamma = 1 / gamma;
    
    56
    +
    
    57
    +  for (int i = 0; i <= 0xFF; i++)
    
    58
    +  {
    
    59
    +    double foreAlpha = i * qAlpha(foregroundColor_) / 255.0 / 255.0;
    
    60
    +    double backAlpha = 1 - foreAlpha;
    
    61
    +    double r = std::pow(qRed(foregroundColor_) / 255.0, gamma);
    
    62
    +    double g = std::pow(qGreen(foregroundColor_) / 255.0, gamma);
    
    63
    +    double b = std::pow(qBlue(foregroundColor_) / 255.0, gamma);
    
    64
    +
    
    65
    +    r = br * backAlpha + r * foreAlpha;
    
    66
    +    g = bg * backAlpha + g * foreAlpha;
    
    67
    +    b = bb * backAlpha + b * foreAlpha;
    
    68
    +
    
    69
    +    r = std::pow(r, invGamma);
    
    70
    +    g = std::pow(g, invGamma);
    
    71
    +    b = std::pow(b, invGamma);
    
    72
    +
    
    73
    +    foregroundTable_[i]
    
    74
    +        = qRgba(static_cast<int>(r * 255), 
    
    75
    +                static_cast<int>(g * 255),
    
    76
    +                static_cast<int>(b * 255), 
    
    77
    +                255);
    
    78
    +  }
    
    79
    +}
    
    80
    +
    
    81
    +
    
    82
    +bool
    
    83
    +RenderingEngine::convertGlyphToBitmapGlyph(FT_Glyph src,
    
    84
    +                      FT_Glyph* out)
    
    85
    +{
    
    86
    +  if (src->format == FT_GLYPH_FORMAT_BITMAP)
    
    87
    +  {
    
    88
    +    *out = src;
    
    89
    +    return false;
    
    90
    +  }
    
    91
    +  if (src->format != FT_GLYPH_FORMAT_OUTLINE)
    
    92
    +  {
    
    93
    +    *out = NULL;
    
    94
    +    return false;
    
    95
    +    // TODO support SVG
    
    96
    +  }
    
    97
    +
    
    98
    +  if (src->format == FT_GLYPH_FORMAT_OUTLINE)
    
    99
    +  {
    
    100
    +    FT_Glyph out2 = src;
    
    101
    +    auto error = FT_Glyph_To_Bitmap(&out2, 
    
    102
    +                                    engine_->renderMode(),
    
    103
    +                                    nullptr,
    
    104
    +                                    false);
    
    105
    +    if (error)
    
    106
    +    {
    
    107
    +      *out = NULL;
    
    108
    +      return false;
    
    109
    +    }
    
    110
    +    *out = out2;
    
    111
    +    return true;
    
    112
    +  }
    
    113
    +
    
    114
    +  *out = NULL;
    
    115
    +  return false;
    
    116
    +}
    
    117
    +
    
    118
    +
    
    119
    +FT_Bitmap
    
    120
    +RenderingEngine::convertBitmapTo8Bpp(FT_Bitmap* bitmap)
    
    121
    +{
    
    122
    +  FT_Bitmap out;
    
    123
    +  out.buffer = NULL;
    
    124
    +  auto error = FT_Bitmap_Convert(engine_->ftLibrary(), bitmap, &out, 1);
    
    125
    +  if (error)
    
    126
    +  {
    
    127
    +    // XXX handling?
    
    128
    +  }
    
    129
    +  return out;
    
    130
    +}
    
    131
    +
    
    132
    +
    
    133
    +void
    
    134
    +convertLCDToARGB(FT_Bitmap& bitmap,
    
    135
    +                 QImage& image,
    
    136
    +                 bool isBGR,
    
    137
    +                 QVector<QRgb>& colorTable)
    
    138
    +{
    
    139
    +  int height = bitmap.rows;
    
    140
    +  int width = bitmap.width / 3;
    
    141
    +  int width3 = bitmap.width;
    
    142
    +
    
    143
    +  unsigned char* srcPtr = bitmap.buffer;
    
    144
    +  unsigned* dstPtr = reinterpret_cast<unsigned*>(image.bits());
    
    145
    +
    
    146
    +  int offR = !isBGR ? 0 : 2;
    
    147
    +  int offG = 1;
    
    148
    +  int offB = isBGR ? 0 : 2;
    
    149
    +  for (int i = 0; i < height; i++)
    
    150
    +  {
    
    151
    +    for (int j = 0; j < width3; j += 3)
    
    152
    +    {
    
    153
    +      unsigned char ar = srcPtr[j + offR];
    
    154
    +      unsigned char ag = srcPtr[j + offG];
    
    155
    +      unsigned char ab = srcPtr[j + offB];
    
    156
    +      unsigned dr = colorTable[ar] & 0xFF;
    
    157
    +      unsigned dg = colorTable[ag] & 0xFF;
    
    158
    +      unsigned db = colorTable[ab] & 0xFF;
    
    159
    +      *dstPtr = (0xFFu << 24) | (dr << 16) | (dg << 8) | db;
    
    160
    +      dstPtr++;
    
    161
    +    }
    
    162
    +    srcPtr += bitmap.pitch;
    
    163
    +    dstPtr += image.bytesPerLine() / 4 - width; // skip blank area
    
    164
    +  }
    
    165
    +}
    
    166
    +
    
    167
    +
    
    168
    +void
    
    169
    +convertLCDVToARGB(FT_Bitmap& bitmap,
    
    170
    +                  QImage& image,
    
    171
    +                  bool isBGR,
    
    172
    +                  QVector<QRgb>& colorTable)
    
    173
    +{
    
    174
    +  int height = bitmap.rows / 3;
    
    175
    +  int width = bitmap.width;
    
    176
    +  int srcPitch = bitmap.pitch;
    
    177
    +
    
    178
    +  unsigned char* srcPtr = bitmap.buffer;
    
    179
    +  unsigned* dstPtr = reinterpret_cast<unsigned*>(image.bits());
    
    180
    +
    
    181
    +  int offR = !isBGR ? 0 : 2 * srcPitch;
    
    182
    +  int offG = srcPitch;
    
    183
    +  int offB = isBGR ? 0 : 2 * srcPitch;
    
    184
    +  for (int i = 0; i < height; i++)
    
    185
    +  {
    
    186
    +    for (int j = 0; j < width; j++)
    
    187
    +    {
    
    188
    +      unsigned char ar = srcPtr[j + offR];
    
    189
    +      unsigned char ag = srcPtr[j + offG];
    
    190
    +      unsigned char ab = srcPtr[j + offB];
    
    191
    +      unsigned dr = colorTable[ar] & 0xFF;
    
    192
    +      unsigned dg = colorTable[ag] & 0xFF;
    
    193
    +      unsigned db = colorTable[ab] & 0xFF;
    
    194
    +      *dstPtr = (0xFFu << 24) | (dr << 16) | (dg << 8) | db;
    
    195
    +      dstPtr++;
    
    196
    +    }
    
    197
    +    srcPtr += 3ull * srcPitch;                  // move 3 lines
    
    198
    +    dstPtr += image.bytesPerLine() / 4 - width; // skip blank area
    
    199
    +  }
    
    200
    +}
    
    201
    +
    
    202
    +
    
    203
    +QImage*
    
    204
    +RenderingEngine::convertBitmapToQImage(FT_Bitmap* src)
    
    205
    +{
    
    206
    +  QImage* result = NULL;
    
    207
    +  
    
    208
    +  auto& bmap = *src;
    
    209
    +  bool ownBitmap = false;
    
    210
    +
    
    211
    +  int width = INT_MAX, height = INT_MAX;
    
    212
    +  if (bmap.width < INT_MAX)
    
    213
    +    width = static_cast<int>(bmap.width);
    
    214
    +  if (bmap.rows < INT_MAX)
    
    215
    +    height = static_cast<int>(bmap.rows);
    
    216
    +  auto format = QImage::Format_Indexed8; // goto crossing init
    
    217
    +
    
    218
    +  if (bmap.pixel_mode == FT_PIXEL_MODE_GRAY2
    
    219
    +      || bmap.pixel_mode == FT_PIXEL_MODE_GRAY4)
    
    220
    +  {
    
    221
    +    bmap = convertBitmapTo8Bpp(&bmap);
    
    222
    +    if (!bmap.buffer)
    
    223
    +      goto cleanup;
    
    224
    +    ownBitmap = true;
    
    225
    +  }
    
    226
    +
    
    227
    +  if (bmap.pixel_mode == FT_PIXEL_MODE_LCD)
    
    228
    +    width /= 3;
    
    229
    +  else if (bmap.pixel_mode == FT_PIXEL_MODE_LCD_V)
    
    230
    +    height /= 3;
    
    231
    +
    
    232
    +  switch (bmap.pixel_mode)
    
    233
    +  {
    
    234
    +  case FT_PIXEL_MODE_MONO:
    
    235
    +    format = QImage::Format_Mono;
    
    236
    +    break;
    
    237
    +  case FT_PIXEL_MODE_GRAY:
    
    238
    +    format = QImage::Format_Indexed8;
    
    239
    +    break;
    
    240
    +  case FT_PIXEL_MODE_BGRA:
    
    241
    +    // XXX "ARGB" here means BGRA due to endianness - may be problematic
    
    242
    +    // on big-endian machines
    
    243
    +    format = QImage::Format_ARGB32_Premultiplied;
    
    244
    +    break;
    
    245
    +  case FT_PIXEL_MODE_LCD:
    
    246
    +  case FT_PIXEL_MODE_LCD_V:
    
    247
    +    format = QImage::Format_ARGB32;
    
    248
    +    break;
    
    249
    +  default:
    
    250
    +    goto cleanup;
    
    251
    +  }
    
    252
    +
    
    253
    +  switch (bmap.pixel_mode) 
    
    254
    +  {
    
    255
    +  case FT_PIXEL_MODE_MONO:
    
    256
    +  case FT_PIXEL_MODE_GRAY:
    
    257
    +  case FT_PIXEL_MODE_BGRA:
    
    258
    +    {
    
    259
    +      QImage image(bmap.buffer, 
    
    260
    +                   width, height, 
    
    261
    +                   bmap.pitch, 
    
    262
    +                   format);
    
    263
    +      if (bmap.pixel_mode == FT_PIXEL_MODE_GRAY)
    
    264
    +        image.setColorTable(foregroundTable_);
    
    265
    +      else if (bmap.pixel_mode == FT_PIXEL_MODE_MONO)
    
    266
    +      {
    
    267
    +        image.setColorCount(2);
    
    268
    +        image.setColor(0, static_cast<QRgb>(0)); // transparent
    
    269
    +        image.setColor(1, foregroundTable_[0xFF]);
    
    270
    +      }
    
    271
    +      result = new QImage(image.copy());
    
    272
    +      // Don't directly use `image` since we're destroying the image
    
    273
    +    }
    
    274
    +    break;
    
    275
    +  case FT_PIXEL_MODE_LCD:;
    
    276
    +    result = new QImage(width, height, format);
    
    277
    +    convertLCDToARGB(bmap, *result, engine_->lcdUsesBGR(), foregroundTable_);
    
    278
    +    break;
    
    279
    +  case FT_PIXEL_MODE_LCD_V:;
    
    280
    +    result = new QImage(width, height, format);
    
    281
    +    convertLCDVToARGB(bmap, *result, engine_->lcdUsesBGR(), foregroundTable_);
    
    282
    +    break;
    
    283
    +  }
    
    284
    +
    
    285
    +cleanup:
    
    286
    +  if (ownBitmap)
    
    287
    +    FT_Bitmap_Done(engine_->ftLibrary(), &bmap);
    
    288
    +
    
    289
    +  return result;
    
    290
    +}
    
    291
    +
    
    292
    +
    
    293
    +QImage*
    
    294
    +RenderingEngine::convertGlyphToQImage(FT_Glyph src,
    
    295
    +                             QRect* outRect,
    
    296
    +                             bool inverseRectY)
    
    297
    +{
    
    298
    +  FT_BitmapGlyph bitmapGlyph;
    
    299
    +  bool ownBitmapGlyph
    
    300
    +    = convertGlyphToBitmapGlyph(src, reinterpret_cast<FT_Glyph*>(&bitmapGlyph));
    
    301
    +  if (!bitmapGlyph)
    
    302
    +    return NULL;
    
    303
    +
    
    304
    +  auto result = convertBitmapToQImage(&bitmapGlyph->bitmap);
    
    305
    +
    
    306
    +  if (result && outRect)
    
    307
    +  {
    
    308
    +    outRect->setLeft(bitmapGlyph->left);
    
    309
    +    if (inverseRectY)
    
    310
    +      outRect->setTop(-bitmapGlyph->top);
    
    311
    +    else
    
    312
    +      outRect->setTop(bitmapGlyph->top);
    
    313
    +    if (bitmapGlyph->bitmap.width < INT_MAX)
    
    314
    +      outRect->setWidth(static_cast<int>(bitmapGlyph->bitmap.width));
    
    315
    +    else
    
    316
    +      outRect->setWidth(INT_MAX);
    
    317
    +
    
    318
    +    if (bitmapGlyph->bitmap.rows < INT_MAX)
    
    319
    +      outRect->setHeight(static_cast<int>(bitmapGlyph->bitmap.rows));
    
    320
    +    else
    
    321
    +      outRect->setHeight(INT_MAX);
    
    322
    +  }
    
    323
    +
    
    324
    +  if (ownBitmapGlyph)
    
    325
    +    FT_Done_Glyph(reinterpret_cast<FT_Glyph>(bitmapGlyph));
    
    326
    +
    
    327
    +  return result;
    
    328
    +}
    
    329
    +
    
    330
    +
    
    331
    +QPoint
    
    332
    +RenderingEngine::computeGlyphOffset(FT_Glyph glyph, bool inverseY)
    
    333
    +{
    
    334
    +  if (glyph->format == FT_GLYPH_FORMAT_OUTLINE)
    
    335
    +  {
    
    336
    +    FT_BBox cbox;
    
    337
    +    FT_Outline_Get_CBox(&reinterpret_cast<FT_OutlineGlyph>(glyph)->outline, 
    
    338
    +                        &cbox);
    
    339
    +    cbox.xMin &= ~63;
    
    340
    +    cbox.yMin &= ~63;
    
    341
    +    cbox.xMax = (cbox.xMax + 63) & ~63;
    
    342
    +    cbox.yMax = (cbox.yMax + 63) & ~63;
    
    343
    +    if (inverseY)
    
    344
    +      cbox.yMax = -cbox.yMax;
    
    345
    +    return { static_cast<int>(cbox.xMin / 64),
    
    346
    +             static_cast<int>(cbox.yMax / 64) };
    
    347
    +  }
    
    348
    +  if (glyph->format == FT_GLYPH_FORMAT_BITMAP)
    
    349
    +  {
    
    350
    +    auto bg = reinterpret_cast<FT_BitmapGlyph>(glyph);
    
    351
    +    if (inverseY)
    
    352
    +      return { bg->left, -bg->top };
    
    353
    +    return { bg->left, bg->top };
    
    354
    +  }
    
    355
    +
    
    356
    +  return {};
    
    357
    +}
    
    358
    +
    
    359
    +
    
    360
    +QImage*
    
    361
    +RenderingEngine::tryDirectRenderColorLayers(int glyphIndex,
    
    362
    +                                   QRect* outRect,
    
    363
    +                                   bool inverseRectY)
    
    364
    +{
    
    365
    +  auto& paletteData = engine_->currentFontPaletteData();
    
    366
    +  auto paletteIndex = engine_->paletteIndex();
    
    367
    +  auto palette = engine_->currentPalette();
    
    368
    +  if (palette == NULL 
    
    369
    +      || !engine_->useColorLayer() 
    
    370
    +      || paletteIndex >= paletteData.num_palettes)
    
    371
    +    return NULL;
    
    372
    +
    
    373
    +  FT_LayerIterator iter = {};
    
    374
    +  
    
    375
    +  FT_UInt layerGlyphIdx = 0;
    
    376
    +  FT_UInt layerColorIdx = 0;
    
    377
    +
    
    378
    +  bool next = FT_Get_Color_Glyph_Layer(engine_->currentFtSize()->face,
    
    379
    +                                       glyphIndex,
    
    380
    +                                       &layerGlyphIdx,
    
    381
    +                                       &layerColorIdx,
    
    382
    +                                       &iter);
    
    383
    +  if (!next)
    
    384
    +    return NULL;
    
    385
    +
    
    386
    +  // temporarily change lf
    
    387
    +  auto imageType = engine_->imageType();
    
    388
    +  auto oldLoadFlags = imageType->flags;
    
    389
    +  auto loadFlags = oldLoadFlags;
    
    390
    +  loadFlags &= ~FT_LOAD_COLOR;
    
    391
    +  loadFlags |= FT_LOAD_RENDER;
    
    392
    +
    
    393
    +  loadFlags &= ~FT_LOAD_TARGET_(0xF);
    
    394
    +  loadFlags |= FT_LOAD_TARGET_NORMAL;
    
    395
    +  imageType->flags = loadFlags;
    
    396
    +
    
    397
    +  FT_Bitmap bitmap = {};
    
    398
    +  FT_Bitmap_Init(&bitmap);
    
    399
    +
    
    400
    +  FT_Vector bitmapOffset = {};
    
    401
    +  bool failed = false;
    
    402
    +
    
    403
    +  do
    
    404
    +  {
    
    405
    +    FT_Vector slotOffset;
    
    406
    +    FT_Glyph glyph;
    
    407
    +    if (FTC_ImageCache_Lookup(engine_->imageCacheManager(),
    
    408
    +                              imageType,
    
    409
    +                              layerGlyphIdx,
    
    410
    +                              &glyph,
    
    411
    +                              NULL))
    
    412
    +    {
    
    413
    +      // XXX Error handling
    
    414
    +      failed = true;
    
    415
    +      break;
    
    416
    +    }
    
    417
    +
    
    418
    +    if (glyph->format != FT_GLYPH_FORMAT_BITMAP)
    
    419
    +      continue;
    
    420
    +
    
    421
    +    auto bitmapGlyph = reinterpret_cast<FT_BitmapGlyph>(glyph);
    
    422
    +    slotOffset.x = bitmapGlyph->left << 6;
    
    423
    +    slotOffset.y = bitmapGlyph->top << 6;
    
    424
    +
    
    425
    +    FT_Color color = {};
    
    426
    +
    
    427
    +    if (layerColorIdx == 0xFFFF)
    
    428
    +    {
    
    429
    +      // TODO: FT_Palette_Get_Foreground_Color: #1134
    
    430
    +      if (paletteData.palette_flags
    
    431
    +          && (paletteData.palette_flags[paletteIndex] 
    
    432
    +              & FT_PALETTE_FOR_DARK_BACKGROUND))
    
    433
    +      {
    
    434
    +        /* white opaque */
    
    435
    +        color.blue = 0xFF;
    
    436
    +        color.green = 0xFF;
    
    437
    +        color.red = 0xFF;
    
    438
    +        color.alpha = 0xFF;
    
    439
    +      }
    
    440
    +      else
    
    441
    +      {
    
    442
    +        /* black opaque */
    
    443
    +        color.blue = 0x00;
    
    444
    +        color.green = 0x00;
    
    445
    +        color.red = 0x00;
    
    446
    +        color.alpha = 0xFF;
    
    447
    +      }
    
    448
    +    }
    
    449
    +    else if (layerColorIdx < paletteData.num_palette_entries)
    
    450
    +      color = palette[layerColorIdx];
    
    451
    +    else
    
    452
    +      continue;
    
    453
    +
    
    454
    +    if (FT_Bitmap_Blend(engine_->ftLibrary(),
    
    455
    +                        &bitmapGlyph->bitmap, slotOffset,
    
    456
    +                        &bitmap, &bitmapOffset,
    
    457
    +                        color))
    
    458
    +    {
    
    459
    +      // XXX error
    
    460
    +      failed = true;
    
    461
    +      break;
    
    462
    +    }
    
    463
    +  } while (FT_Get_Color_Glyph_Layer(engine_->currentFtSize()->face,
    
    464
    +                                    glyphIndex,
    
    465
    +                                    &layerGlyphIdx,
    
    466
    +                                    &layerColorIdx,
    
    467
    +                                    &iter));
    
    468
    +
    
    469
    +  imageType->flags = oldLoadFlags;
    
    470
    +  if (failed)
    
    471
    +  {
    
    472
    +    FT_Bitmap_Done(engine_->ftLibrary(), &bitmap);
    
    473
    +    return NULL;
    
    474
    +  }
    
    475
    +
    
    476
    +  auto img = convertBitmapToQImage(&bitmap);
    
    477
    +  if (outRect)
    
    478
    +  {
    
    479
    +    outRect->moveLeft(static_cast<int>(bitmapOffset.x >> 6));
    
    480
    +    if (inverseRectY)
    
    481
    +      outRect->moveTop(static_cast<int>(-bitmapOffset.y >> 6));
    
    482
    +    else
    
    483
    +      outRect->moveTop(static_cast<int>(bitmapOffset.y >> 6));
    
    484
    +    outRect->setSize(img->size());
    
    485
    +  }
    
    486
    +
    
    487
    +  FT_Bitmap_Done(engine_->ftLibrary(), &bitmap);
    
    488
    +
    
    489
    +  return img;
    
    490
    +}
    
    491
    +
    
    492
    +
    
    493
    +// end of rendering.cpp

  • src/ftinspect/engine/rendering.hpp
    1
    +// rendering.hpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#pragma once
    
    6
    +
    
    7
    +#include <QColor>
    
    8
    +#include <QImage>
    
    9
    +#include <freetype/freetype.h>
    
    10
    +#include <freetype/ftglyph.h>
    
    11
    +
    
    12
    +class Engine;
    
    13
    +class RenderingEngine
    
    14
    +{
    
    15
    +public:
    
    16
    +  RenderingEngine(Engine* engine);
    
    17
    +
    
    18
    +  void setForeground(QRgb foreground);
    
    19
    +  void setBackground(QRgb background);
    
    20
    +  void calculateForegroundTable();
    
    21
    +
    
    22
    +  QRgb foreground() { return foregroundColor_; }
    
    23
    +  QRgb background() { return backgroundColor_; }
    
    24
    +
    
    25
    +  // Return `true` if you need to free `out`
    
    26
    +  // `out` will be set to NULL in cases of error
    
    27
    +  bool convertGlyphToBitmapGlyph(FT_Glyph src, FT_Glyph* out);
    
    28
    +  FT_Bitmap convertBitmapTo8Bpp(FT_Bitmap* bitmap);
    
    29
    +  QImage* convertBitmapToQImage(FT_Bitmap* src);
    
    30
    +  QImage* convertGlyphToQImage(FT_Glyph src, 
    
    31
    +                               QRect* outRect,
    
    32
    +                               bool inverseRectY);
    
    33
    +  QPoint computeGlyphOffset(FT_Glyph glyph, bool inverseY);
    
    34
    +
    
    35
    +  /*
    
    36
    +   * Directly render the glyph at the specified index
    
    37
    +   * to a `QImage`. If you want to perform color-layer
    
    38
    +   * rendering, call this before trying to load the
    
    39
    +   * glyph and do normal rendering, If the returning
    
    40
    +   * value is non-NULL, then there's no need to
    
    41
    +   * load the glyph the normal way, just draw the `QImage`.
    
    42
    +   * Will return NULL if not enabled or color layers not available.
    
    43
    +   */
    
    44
    +  QImage* tryDirectRenderColorLayers(int glyphIndex,
    
    45
    +                                     QRect* outRect,
    
    46
    +                                     bool inverseRectY = false);
    
    47
    +
    
    48
    +private:
    
    49
    +  Engine* engine_;
    
    50
    +
    
    51
    +  QRgb backgroundColor_;
    
    52
    +  QRgb foregroundColor_;
    
    53
    +  QVector<QRgb> foregroundTable_;
    
    54
    +};
    
    55
    +
    
    56
    +// end of rendering.hpp

  • src/ftinspect/engine/stringrenderer.cpp
    ... ... @@ -565,7 +565,8 @@ StringRenderer::renderLine(int x,
    565 565
     
    
    566 566
         QRect rect;
    
    567 567
         QImage* colorLayerImage
    
    568
    -        = engine_->tryDirectRenderColorLayers(ctx.glyphIndex, &rect, true);
    
    568
    +      = engine_->renderingEngine()->tryDirectRenderColorLayers(ctx.glyphIndex,
    
    569
    +                                                               &rect, true);
    
    569 570
     
    
    570 571
         if (colorLayerImage)
    
    571 572
         {
    

  • src/ftinspect/glyphcomponents/glyphbitmap.cpp
    ... ... @@ -30,10 +30,12 @@ GlyphBitmap::GlyphBitmap(int glyphIndex,
    30 30
                              Engine* engine)
    
    31 31
     {
    
    32 32
       QRect bRect;
    
    33
    -  image_ = engine->tryDirectRenderColorLayers(glyphIndex, &bRect, true);
    
    33
    +  image_ = engine->renderingEngine()->tryDirectRenderColorLayers(glyphIndex,
    
    34
    +                                                                 &bRect, true);
    
    34 35
     
    
    35 36
       if (!image_)
    
    36
    -    image_ = engine->convertGlyphToQImage(glyph, &bRect, true);
    
    37
    +    image_ = engine->renderingEngine()->convertGlyphToQImage(glyph, &bRect, 
    
    38
    +                                                             true);
    
    37 39
       boundingRect_ = bRect; // QRect to QRectF
    
    38 40
     }
    
    39 41
     
    

  • src/ftinspect/glyphcomponents/glyphcontinuous.cpp
    ... ... @@ -109,7 +109,7 @@ void
    109 109
     GlyphContinuous::paintEvent(QPaintEvent* event)
    
    110 110
     {
    
    111 111
       QPainter painter(this);
    
    112
    -  painter.fillRect(rect(), engine_->background());
    
    112
    +  painter.fillRect(rect(), engine_->renderingEngine()->background());
    
    113 113
     
    
    114 114
       if (glyphCache_.empty())
    
    115 115
         fillCache();
    
    ... ... @@ -423,7 +423,9 @@ GlyphContinuous::saveSingleGlyph(FT_Glyph glyph,
    423 423
         return;
    
    424 424
     
    
    425 425
       QRect rect;
    
    426
    -  QImage* image = engine_->convertGlyphToQImage(glyph, &rect, true);
    
    426
    +  QImage* image = engine_->renderingEngine()->convertGlyphToQImage(glyph, 
    
    427
    +                                                                   &rect, 
    
    428
    +                                                                   true);
    
    427 429
       saveSingleGlyphImage(image, rect, penPos, glyph->advance, gctx);
    
    428 430
     }
    
    429 431
     
    

  • src/ftinspect/meson.build
    ... ... @@ -29,6 +29,7 @@ if qt5_dep.found()
    29 29
         'engine/fontinfo.cpp',
    
    30 30
         'engine/fontinfonamesmapping.cpp',
    
    31 31
         'engine/mmgx.cpp',
    
    32
    +    'engine/rendering.cpp',
    
    32 33
         'engine/renderutils.cpp',
    
    33 34
     
    
    34 35
         'glyphcomponents/glyphbitmap.cpp',
    

  • src/ftinspect/panels/settingpanel.cpp
    ... ... @@ -369,8 +369,8 @@ SettingPanel::syncSettings()
    369 369
         antiAliasingComboBox_->currentIndex()
    
    370 370
           == AntiAliasingComboBoxModel::AntiAliasing_Light_SubPixel);
    
    371 371
     
    
    372
    -  engine_->setForeground(foregroundColor_.rgba());
    
    373
    -  engine_->setBackground(backgroundColor_.rgba());
    
    372
    +  engine_->renderingEngine()->setForeground(foregroundColor_.rgba());
    
    373
    +  engine_->renderingEngine()->setBackground(backgroundColor_.rgba());
    
    374 374
       mmgxPanel_->syncSettings();
    
    375 375
     }
    
    376 376
     
    

  • src/ftinspect/panels/singular.cpp
    ... ... @@ -87,7 +87,8 @@ SingularTab::drawGlyph()
    87 87
         currentGlyphPointNumbersItem_ = NULL;
    
    88 88
       }
    
    89 89
     
    
    90
    -  glyphView_->setBackgroundBrush(QColor(engine_->background()));
    
    90
    +  glyphView_->setBackgroundBrush(
    
    91
    +    QColor(engine_->renderingEngine()->background()));
    
    91 92
     
    
    92 93
       syncSettings();
    
    93 94
       FT_Glyph glyph = engine_->loadGlyph(currentGlyphIndex_);
    


  • reply via email to

    [Prev in Thread] Current Thread [Next in Thread]