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-final] 2 commits: [ftin


From: Charlie Jiang (@cqjjjzr)
Subject: [Git][freetype/freetype-demos][gsoc-2022-chariri-final] 2 commits: [ftinspect] Support MM/GX.
Date: Sun, 04 Sep 2022 15:19:51 +0000

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

Commits:

  • 5aaf34ba
    by Charlie Jiang at 2022-09-04T22:51:27+08:00
    [ftinspect] Support MM/GX.
    
    * src/ftinspect/panels/settingpanelmmgx.cpp,
      src/ftinspect/panels/settingpanelmmgx.hpp:
      Add GUI widgets for MM/GX settings.
    
    * src/ftinspect/engine/mmgx.cpp, src/ftinspect/engine/mmgx.hpp:
      Add `MMGXAxisInfo` to retrieve axes info. However, the SFNT name table
      isn't implemented, so the SFNT based axis names are unavailable.
    
    * src/ftinspect/engine/engine.cpp, src/ftinspect/engine/engine.hpp:
      Add `applyMMGXDesignCoords`. Add getters `currentFontMMGXState` and
      `currentFontMMGXAxes`. Info is retrieved when loading font.
    
    * src/ftinspect/panels/settingpanel.cpp,
      src/ftinspect/panels/settingpanel.hpp: Uncomment functional code.
      Remove `checkHintingMode` and `checkStemDarkening`. Applying of delayed
      settings is taken care by the `MainGUI`. So emitting `fontReloadNeeded`
      simply will do the work.
    
    * src/ftinspect/maingui.cpp: Don't reset the cache so aggressively.
    
    * src/ftinspect/CMakeLists.txt, src/ftinspect/meson.build: Updated.
    
  • 6bf56f74
    by Charlie Jiang at 2022-09-04T23:19:26+08:00
    [ftinspect] Add SFNT `name` table retrieving.
    
    * src/ftinspect/engine/fontinfo.cpp, src/ftinspect/engine/fontinfo.hpp:
      New files, add `SFNTName` to retrieve `name` table.
      Conversions to `QString` from mainstream encodings are supported.
    
    * src/ftinspect/engine/engine.cpp, src/ftinspect/engine/engine.hpp:
      Add `currentFontSFNTNames` and retrieve the `name` table when loading the
      font. Also pass the SFNT name table when loading palettes.
    
    * src/ftinspect/engine/mmgx.cpp, src/ftinspect/engine/paletteinfo.cpp:
      Uncomment functional code to make use of the `name` table.
    
    * src/ftinspect/CMakeLists.txt, src/ftinspect/meson.build: Updated.
    

14 changed files:

Changes:

  • src/ftinspect/CMakeLists.txt
    ... ... @@ -24,6 +24,8 @@ add_executable(ftinspect
    24 24
       "engine/fontfilemanager.cpp"
    
    25 25
       "engine/rendering.cpp"
    
    26 26
       "engine/paletteinfo.cpp"
    
    27
    +  "engine/mmgx.cpp"
    
    28
    +  "engine/fontinfo.cpp"
    
    27 29
     
    
    28 30
       "glyphcomponents/glyphbitmap.cpp"
    
    29 31
       "glyphcomponents/glyphoutline.cpp"
    
    ... ... @@ -40,6 +42,7 @@ add_executable(ftinspect
    40 42
       "models/customcomboboxmodels.cpp"
    
    41 43
     
    
    42 44
       "panels/settingpanel.cpp"
    
    45
    +  "panels/settingpanelmmgx.cpp"
    
    43 46
       "panels/singular.cpp"
    
    44 47
     )
    
    45 48
     target_link_libraries(ftinspect
    

  • src/ftinspect/engine/engine.cpp
    ... ... @@ -11,6 +11,7 @@
    11 11
     #include <freetype/ftmodapi.h>
    
    12 12
     #include <freetype/ftdriver.h>
    
    13 13
     #include <freetype/ftlcdfil.h>
    
    14
    +#include <freetype/ftmm.h>
    
    14 15
     
    
    15 16
     
    
    16 17
     /////////////////////////////////////////////////////////////////////////////
    
    ... ... @@ -327,6 +328,7 @@ Engine::loadFont(int fontIndex,
    327 328
         ftSize_ = NULL;
    
    328 329
         curFamilyName_ = QString();
    
    329 330
         curStyleName_ = QString();
    
    331
    +    curSFNTNames_.clear();
    
    330 332
       }
    
    331 333
       else
    
    332 334
       {
    
    ... ... @@ -342,7 +344,10 @@ Engine::loadFont(int fontIndex,
    342 344
           fontType_ = FontType_TrueType;
    
    343 345
         else
    
    344 346
           fontType_ = FontType_Other;
    
    347
    +
    
    348
    +    SFNTName::get(this, curSFNTNames_);
    
    345 349
         loadPaletteInfos();
    
    350
    +    curMMGXState_ = MMGXAxisInfo::get(this, curMMGXAxes_);
    
    346 351
       }
    
    347 352
     
    
    348 353
       curNumGlyphs_ = numGlyphs;
    
    ... ... @@ -657,6 +662,19 @@ Engine::setStemDarkening(bool darkening)
    657 662
     }
    
    658 663
     
    
    659 664
     
    
    665
    +void
    
    666
    +Engine::applyMMGXDesignCoords(FT_Fixed* coords,
    
    667
    +                              size_t count)
    
    668
    +{
    
    669
    +  if (!ftSize_)
    
    670
    +    return;
    
    671
    +  if (count >= UINT_MAX)
    
    672
    +    count = UINT_MAX - 1;
    
    673
    +  FT_Set_Var_Design_Coordinates(ftSize_->face,
    
    674
    +                                static_cast<unsigned>(count), coords);
    
    675
    +}
    
    676
    +
    
    677
    +
    
    660 678
     void
    
    661 679
     Engine::update()
    
    662 680
     {
    
    ... ... @@ -834,8 +852,8 @@ Engine::loadPaletteInfos()
    834 852
       // size never exceeds max val of ushort.
    
    835 853
       curPaletteInfos_.reserve(paletteData_.num_palettes);
    
    836 854
       for (int i = 0; i < paletteData_.num_palettes; ++i)
    
    837
    -    curPaletteInfos_.emplace_back(ftFallbackFace_, paletteData_, i, nullptr);
    
    838
    -    // no `NULL` here - we need `std::nullptr_t`
    
    855
    +    curPaletteInfos_.emplace_back(ftFallbackFace_, paletteData_, i,
    
    856
    +                                  &curSFNTNames_);
    
    839 857
     }
    
    840 858
     
    
    841 859
     
    

  • src/ftinspect/engine/engine.hpp
    ... ... @@ -8,6 +8,8 @@
    8 8
     #include "fontfilemanager.hpp"
    
    9 9
     
    
    10 10
     #include "paletteinfo.hpp"
    
    11
    +#include "fontinfo.hpp"
    
    12
    +#include "mmgx.hpp"
    
    11 13
     #include "rendering.hpp"
    
    12 14
     
    
    13 15
     #include <memory>
    
    ... ... @@ -119,6 +121,9 @@ public:
    119 121
       std::vector<PaletteInfo>& currentFontPalettes() { return curPaletteInfos_; }
    
    120 122
       FT_Color* currentPalette() { return palette_; }
    
    121 123
       FT_Palette_Data& currentFontPaletteData() { return paletteData_; }
    
    124
    +  MMGXState currentFontMMGXState() { return curMMGXState_; }
    
    125
    +  std::vector<MMGXAxisInfo>& currentFontMMGXAxes() { return curMMGXAxes_; }
    
    126
    +  std::vector<SFNTName>& currentFontSFNTNames() { return curSFNTNames_; }
    
    122 127
     
    
    123 128
       QString glyphName(int glyphIndex);
    
    124 129
       long numberOfFaces(int fontIndex);
    
    ... ... @@ -183,7 +188,8 @@ public:
    183 188
       void setTTInterpreterVersion(int version);
    
    184 189
     
    
    185 190
       void setStemDarkening(bool darkening);
    
    186
    -  
    
    191
    +  void applyMMGXDesignCoords(FT_Fixed* coords, size_t count);
    
    192
    +
    
    187 193
       //////// Misc
    
    188 194
     
    
    189 195
       friend FT_Error faceRequester(FTC_FaceID,
    
    ... ... @@ -200,11 +206,14 @@ private:
    200 206
     
    
    201 207
       // font info
    
    202 208
       int curFontIndex_ = -1;
    
    209
    +  int fontType_;
    
    203 210
       QString curFamilyName_;
    
    204 211
       QString curStyleName_;
    
    205 212
       int curNumGlyphs_ = -1;
    
    206 213
       std::vector<PaletteInfo> curPaletteInfos_;
    
    207
    -  int fontType_;
    
    214
    +  MMGXState curMMGXState_ = MMGXState::NoMMGX;
    
    215
    +  std::vector<MMGXAxisInfo> curMMGXAxes_;
    
    216
    +  std::vector<SFNTName> curSFNTNames_;
    
    208 217
     
    
    209 218
       // basic objects
    
    210 219
       FT_Library library_;
    

  • src/ftinspect/engine/fontinfo.cpp
    1
    +// fontinfo.cpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#include "fontinfo.hpp"
    
    6
    +
    
    7
    +#include "engine.hpp"
    
    8
    +
    
    9
    +#include <memory>
    
    10
    +#include <utility>
    
    11
    +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    
    12
    +#include <QTextCodec>
    
    13
    +#else
    
    14
    +#include <QStringConverter>
    
    15
    +#include <QByteArrayView>
    
    16
    +#endif
    
    17
    +#include <freetype/ftmodapi.h>
    
    18
    +#include <freetype/ttnameid.h>
    
    19
    +
    
    20
    +
    
    21
    +void
    
    22
    +SFNTName::get(Engine* engine,
    
    23
    +              std::vector<SFNTName>& list)
    
    24
    +{
    
    25
    +  auto face = engine->currentFallbackFtFace();
    
    26
    +  if (!face || !FT_IS_SFNT(face))
    
    27
    +  {
    
    28
    +    list.clear();
    
    29
    +    return;
    
    30
    +  }
    
    31
    +  
    
    32
    +  auto newSize = FT_Get_Sfnt_Name_Count(face);
    
    33
    +  if (list.size() != static_cast<size_t>(newSize))
    
    34
    +    list.resize(newSize);
    
    35
    +
    
    36
    +  FT_SfntName sfntName;
    
    37
    +  FT_SfntLangTag langTag;
    
    38
    +  for (unsigned int i = 0; i < newSize; ++i)
    
    39
    +  {
    
    40
    +    FT_Get_Sfnt_Name(face, i, &sfntName);
    
    41
    +    auto& obj = list[i];
    
    42
    +    obj.platformID = sfntName.platform_id;
    
    43
    +    obj.encodingID = sfntName.encoding_id;
    
    44
    +    obj.languageID = sfntName.language_id;
    
    45
    +    obj.nameID = sfntName.name_id;
    
    46
    +
    
    47
    +    auto len = sfntName.string_len >= INT_MAX
    
    48
    +                 ? INT_MAX - 1
    
    49
    +                 : sfntName.string_len;
    
    50
    +    obj.strBuf = QByteArray(reinterpret_cast<const char*>(sfntName.string), 
    
    51
    +                            len);
    
    52
    +    obj.str = sfntNameToQString(sfntName, &obj.strValid);
    
    53
    +
    
    54
    +    if (obj.languageID >= 0x8000)
    
    55
    +    {
    
    56
    +      auto err = FT_Get_Sfnt_LangTag(face, obj.languageID, &langTag);
    
    57
    +      if (!err)
    
    58
    +        obj.langTag = utf16BEToQString(reinterpret_cast<char*>(langTag.string),
    
    59
    +                                       langTag.string_len);
    
    60
    +    }
    
    61
    +  }
    
    62
    +}
    
    63
    +
    
    64
    +
    
    65
    +QString
    
    66
    +SFNTName::sfntNameToQString(FT_SfntName const& sfntName, 
    
    67
    +                            bool* outSuccess)
    
    68
    +{
    
    69
    +  return sfntNameToQString(sfntName.platform_id, sfntName.encoding_id,
    
    70
    +                           reinterpret_cast<char const*>(sfntName.string),
    
    71
    +                           sfntName.string_len,
    
    72
    +                           outSuccess);
    
    73
    +}
    
    74
    +
    
    75
    +
    
    76
    +QString
    
    77
    +SFNTName::sfntNameToQString(SFNTName const& sfntName, bool* outSuccess)
    
    78
    +{
    
    79
    +  return sfntNameToQString(sfntName.platformID, sfntName.encodingID,
    
    80
    +                           sfntName.strBuf.data(), sfntName.strBuf.size(),
    
    81
    +                           outSuccess);
    
    82
    +}
    
    83
    +
    
    84
    +
    
    85
    +QString
    
    86
    +SFNTName::sfntNameToQString(unsigned short platformID,
    
    87
    +                            unsigned short encodingID,
    
    88
    +                            char const* str,
    
    89
    +                            size_t size,
    
    90
    +                            bool* outSuccess)
    
    91
    +{
    
    92
    +  // TODO not complete.
    
    93
    +  if (size >= INT_MAX - 1)
    
    94
    +    return "";
    
    95
    +
    
    96
    +  if (outSuccess)
    
    97
    +    *outSuccess = true;
    
    98
    +
    
    99
    +  switch (platformID)
    
    100
    +  {
    
    101
    +  case TT_PLATFORM_APPLE_UNICODE:
    
    102
    +    // All UTF-16BE.
    
    103
    +    return utf16BEToQString(str, size);
    
    104
    +  case TT_PLATFORM_MACINTOSH:
    
    105
    +    if (encodingID == TT_MAC_ID_ROMAN)
    
    106
    +      return QString::fromLatin1(str, static_cast<int>(size));
    
    107
    +
    
    108
    +    if (outSuccess)
    
    109
    +      *outSuccess = false;
    
    110
    +    return "<encoding unsupported>";
    
    111
    +  case TT_PLATFORM_ISO:
    
    112
    +    switch (encodingID)
    
    113
    +    {
    
    114
    +    case TT_ISO_ID_7BIT_ASCII:
    
    115
    +    case TT_ISO_ID_8859_1:
    
    116
    +      return QString::fromLatin1(str, static_cast<int>(size));
    
    117
    +    case TT_ISO_ID_10646:
    
    118
    +      return utf16BEToQString(str, size);
    
    119
    +    default:
    
    120
    +      if (outSuccess)
    
    121
    +        *outSuccess = false;
    
    122
    +      return "<encoding unsupported>";
    
    123
    +    }
    
    124
    +  case TT_PLATFORM_MICROSOFT:
    
    125
    +    switch (encodingID)
    
    126
    +    {
    
    127
    +      /* TT_MS_ID_SYMBOL_CS is Unicode, similar to PID/EID=3/1 */
    
    128
    +    case TT_MS_ID_SYMBOL_CS:
    
    129
    +    case TT_MS_ID_UNICODE_CS:
    
    130
    +    case TT_MS_ID_UCS_4: // This is UTF-16LE as well, according to MS doc
    
    131
    +      return utf16BEToQString(str, size);
    
    132
    +
    
    133
    +    default:
    
    134
    +      if (outSuccess)
    
    135
    +        *outSuccess = false;
    
    136
    +      return "<encoding unsupported>";
    
    137
    +    }
    
    138
    +  }
    
    139
    +
    
    140
    +  if (outSuccess)
    
    141
    +    *outSuccess = false;
    
    142
    +  return "<platform unsupported>";
    
    143
    +}
    
    144
    +
    
    145
    +
    
    146
    +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    
    147
    +QTextCodec* utf16BECodec = QTextCodec::codecForName("UTF-16BE");
    
    148
    +#else
    
    149
    +QStringDecoder utf16BECvt = (QStringDecoder(QStringDecoder::Utf16BE))(size);
    
    150
    +#endif
    
    151
    +
    
    152
    +QString
    
    153
    +SFNTName::utf16BEToQString(char const* str,
    
    154
    +                           size_t size)
    
    155
    +{
    
    156
    +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    
    157
    +  if (size >= INT_MAX)
    
    158
    +    size = INT_MAX - 1;
    
    159
    +  return utf16BECodec->toUnicode(str, static_cast<int>(size));
    
    160
    +#else
    
    161
    +  return utf16BECvt(QByteArrayView(reinterpret_cast<char*>(str), size));
    
    162
    +#endif
    
    163
    +}
    
    164
    +
    
    165
    +
    
    166
    +// end of fontinfo.cpp

  • src/ftinspect/engine/fontinfo.hpp
    1
    +// fontinfo.hpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#pragma once
    
    6
    +
    
    7
    +#include <set>
    
    8
    +#include <vector>
    
    9
    +#include <QByteArray>
    
    10
    +#include <QString>
    
    11
    +#include <freetype/freetype.h>
    
    12
    +#include <freetype/ftsnames.h>
    
    13
    +
    
    14
    +class Engine;
    
    15
    +struct SFNTName
    
    16
    +{
    
    17
    +  unsigned short nameID;
    
    18
    +  unsigned short platformID;
    
    19
    +  unsigned short encodingID;
    
    20
    +  unsigned short languageID;
    
    21
    +  QByteArray strBuf;
    
    22
    +  QString str;
    
    23
    +  QString langTag;
    
    24
    +  bool strValid = false;
    
    25
    +
    
    26
    +  static void get(Engine* engine,
    
    27
    +                  std::vector<SFNTName>& list);
    
    28
    +  static QString sfntNameToQString(FT_SfntName const& sfntName,
    
    29
    +                                   bool* outSuccess = NULL);
    
    30
    +  static QString sfntNameToQString(SFNTName const& sfntName,
    
    31
    +                                   bool* outSuccess = NULL);
    
    32
    +  static QString sfntNameToQString(unsigned short platformID,
    
    33
    +                                   unsigned short encodingID, 
    
    34
    +                                   char const* str, size_t size,
    
    35
    +                                   bool* outSuccess = NULL);
    
    36
    +  static QString utf16BEToQString(char const* str, size_t size);
    
    37
    +
    
    38
    +
    
    39
    +  friend bool
    
    40
    +  operator==(const SFNTName& lhs,
    
    41
    +             const SFNTName& rhs)
    
    42
    +  {
    
    43
    +    return lhs.nameID == rhs.nameID
    
    44
    +      && lhs.platformID == rhs.platformID
    
    45
    +      && lhs.encodingID == rhs.encodingID
    
    46
    +      && lhs.languageID == rhs.languageID
    
    47
    +      && lhs.strBuf == rhs.strBuf
    
    48
    +      && lhs.langTag == rhs.langTag;
    
    49
    +  }
    
    50
    +
    
    51
    +
    
    52
    +  friend bool
    
    53
    +  operator!=(const SFNTName& lhs,
    
    54
    +             const SFNTName& rhs)
    
    55
    +  {
    
    56
    +    return !(lhs == rhs);
    
    57
    +  }
    
    58
    +};
    
    59
    +
    
    60
    +
    
    61
    +// end of fontinfo.hpp

  • src/ftinspect/engine/mmgx.cpp
    1
    +// mmgx.cpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#include "mmgx.hpp"
    
    6
    +
    
    7
    +#include "engine.hpp"
    
    8
    +
    
    9
    +#include <freetype/ftmm.h>
    
    10
    +
    
    11
    +
    
    12
    +MMGXState
    
    13
    +MMGXAxisInfo::get(Engine* engine,
    
    14
    +                  std::vector<MMGXAxisInfo>& infos)
    
    15
    +{
    
    16
    +  auto face = engine->currentFallbackFtFace();
    
    17
    +  if (!face)
    
    18
    +  {
    
    19
    +    infos.clear();
    
    20
    +    return MMGXState::NoMMGX;
    
    21
    +  }
    
    22
    +
    
    23
    +  if (!FT_HAS_MULTIPLE_MASTERS(face))
    
    24
    +  {
    
    25
    +    infos.clear();
    
    26
    +    return MMGXState::NoMMGX;
    
    27
    +  }
    
    28
    +
    
    29
    +  FT_Multi_Master dummy;
    
    30
    +  auto error = FT_Get_Multi_Master(face, &dummy);
    
    31
    +  auto state = error ? MMGXState::GX_OVF : MMGXState::MM;
    
    32
    +  
    
    33
    +  FT_MM_Var* mm;
    
    34
    +  if (FT_Get_MM_Var(face, &mm))
    
    35
    +  {
    
    36
    +    infos.clear();
    
    37
    +    return state;
    
    38
    +  }
    
    39
    +
    
    40
    +  infos.resize(mm->num_axis);
    
    41
    +
    
    42
    +  auto& sfnt = engine->currentFontSFNTNames();
    
    43
    +  for (unsigned int i = 0; i < mm->num_axis; ++i)
    
    44
    +  {
    
    45
    +    auto& axis = mm->axis[i];
    
    46
    +    auto& info = infos[i];
    
    47
    +    info.maximum = axis.maximum / 65536.0;
    
    48
    +    info.minimum = axis.minimum / 65536.0;
    
    49
    +    info.def = axis.def / 65536.0;
    
    50
    +    info.tag = axis.tag;
    
    51
    +    info.isMM = state == MMGXState::MM;
    
    52
    +
    
    53
    +    unsigned int flags = 0;
    
    54
    +    FT_Get_Var_Axis_Flags(mm, i, &flags);
    
    55
    +    info.hidden = (flags & FT_VAR_AXIS_FLAG_HIDDEN) != 0;
    
    56
    +
    
    57
    +    auto nameSet = false;
    
    58
    +    if (state == MMGXState::GX_OVF)
    
    59
    +    {
    
    60
    +      auto strid = mm->axis[i].strid;
    
    61
    +      for (auto& obj : sfnt)
    
    62
    +      {
    
    63
    +        if (obj.nameID == strid && obj.strValid)
    
    64
    +        {
    
    65
    +          info.name = obj.str;
    
    66
    +          nameSet = true;
    
    67
    +          break;
    
    68
    +        }
    
    69
    +      }
    
    70
    +    }
    
    71
    +
    
    72
    +    // XXX security flaw
    
    73
    +    if (!nameSet)
    
    74
    +      info.name = QString(axis.name);
    
    75
    +  }
    
    76
    +
    
    77
    +  FT_Done_MM_Var(face->glyph->library, mm);
    
    78
    +
    
    79
    +  return state;
    
    80
    +}
    
    81
    +
    
    82
    +
    
    83
    +// end of mmgx.cpp

  • src/ftinspect/engine/mmgx.hpp
    1
    +// mmgx.hpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#pragma once
    
    6
    +
    
    7
    +#include <vector>
    
    8
    +#include <QString>
    
    9
    +
    
    10
    +class Engine;
    
    11
    +
    
    12
    +enum class MMGXState
    
    13
    +{
    
    14
    +  NoMMGX,
    
    15
    +  MM,     // Adobe MM
    
    16
    +  GX_OVF, // GX or OpenType variable fonts
    
    17
    +};
    
    18
    +
    
    19
    +struct MMGXAxisInfo
    
    20
    +{
    
    21
    +  QString name;
    
    22
    +  unsigned long tag;
    
    23
    +
    
    24
    +  double minimum;
    
    25
    +  double maximum;
    
    26
    +  double def;
    
    27
    +
    
    28
    +  bool hidden;
    
    29
    +  bool isMM;
    
    30
    +
    
    31
    +  static MMGXState get(Engine* engine, std::vector<MMGXAxisInfo>& infos);
    
    32
    +
    
    33
    +
    
    34
    +  friend bool
    
    35
    +  operator==(const MMGXAxisInfo& lhs,
    
    36
    +             const MMGXAxisInfo& rhs)
    
    37
    +  {
    
    38
    +    return lhs.name == rhs.name
    
    39
    +      && lhs.tag == rhs.tag
    
    40
    +      && lhs.minimum == rhs.minimum
    
    41
    +      && lhs.maximum == rhs.maximum
    
    42
    +      && lhs.def == rhs.def
    
    43
    +      && lhs.hidden == rhs.hidden
    
    44
    +      && lhs.isMM == rhs.isMM;
    
    45
    +  }
    
    46
    +
    
    47
    +
    
    48
    +  friend bool
    
    49
    +  operator!=(const MMGXAxisInfo& lhs,
    
    50
    +             const MMGXAxisInfo& rhs)
    
    51
    +  {
    
    52
    +    return !(lhs == rhs);
    
    53
    +  }
    
    54
    +};
    
    55
    +
    
    56
    +
    
    57
    +// end of mmgx.hpp

  • src/ftinspect/engine/paletteinfo.cpp
    ... ... @@ -4,7 +4,7 @@
    4 4
     
    
    5 5
     #include "paletteinfo.hpp"
    
    6 6
     
    
    7
    -//#include "fontinfo.hpp"
    
    7
    +#include "fontinfo.hpp"
    
    8 8
     
    
    9 9
     PaletteInfo::PaletteInfo(FT_Face face, 
    
    10 10
                              FT_Palette_Data& data, 
    
    ... ... @@ -15,15 +15,15 @@ PaletteInfo::PaletteInfo(FT_Face face,
    15 15
       if (sfntNames && data.palette_name_ids)
    
    16 16
       {
    
    17 17
         auto id = data.palette_name_ids[index];
    
    18
    -    name = "(unsupported)";
    
    19
    -    //for (auto& obj : *sfntNames)
    
    20
    -    //{
    
    21
    -    //  if (obj.nameID == id && obj.strValid)
    
    22
    -    //  {
    
    23
    -    //    name = obj.str;
    
    24
    -    //    break;
    
    25
    -    //  }
    
    26
    -    //}
    
    18
    +    name = "(invalid)";
    
    19
    +    for (auto& obj : *sfntNames)
    
    20
    +    {
    
    21
    +      if (obj.nameID == id && obj.strValid)
    
    22
    +      {
    
    23
    +        name = obj.str;
    
    24
    +        break;
    
    25
    +      }
    
    26
    +    }
    
    27 27
       }
    
    28 28
       else
    
    29 29
         name = "(unnamed)";
    

  • src/ftinspect/maingui.cpp
    ... ... @@ -180,7 +180,7 @@ MainGUI::repaintCurrentTab()
    180 180
     void
    
    181 181
     MainGUI::reloadCurrentTabFont()
    
    182 182
     {
    
    183
    -  engine_->resetCache();
    
    183
    +  settingPanel_->applyDelayedSettings(); // This will reset the cache.
    
    184 184
       applySettings();
    
    185 185
       auto index = tabWidget_->currentIndex();
    
    186 186
       if (index >= 0 && static_cast<size_t>(index) < tabs_.size())
    
    ... ... @@ -192,7 +192,6 @@ void
    192 192
     MainGUI::applySettings()
    
    193 193
     {
    
    194 194
       settingPanel_->applySettings();
    
    195
    -  settingPanel_->applyDelayedSettings();
    
    196 195
     }
    
    197 196
     
    
    198 197
     
    

  • src/ftinspect/meson.build
    ... ... @@ -25,6 +25,8 @@ if qt5_dep.found()
    25 25
         'engine/fontfilemanager.cpp',
    
    26 26
         'engine/rendering.cpp',
    
    27 27
         'engine/paletteinfo.cpp',
    
    28
    +    'engine/mmgx.cpp',
    
    29
    +    'engine/fontinfo.cpp',
    
    28 30
     
    
    29 31
         'glyphcomponents/glyphbitmap.cpp',
    
    30 32
         'glyphcomponents/glyphoutline.cpp',
    
    ... ... @@ -41,6 +43,7 @@ if qt5_dep.found()
    41 43
         'models/customcomboboxmodels.cpp',
    
    42 44
     
    
    43 45
         'panels/settingpanel.cpp',
    
    46
    +    'panels/settingpanelmmgx.cpp',
    
    44 47
         'panels/singular.cpp',
    
    45 48
     
    
    46 49
         'ftinspect.cpp',
    
    ... ... @@ -58,6 +61,7 @@ if qt5_dep.found()
    58 61
           'maingui.hpp',
    
    59 62
           'models/customcomboboxmodels.hpp',
    
    60 63
           'panels/settingpanel.hpp',
    
    64
    +      'panels/settingpanelmmgx.hpp',
    
    61 65
           'panels/singular.hpp',
    
    62 66
         ],
    
    63 67
         dependencies: qt5_dep)
    

  • src/ftinspect/panels/settingpanel.cpp
    ... ... @@ -99,16 +99,6 @@ SettingPanel::checkHinting()
    99 99
     }
    
    100 100
     
    
    101 101
     
    
    102
    -void
    
    103
    -SettingPanel::checkHintingMode()
    
    104
    -{
    
    105
    -  //if (!comparatorMode_)
    
    106
    -  applyDelayedSettings();
    
    107
    -
    
    108
    -  emit fontReloadNeeded();
    
    109
    -}
    
    110
    -
    
    111
    -
    
    112 102
     void
    
    113 103
     SettingPanel::checkAutoHinting()
    
    114 104
     {
    
    ... ... @@ -193,16 +183,6 @@ SettingPanel::checkPalette()
    193 183
     }
    
    194 184
     
    
    195 185
     
    
    196
    -void
    
    197
    -SettingPanel::checkStemDarkening()
    
    198
    -{
    
    199
    -  //if (!comparatorMode_)
    
    200
    -  applyDelayedSettings();
    
    201
    -
    
    202
    -  emit fontReloadNeeded();
    
    203
    -}
    
    204
    -
    
    205
    -
    
    206 186
     void
    
    207 187
     SettingPanel::openBackgroundPicker()
    
    208 188
     {
    
    ... ... @@ -339,7 +319,7 @@ SettingPanel::onFontChanged()
    339 319
       paletteComboBox_->setEnabled(colorLayerCheckBox_->isChecked()
    
    340 320
                                    && paletteComboBox_->count() > 0);
    
    341 321
       populatePalettes();
    
    342
    -  //mmgxPanel_->reloadFont();
    
    322
    +  mmgxPanel_->reloadFont();
    
    343 323
       blockSignals(blockState);
    
    344 324
     
    
    345 325
       // Place this after `blockSignals` to let the signals emitted normally
    
    ... ... @@ -389,7 +369,7 @@ SettingPanel::applySettings()
    389 369
     
    
    390 370
       engine_->renderingEngine()->setForeground(foregroundColor_.rgba());
    
    391 371
       engine_->renderingEngine()->setBackground(backgroundColor_.rgba());
    
    392
    -  //mmgxPanel_->applySettings();
    
    372
    +  mmgxPanel_->applySettings();
    
    393 373
     }
    
    394 374
     
    
    395 375
     
    
    ... ... @@ -481,8 +461,7 @@ SettingPanel::createLayout()
    481 461
       gammaLabel_->setBuddy(gammaSlider_);
    
    482 462
       gammaValueLabel_ = new QLabel(this);
    
    483 463
     
    
    484
    -  // TODO: MM/GX
    
    485
    -  mmgxPanel_ = new QWidget(this);
    
    464
    +  mmgxPanel_ = new SettingPanelMMGX(this, engine_);
    
    486 465
     
    
    487 466
       backgroundButton_ = new QPushButton(tr("Background"), this);
    
    488 467
       foregroundButton_ = new QPushButton(tr("Foreground"), this);
    
    ... ... @@ -622,7 +601,7 @@ SettingPanel::createConnections()
    622 601
       // use `qOverload` here to prevent ambiguity.
    
    623 602
       connect(hintingModeComboBox_, 
    
    624 603
               QOverload<int>::of(&QComboBox::currentIndexChanged),
    
    625
    -          this, &SettingPanel::checkHintingMode);
    
    604
    +          this, &SettingPanel::fontReloadNeeded);
    
    626 605
       connect(antiAliasingComboBox_,
    
    627 606
               QOverload<int>::of(&QComboBox::currentIndexChanged),
    
    628 607
               this, &SettingPanel::checkAntiAliasing);
    
    ... ... @@ -656,7 +635,7 @@ SettingPanel::createConnections()
    656 635
       connect(embeddedBitmapCheckBox_, &QCheckBox::clicked,
    
    657 636
               this, &SettingPanel::fontReloadNeeded);
    
    658 637
       connect(stemDarkeningCheckBox_, &QCheckBox::clicked,
    
    659
    -          this, &SettingPanel::checkStemDarkening);
    
    638
    +          this, &SettingPanel::fontReloadNeeded);
    
    660 639
       connect(colorLayerCheckBox_, &QCheckBox::clicked,
    
    661 640
               this, &SettingPanel::checkPalette);
    
    662 641
     
    
    ... ... @@ -664,6 +643,9 @@ SettingPanel::createConnections()
    664 643
               this, &SettingPanel::openBackgroundPicker);
    
    665 644
       connect(foregroundButton_, &QPushButton::clicked,
    
    666 645
               this, &SettingPanel::openForegroundPicker);
    
    646
    +
    
    647
    +  connect(mmgxPanel_, &SettingPanelMMGX::mmgxCoordsChanged,
    
    648
    +          this, &SettingPanel::fontReloadNeeded);
    
    667 649
     }
    
    668 650
     
    
    669 651
     
    

  • src/ftinspect/panels/settingpanel.hpp
    ... ... @@ -6,6 +6,7 @@
    6 6
     
    
    7 7
     #include "../engine/engine.hpp"
    
    8 8
     #include "../models/customcomboboxmodels.hpp"
    
    9
    +#include "settingpanelmmgx.hpp"
    
    9 10
     
    
    10 11
     #include <QWidget>
    
    11 12
     #include <QTabWidget>
    
    ... ... @@ -54,8 +55,7 @@ private:
    54 55
     
    
    55 56
       QWidget* generalTab_;
    
    56 57
       QWidget* hintingRenderingTab_;
    
    57
    -  //SettingPanelMMGX* mmgxPanel_;
    
    58
    -  QWidget* mmgxPanel_;
    
    58
    +  SettingPanelMMGX* mmgxPanel_;
    
    59 59
     
    
    60 60
       QLabel* gammaLabel_;
    
    61 61
       QLabel* gammaValueLabel_;
    
    ... ... @@ -113,11 +113,9 @@ private:
    113 113
     
    
    114 114
       void checkAllSettings();
    
    115 115
       void checkHinting();
    
    116
    -  void checkHintingMode();
    
    117 116
       void checkAutoHinting();
    
    118 117
       void checkAntiAliasing();
    
    119 118
       void checkPalette();
    
    120
    -  void checkStemDarkening();
    
    121 119
     
    
    122 120
       void openBackgroundPicker();
    
    123 121
       void openForegroundPicker();
    

  • src/ftinspect/panels/settingpanelmmgx.cpp
    1
    +// settingpanelmmgx.cpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#include "settingpanelmmgx.hpp"
    
    6
    +
    
    7
    +#include <QScrollBar>
    
    8
    +
    
    9
    +#include "../engine/engine.hpp"
    
    10
    +#include "../uihelper.hpp"
    
    11
    +
    
    12
    +SettingPanelMMGX::SettingPanelMMGX(QWidget* parent,
    
    13
    +                                   Engine* engine)
    
    14
    +: QWidget(parent),
    
    15
    +  engine_(engine)
    
    16
    +{
    
    17
    +  createLayout();
    
    18
    +  createConnections();
    
    19
    +}
    
    20
    +
    
    21
    +
    
    22
    +void
    
    23
    +SettingPanelMMGX::reloadFont()
    
    24
    +{
    
    25
    +  setEnabled(engine_->currentFontMMGXState() != MMGXState::NoMMGX);
    
    26
    +  if (currentAxes_ == engine_->currentFontMMGXAxes())
    
    27
    +    return;
    
    28
    +
    
    29
    +  currentAxes_ = engine_->currentFontMMGXAxes();
    
    30
    +
    
    31
    +  auto newSize = currentAxes_.size();
    
    32
    +  auto oldSize = itemWidgets_.size();
    
    33
    +  auto minSize = std::min(newSize, oldSize);
    
    34
    +
    
    35
    +  // This won't trigger unexpected updating since signals are blocked
    
    36
    +  for (size_t i = 0; i < minSize; ++i)
    
    37
    +    itemWidgets_[i]->updateInfo(currentAxes_[i]);
    
    38
    +
    
    39
    +  if (newSize < oldSize)
    
    40
    +  {
    
    41
    +    for (size_t i = newSize; i < oldSize; ++i)
    
    42
    +    {
    
    43
    +      auto w = itemWidgets_[i];
    
    44
    +      disconnect(w);
    
    45
    +      listLayout_->removeWidget(w);
    
    46
    +      delete w;
    
    47
    +    }
    
    48
    +    itemWidgets_.resize(newSize);
    
    49
    +  }
    
    50
    +  else if (newSize > oldSize)
    
    51
    +  {
    
    52
    +    itemWidgets_.resize(newSize);
    
    53
    +    for (size_t i = oldSize; i < newSize; ++i)
    
    54
    +    {
    
    55
    +      auto w = new MMGXSettingItem(this);
    
    56
    +      itemWidgets_[i] = w;
    
    57
    +      w->updateInfo(currentAxes_[i]);
    
    58
    +      listLayout_->addWidget(w);
    
    59
    +      connect(w, &MMGXSettingItem::valueChanged,
    
    60
    +              [this, i] { itemChanged(i); });
    
    61
    +    }
    
    62
    +  }
    
    63
    +  checkHidden();
    
    64
    +  retrieveValues();
    
    65
    +  applySettings();
    
    66
    +}
    
    67
    +
    
    68
    +
    
    69
    +void
    
    70
    +SettingPanelMMGX::applySettings()
    
    71
    +{
    
    72
    +  engine_->reloadFont();
    
    73
    +  engine_->applyMMGXDesignCoords(currentValues_.data(),
    
    74
    +                                 currentValues_.size());
    
    75
    +}
    
    76
    +
    
    77
    +
    
    78
    +void
    
    79
    +SettingPanelMMGX::checkHidden()
    
    80
    +{
    
    81
    +  if (itemWidgets_.size() < currentAxes_.size())
    
    82
    +    return; // This should never happen!
    
    83
    +  for (int i = 0; static_cast<size_t>(i) < currentAxes_.size(); ++i)
    
    84
    +    itemWidgets_[i]->setVisible(showHiddenCheckBox_->isChecked()
    
    85
    +                                || !currentAxes_[i].hidden);
    
    86
    +}
    
    87
    +
    
    88
    +
    
    89
    +void
    
    90
    +SettingPanelMMGX::createLayout()
    
    91
    +{
    
    92
    +  showHiddenCheckBox_ = new QCheckBox(tr("Show Hidden"), this);
    
    93
    +  groupingCheckBox_ = new QCheckBox(tr("Grouping"), this);
    
    94
    +  resetDefaultButton_ = new QPushButton(tr("Reset Default"), this);
    
    95
    +  itemsListWidget_ = new QWidget(this);
    
    96
    +  scrollArea_ = new UnboundScrollArea(this);
    
    97
    +
    
    98
    +  scrollArea_->setWidget(itemsListWidget_);
    
    99
    +  scrollArea_->setWidgetResizable(true);
    
    100
    +  itemsListWidget_->setAutoFillBackground(false);
    
    101
    +
    
    102
    +  mainLayout_ = new QVBoxLayout;
    
    103
    +  listLayout_ = new QVBoxLayout;
    
    104
    +  listWrapperLayout_ = new QVBoxLayout;
    
    105
    +
    
    106
    +  listLayout_->setSpacing(0);
    
    107
    +  listLayout_->setContentsMargins(0, 0, 0, 0);
    
    108
    +  itemsListWidget_->setContentsMargins(0, 0, 0, 0);
    
    109
    +
    
    110
    +  itemsListWidget_->setLayout(listWrapperLayout_);
    
    111
    +
    
    112
    +  listWrapperLayout_->addLayout(listLayout_);
    
    113
    +  listWrapperLayout_->addStretch(1);
    
    114
    +
    
    115
    +  mainLayout_->addWidget(showHiddenCheckBox_);
    
    116
    +  mainLayout_->addWidget(groupingCheckBox_);
    
    117
    +  mainLayout_->addWidget(resetDefaultButton_);
    
    118
    +  mainLayout_->addWidget(scrollArea_, 1);
    
    119
    +
    
    120
    +  setLayout(mainLayout_);
    
    121
    +}
    
    122
    +
    
    123
    +
    
    124
    +void
    
    125
    +SettingPanelMMGX::createConnections()
    
    126
    +{
    
    127
    +  connect(showHiddenCheckBox_, &QCheckBox::clicked,
    
    128
    +          this, &SettingPanelMMGX::checkHidden);
    
    129
    +  connect(resetDefaultButton_, &QCheckBox::clicked,
    
    130
    +          this, &SettingPanelMMGX::resetDefaultClicked);
    
    131
    +  connect(groupingCheckBox_, &QCheckBox::clicked,
    
    132
    +          this, &SettingPanelMMGX::checkGrouping);
    
    133
    +}
    
    134
    +
    
    135
    +
    
    136
    +void
    
    137
    +SettingPanelMMGX::retrieveValues()
    
    138
    +{
    
    139
    +  currentValues_.resize(currentAxes_.size());
    
    140
    +  for (unsigned i = 0; i < currentAxes_.size(); ++i)
    
    141
    +    currentValues_[i] = itemWidgets_[i]->value();
    
    142
    +}
    
    143
    +
    
    144
    +
    
    145
    +void
    
    146
    +SettingPanelMMGX::itemChanged(size_t index)
    
    147
    +{
    
    148
    +  if (groupingCheckBox_->isChecked()
    
    149
    +      && index < currentAxes_.size() && index < itemWidgets_.size())
    
    150
    +  {
    
    151
    +    auto tag = currentAxes_[index].tag;
    
    152
    +    auto value = itemWidgets_[index]->value();
    
    153
    +    for (size_t i = 0; i < itemWidgets_.size(); ++i)
    
    154
    +      if (i != index && currentAxes_[i].tag == tag)
    
    155
    +        itemWidgets_[i]->setValue(value);
    
    156
    +  }
    
    157
    +
    
    158
    +  retrieveValues();
    
    159
    +  emit mmgxCoordsChanged();
    
    160
    +}
    
    161
    +
    
    162
    +
    
    163
    +void
    
    164
    +SettingPanelMMGX::resetDefaultClicked()
    
    165
    +{
    
    166
    +  for (auto w : itemWidgets_)
    
    167