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


From: Charlie Jiang (@cqjjjzr)
Subject: [Git][freetype/freetype-demos][gsoc-2022-chariri-3] 2 commits: [ftinspect] WIP: Add "Glyph Details" dock panel.
Date: Tue, 02 Aug 2022 15:26:28 +0000

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

Commits:

  • e458f62c
    by Charlie Jiang at 2022-08-02T00:01:18+08:00
    [ftinspect] WIP: Add "Glyph Details" dock panel.
    
    Open a "Glyph Details" tool panel when a glyph in the Continuous View is
    clicked, showing info and enlarged view of the glyph.
    
    TODO: Add more info lines.
    
    * src/ftinspect/panels/continuous.cpp, src/ftinspect/panels/continuous.hpp:
      Add the ctor arguments and fields to hold the dock panel and glyph details
      widget. Add `updateGlyphDetails` func to handle events to open the panel.
    
    * src/ftinspect/rendering/glyphbitmap.cpp,
      src/ftinspect/rendering/glyphbitmap.hpp: Add `GlyphBitmapWidget` class to
      render a `GlyphBitmap` without `QGraphicsView`. Add a new ctor passing in
      `QImage` to the `GlyphBitmap`.
    
    * src/ftinspect/panels/glyphdetails.cpp,
      src/ftinspect/panels/glyphdetails.hpp: New files.
    
    * src/ftinspect/rendering/glyphcontinuous.cpp,
      src/ftinspect/rendering/glyphcontinuous.hpp: Support opening glyph details
      window. Make the related change since `StringRenderer` no longer translate
      the glyph to the pen position.
    
    * src/ftinspect/maingui.cpp: Add `GlyphDetails` and the corresponding
      `QDockWidget`, and pass them to the continuous view.
    
    * src/ftinspect/uihelper.cpp, src/ftinspect/uihelper.hpp: Add
      `setLabelSelectable` function.
    
    * src/ftinspect/engine/stringrenderer.cpp:
      Fix `setX/Y` bug. Fix crash about `prev` pointer when `resize` is called
      (which invalidates the `prev` pointer)
      Don't translate the glyph to the target point, but let the draw routine
      to draw it at the correct pen position.
    
    * src/ftinspect/engine/engine.cpp: Fix bug: use `moveLeft/Top` instead of
      `setX/Y`. Honestly I don't know why it works before...
    
    * src/ftinspect/engine/stringrenderer.hpp: Add `charMapIndex` getter.
    
    * src/ftinspect/CMakeLists.txt, src/ftinspect/meson.build: Updated.
    
  • e11ed2d6
    by Charlie Jiang at 2022-08-02T23:22:07+08:00
    [ftinspect] Add more info entries to the glyph details panel.
    
    Now it shows metrics, ink info and bitmap offset. Also fix a bug in
    `StringRenderer` so translating to pen position of pre-rendered `QImage` is
    also handled by the receiver instead of the `StringRenderer`.
    
    * src/ftinspect/panels/glyphdetails.cpp,
      src/ftinspect/panels/glyphdetails.hpp: Add entries as described.
    
    * src/ftinspect/engine/engine.cpp, src/ftinspect/engine/engine.hpp:
      Add `noScale` argument to `loadGlyphIntoSlotWithoutCache` func to retrieve
      metrics in font native units.
      Add `inverseRectY` argument to `tryDirectRenderColorLayers`.
    
    * src/ftinspect/engine/stringrenderer.cpp,
      src/ftinspect/engine/stringrenderer.hpp:
      Fix the issue that pre-rendered `QImage` is tranlated by the renderer.
      Add a new argument to the `RenderImageCallback` to pass pen position.
    
    * src/ftinspect/rendering/glyphcontinuous.cpp,
      src/ftinspect/rendering/glyphcontinuous.hpp:
      Handle pen position in the callback. Set `penPos` for pre-rendered image
      cache entries.
    
    * src/ftinspect/rendering/glyphbitmap.cpp,
      src/ftinspect/rendering/glyphbitmap.hpp: Leverage the `inverseRectY` arg.
    

18 changed files:

Changes:

  • src/ftinspect/CMakeLists.txt
    ... ... @@ -45,6 +45,7 @@ add_executable(ftinspect
    45 45
       "panels/settingpanel.cpp"
    
    46 46
       "panels/singular.cpp"
    
    47 47
       "panels/continuous.cpp"
    
    48
    +  "panels/glyphdetails.cpp"
    
    48 49
     )
    
    49 50
     target_link_libraries(ftinspect
    
    50 51
       Qt5::Core Qt5::Widgets
    

  • src/ftinspect/engine/engine.cpp
    ... ... @@ -540,9 +540,13 @@ Engine::loadGlyph(int glyphIndex)
    540 540
     
    
    541 541
     
    
    542 542
     int
    
    543
    -Engine::loadGlyphIntoSlotWithoutCache(int glyphIndex)
    
    543
    +Engine::loadGlyphIntoSlotWithoutCache(int glyphIndex,
    
    544
    +                                      bool noScale)
    
    544 545
     {
    
    545
    -  return FT_Load_Glyph(ftSize_->face, glyphIndex, loadFlags_);
    
    546
    +  auto flags = static_cast<int>(loadFlags_);
    
    547
    +  if (noScale)
    
    548
    +    flags |= FT_LOAD_NO_SCALE;
    
    549
    +  return FT_Load_Glyph(ftSize_->face, glyphIndex, flags);
    
    546 550
     }
    
    547 551
     
    
    548 552
     
    
    ... ... @@ -1019,7 +1023,8 @@ Engine::computeGlyphOffset(FT_Glyph glyph, bool inverseY)
    1019 1023
     
    
    1020 1024
     QImage*
    
    1021 1025
     Engine::tryDirectRenderColorLayers(int glyphIndex,
    
    1022
    -                                   QRect* outRect)
    
    1026
    +                                   QRect* outRect,
    
    1027
    +                                   bool inverseRectY)
    
    1023 1028
     {
    
    1024 1029
       if (palette_ == NULL 
    
    1025 1030
           || !useColorLayer_ 
    
    ... ... @@ -1131,9 +1136,12 @@ Engine::tryDirectRenderColorLayers(int glyphIndex,
    1131 1136
       auto img = convertBitmapToQImage(&bitmap);
    
    1132 1137
       if (outRect)
    
    1133 1138
       {
    
    1139
    +    outRect->moveLeft(bitmapOffset.x >> 6);
    
    1140
    +    if (inverseRectY)
    
    1141
    +      outRect->moveTop(-bitmapOffset.y >> 6);
    
    1142
    +    else
    
    1143
    +      outRect->moveTop(bitmapOffset.y >> 6);
    
    1134 1144
         outRect->setSize(img->size());
    
    1135
    -    outRect->setLeft(bitmapOffset.x >> 6);
    
    1136
    -    outRect->setTop(bitmapOffset.y >> 6);
    
    1137 1145
       }
    
    1138 1146
     
    
    1139 1147
       FT_Bitmap_Done(library_, &bitmap);
    

  • src/ftinspect/engine/engine.hpp
    ... ... @@ -79,7 +79,7 @@ public:
    79 79
                    long faceIndex,
    
    80 80
                    int namedInstanceIndex); // return number of glyphs
    
    81 81
       FT_Glyph loadGlyph(int glyphIndex);
    
    82
    -  int loadGlyphIntoSlotWithoutCache(int glyphIndex);
    
    82
    +  int loadGlyphIntoSlotWithoutCache(int glyphIndex, bool noScale = false);
    
    83 83
     
    
    84 84
       // Sometimes the engine is already updated, and we want to be faster
    
    85 85
       FT_Glyph loadGlyphWithoutUpdate(int glyphIndex,
    
    ... ... @@ -106,7 +106,8 @@ public:
    106 106
        * Will return NULL if not enabled or color layers not available.
    
    107 107
        */
    
    108 108
       QImage* tryDirectRenderColorLayers(int glyphIndex,
    
    109
    -                                     QRect* outRect);
    
    109
    +                                     QRect* outRect,
    
    110
    +                                     bool inverseRectY = false);
    
    110 111
     
    
    111 112
       // reload current triplet, but with updated settings, useful for updating
    
    112 113
       // `ftSize_` only
    

  • src/ftinspect/engine/stringrenderer.cpp
    ... ... @@ -269,7 +269,6 @@ StringRenderer::prepareLine(int offset,
    269 269
         // TODO: Optimize: use a sparse vector...!
    
    270 270
         // The problem is that when doing a `list::resize`, the ctor is called
    
    271 271
         // for unnecessarily many times.
    
    272
    -    GlyphContext* prev = &tempGlyphContext_;
    
    273 272
         tempGlyphContext_ = {};
    
    274 273
         for (unsigned n = offset; n < static_cast<unsigned>(limitIndex_);)
    
    275 274
         {
    
    ... ... @@ -283,6 +282,7 @@ StringRenderer::prepareLine(int offset,
    283 282
           ctx.glyphIndex = static_cast<int>(
    
    284 283
               engine_->glyphIndexFromCharCode(static_cast<int>(n), charMapIndex_));
    
    285 284
     
    
    285
    +      auto prev = n == 0 ? &tempGlyphContext_ : &activeGlyphs_[n - 1];
    
    286 286
           if (!ctx.glyph)
    
    287 287
             loadSingleContext(&ctx, prev);
    
    288 288
     
    
    ... ... @@ -292,7 +292,6 @@ StringRenderer::prepareLine(int offset,
    292 292
           outActualLineWidth.y += ctx.hadvance.y;
    
    293 293
           ++n;
    
    294 294
           ++totalCount;
    
    295
    -      prev = &ctx;
    
    296 295
         }
    
    297 296
       }
    
    298 297
       else
    
    ... ... @@ -504,13 +503,12 @@ StringRenderer::renderLine(int x,
    504 503
     
    
    505 504
         QRect rect;
    
    506 505
         QImage* colorLayerImage
    
    507
    -        = engine_->tryDirectRenderColorLayers(ctx.glyphIndex, &rect);
    
    506
    +        = engine_->tryDirectRenderColorLayers(ctx.glyphIndex, &rect, true);
    
    508 507
     
    
    509 508
         if (colorLayerImage)
    
    510 509
         {
    
    511
    -      rect.setX(rect.x() + (pen.x >> 6));
    
    512
    -      rect.setY(height - rect.y() - (pen.y >> 6));
    
    513
    -      renderImageCallback_(colorLayerImage, rect, advance, ctx);
    
    510
    +      FT_Vector penPos = { (pen.x >> 6), height - (pen.y >> 6) };
    
    511
    +      renderImageCallback_(colorLayerImage, rect, penPos, advance, ctx);
    
    514 512
         }
    
    515 513
         else
    
    516 514
         {
    
    ... ... @@ -529,9 +527,7 @@ StringRenderer::renderLine(int x,
    529 527
             if (!error)
    
    530 528
             {
    
    531 529
               if (matrixEnabled_)
    
    532
    -            error = FT_Glyph_Transform(image, &matrix_, &pen);
    
    533
    -          else
    
    534
    -            error = FT_Glyph_Transform(image, NULL, &pen);
    
    530
    +            error = FT_Glyph_Transform(image, &matrix_, NULL);
    
    535 531
             }
    
    536 532
     
    
    537 533
             if (error)
    
    ... ... @@ -544,15 +540,10 @@ StringRenderer::renderLine(int x,
    544 540
           {
    
    545 541
             auto bitmap = reinterpret_cast<FT_BitmapGlyph>(image);
    
    546 542
     
    
    547
    -        if (vertical_)
    
    548
    -        {
    
    549
    -          bitmap->left += (ctx.vvector.x + pen.x) >> 6;
    
    550
    -          bitmap->top += (ctx.vvector.y + pen.y) >> 6;
    
    551
    -        }
    
    552
    -        else
    
    543
    +         if (vertical_)
    
    553 544
             {
    
    554
    -          bitmap->left += pen.x >> 6;
    
    555
    -          bitmap->top += pen.y >> 6;
    
    545
    +           bitmap->left += (ctx.vvector.x) >> 6;
    
    546
    +           bitmap->top += (ctx.vvector.y) >> 6;
    
    556 547
             }
    
    557 548
           }
    
    558 549
     
    

  • src/ftinspect/engine/stringrenderer.hpp
    ... ... @@ -70,8 +70,9 @@ public:
    70 70
        * The receiver is responsible for deleteing the QImage.
    
    71 71
        */
    
    72 72
       using RenderImageCallback = std::function<void(QImage*, 
    
    73
    -                                                 QRect, 
    
    74
    -                                                 FT_Vector, 
    
    73
    +                                                 QRect,
    
    74
    +                                                 FT_Vector, // penPos
    
    75
    +                                                 FT_Vector, // advance
    
    75 76
                                                      GlyphContext&)>;
    
    76 77
       /*
    
    77 78
        * The glyph pointer may be replaced. In that case, ownership is transfered
    
    ... ... @@ -95,6 +96,7 @@ public:
    95 96
     
    
    96 97
       bool isWaterfall() { return waterfall_; }
    
    97 98
       double position(){ return position_; }
    
    99
    +  int charMapIndex() { return charMapIndex_; }
    
    98 100
     
    
    99 101
       void
    
    100 102
       setCallback(RenderCallback cb)
    

  • src/ftinspect/maingui.cpp
    ... ... @@ -191,6 +191,13 @@ MainGUI::syncSettings()
    191 191
     void
    
    192 192
     MainGUI::createLayout()
    
    193 193
     {
    
    194
    +  // floating
    
    195
    +  glyphDetails_ = new GlyphDetails(this, engine_);
    
    196
    +  glyphDetailsDockWidget_ = new QDockWidget(tr("Glyph Details"), this);
    
    197
    +  glyphDetailsDockWidget_->setWidget(glyphDetails_);
    
    198
    +  glyphDetailsDockWidget_->setFloating(true);
    
    199
    +  glyphDetailsDockWidget_->hide();
    
    200
    +
    
    194 201
       // left side
    
    195 202
       settingPanel_ = new SettingPanel(this, engine_);
    
    196 203
     
    
    ... ... @@ -212,7 +219,8 @@ MainGUI::createLayout()
    212 219
     
    
    213 220
       // right side
    
    214 221
       singularTab_ = new SingularTab(this, engine_);
    
    215
    -  continuousTab_ = new ContinuousTab(this, engine_);
    
    222
    +  continuousTab_ = new ContinuousTab(this, engine_,
    
    223
    +                                     glyphDetailsDockWidget_, glyphDetails_);
    
    216 224
     
    
    217 225
       tabWidget_ = new QTabWidget(this);
    
    218 226
     
    

  • src/ftinspect/maingui.hpp
    ... ... @@ -10,6 +10,7 @@
    10 10
     #include "panels/settingpanel.hpp"
    
    11 11
     #include "panels/singular.hpp"
    
    12 12
     #include "panels/continuous.hpp"
    
    13
    +#include "panels/glyphdetails.hpp"
    
    13 14
     
    
    14 15
     #include <QAction>
    
    15 16
     #include <QCheckBox>
    
    ... ... @@ -19,6 +20,7 @@
    19 20
     #include <QFileSystemWatcher>
    
    20 21
     #include <QGridLayout>
    
    21 22
     #include <QHash>
    
    23
    +#include <QDockWidget>
    
    22 24
     #include <QHBoxLayout>
    
    23 25
     #include <QLabel>
    
    24 26
     #include <QList>
    
    ... ... @@ -108,6 +110,9 @@ private:
    108 110
       SingularTab* singularTab_;
    
    109 111
       ContinuousTab* continuousTab_;
    
    110 112
     
    
    113
    +  QDockWidget* glyphDetailsDockWidget_;
    
    114
    +  GlyphDetails* glyphDetails_;
    
    115
    +
    
    111 116
       void openFonts(QStringList const& fileNames);
    
    112 117
     
    
    113 118
       void syncSettings();
    

  • src/ftinspect/meson.build
    ... ... @@ -45,6 +45,7 @@ if qt5_dep.found()
    45 45
         'panels/settingpanel.cpp',
    
    46 46
         'panels/singular.cpp',
    
    47 47
         'panels/continuous.cpp',
    
    48
    +    'panels/glyphdetails.cpp',
    
    48 49
     
    
    49 50
         'ftinspect.cpp',
    
    50 51
         'maingui.cpp',
    
    ... ... @@ -63,6 +64,7 @@ if qt5_dep.found()
    63 64
           'panels/settingpanel.hpp',
    
    64 65
           'panels/singular.hpp',
    
    65 66
           'panels/continuous.hpp',
    
    67
    +      'panels/glyphdetails.hpp',
    
    66 68
           'maingui.hpp',
    
    67 69
         ],
    
    68 70
         dependencies: qt5_dep)
    

  • src/ftinspect/panels/continuous.cpp
    ... ... @@ -4,13 +4,20 @@
    4 4
     
    
    5 5
     #include "continuous.hpp"
    
    6 6
     
    
    7
    +#include "glyphdetails.hpp"
    
    8
    +
    
    7 9
     #include <climits>
    
    8 10
     #include <QVariant>
    
    9 11
     
    
    10 12
     
    
    11 13
     ContinuousTab::ContinuousTab(QWidget* parent,
    
    12
    -                             Engine* engine)
    
    13
    -: QWidget(parent), engine_(engine)
    
    14
    +                             Engine* engine,
    
    15
    +                             QDockWidget* gdWidget,
    
    16
    +                             GlyphDetails* glyphDetails)
    
    17
    +: QWidget(parent),
    
    18
    +  engine_(engine),
    
    19
    +  glyphDetailsWidget_(gdWidget),
    
    20
    +  glyphDetails_(glyphDetails)
    
    14 21
     {
    
    15 22
       createLayout();
    
    16 23
     
    
    ... ... @@ -260,6 +267,17 @@ ContinuousTab::changeBeginIndexFromCanvas(int index)
    260 267
     }
    
    261 268
     
    
    262 269
     
    
    270
    +void
    
    271
    +ContinuousTab::updateGlyphDetails(GlyphCacheEntry* ctxt,
    
    272
    +                                  int charMapIndex,
    
    273
    +                                  bool open)
    
    274
    +{
    
    275
    +  glyphDetails_->updateGlyph(*ctxt, charMapIndex);
    
    276
    +  if (open)
    
    277
    +    glyphDetailsWidget_->setVisible(true);
    
    278
    +}
    
    279
    +
    
    280
    +
    
    263 281
     bool
    
    264 282
     ContinuousTab::eventFilter(QObject* watched,
    
    265 283
                                QEvent* event)
    
    ... ... @@ -413,6 +431,8 @@ ContinuousTab::createConnections()
    413 431
               this, &ContinuousTab::switchToSingular);
    
    414 432
       connect(canvas_, &GlyphContinuous::beginIndexChangeRequest, 
    
    415 433
               this, &ContinuousTab::changeBeginIndexFromCanvas);
    
    434
    +  connect(canvas_, &GlyphContinuous::updateGlyphDetails, 
    
    435
    +          this, &ContinuousTab::updateGlyphDetails);
    
    416 436
     
    
    417 437
       connect(indexSelector_, &GlyphIndexSelector::currentIndexChanged,
    
    418 438
               this, &ContinuousTab::repaintGlyph);
    

  • src/ftinspect/panels/continuous.hpp
    ... ... @@ -19,14 +19,17 @@
    19 19
     #include <QGridLayout>
    
    20 20
     #include <QBoxLayout>
    
    21 21
     #include <QPlainTextEdit>
    
    22
    +#include <QDockWidget>
    
    22 23
     #include <QCheckBox>
    
    23 24
     
    
    25
    +class GlyphDetails;
    
    24 26
     class ContinuousTab
    
    25 27
     : public QWidget, public AbstractTab
    
    26 28
     {
    
    27 29
       Q_OBJECT
    
    28 30
     public:
    
    29
    -  ContinuousTab(QWidget* parent, Engine* engine);
    
    31
    +  ContinuousTab(QWidget* parent, Engine* engine,
    
    32
    +                QDockWidget* gdWidget, GlyphDetails* glyphDetails);
    
    30 33
       ~ContinuousTab() override = default;
    
    31 34
     
    
    32 35
       void repaintGlyph() override;
    
    ... ... @@ -49,6 +52,9 @@ public:
    49 52
       void sourceTextChanged();
    
    50 53
       void reloadGlyphsAndRepaint();
    
    51 54
       void changeBeginIndexFromCanvas(int index);
    
    55
    +  void updateGlyphDetails(GlyphCacheEntry* ctxt, 
    
    56
    +                          int charMapIndex, 
    
    57
    +                          bool open);
    
    52 58
     
    
    53 59
     signals:
    
    54 60
       void switchToSingular(int glyphIndex, double sizePoint);
    
    ... ... @@ -103,6 +109,9 @@ private:
    103 109
       QGridLayout* bottomLayout_;
    
    104 110
       QVBoxLayout* mainLayout_;
    
    105 111
     
    
    112
    +  QDockWidget* glyphDetailsWidget_;
    
    113
    +  GlyphDetails* glyphDetails_;
    
    114
    +
    
    106 115
       void createLayout();
    
    107 116
       void createConnections();
    
    108 117
     
    

  • src/ftinspect/panels/glyphdetails.cpp
    1
    +// glyphdetails.cpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#include "glyphdetails.hpp"
    
    6
    +
    
    7
    +#include "../engine/stringrenderer.hpp"
    
    8
    +#include "../rendering/glyphcontinuous.hpp"
    
    9
    +#include "../uihelper.hpp"
    
    10
    +#include "../engine/engine.hpp"
    
    11
    +
    
    12
    +
    
    13
    +GlyphDetails::GlyphDetails(QWidget* parent,
    
    14
    +                           Engine* engine)
    
    15
    +: QWidget(parent),
    
    16
    +  engine_(engine)
    
    17
    +{
    
    18
    +  createLayout();
    
    19
    +  createConnections();
    
    20
    +}
    
    21
    +
    
    22
    +
    
    23
    +GlyphDetails::~GlyphDetails()
    
    24
    +{
    
    25
    +}
    
    26
    +
    
    27
    +
    
    28
    +void
    
    29
    +GlyphDetails::updateGlyph(GlyphCacheEntry& ctxt, int charMapIndex)
    
    30
    +{
    
    31
    +  auto& cmaps = engine_->currentFontCharMaps();
    
    32
    +
    
    33
    +  glyphIndexLabel_->setText(QString::number(ctxt.glyphIndex));
    
    34
    +  if (charMapIndex < 0 || charMapIndex >= static_cast<int>(cmaps.size()))
    
    35
    +  {
    
    36
    +    charCodePromptLabel_->setVisible(false);
    
    37
    +    charCodeLabel_->setVisible(false);
    
    38
    +  }
    
    39
    +  else
    
    40
    +  {
    
    41
    +    charCodePromptLabel_->setVisible(true);
    
    42
    +    charCodeLabel_->setVisible(true);
    
    43
    +    charCodeLabel_->setText(
    
    44
    +        cmaps[charMapIndex].stringifyIndexShort(ctxt.charCode));
    
    45
    +  }
    
    46
    +
    
    47
    +  auto glyphName = engine_->glyphName(ctxt.glyphIndex);
    
    48
    +  if (glyphName.isEmpty())
    
    49
    +    glyphName = "(none)";
    
    50
    +  glyphNameLabel_->setText(glyphName);
    
    51
    +
    
    52
    +  auto rect = ctxt.basePosition.translated(-(ctxt.penPos.x()),
    
    53
    +                                           -(ctxt.penPos.y()));
    
    54
    +  bitmapWidget_->updateImage(ctxt.image, rect);
    
    55
    +
    
    56
    +  // load glyphs in all units
    
    57
    +  dpi_ = engine_->dpi();
    
    58
    +  engine_->reloadFont();
    
    59
    +
    
    60
    +  engine_->loadGlyphIntoSlotWithoutCache(ctxt.glyphIndex, true);
    
    61
    +  fontUnitMetrics_ = engine_->currentFaceSlot()->metrics;
    
    62
    +  engine_->loadGlyphIntoSlotWithoutCache(ctxt.glyphIndex, false);
    
    63
    +  pixelMetrics_ = engine_->currentFaceSlot()->metrics;
    
    64
    +
    
    65
    +  changeUnit(unitButtonGroup_->checkedId());
    
    66
    +
    
    67
    +  inkSizeLabel_->setText(QString("(%1, %2) px")
    
    68
    +                                 .arg(rect.width())
    
    69
    +                                 .arg(rect.height()));
    
    70
    +  bitmapOffsetLabel_->setText(QString("(%1, %2) px")
    
    71
    +                                    .arg(rect.x())
    
    72
    +                                    .arg(rect.y()));
    
    73
    +}
    
    74
    +
    
    75
    +
    
    76
    +void
    
    77
    +GlyphDetails::createLayout()
    
    78
    +{
    
    79
    +  unitButtonGroup_ = new QButtonGroup(this);
    
    80
    +  fontUnitButton_ = new QRadioButton(tr("Font Unit"), this);
    
    81
    +  pointButton_ = new QRadioButton(tr("Point"), this);
    
    82
    +  pixelButton_ = new QRadioButton(tr("Pixel"), this);
    
    83
    +  unitButtonGroup_->addButton(fontUnitButton_, DU_FontUnit);
    
    84
    +  unitButtonGroup_->addButton(pointButton_, DU_Point);
    
    85
    +  unitButtonGroup_->addButton(pixelButton_, DU_Pixel);
    
    86
    +  fontUnitButton_->setChecked(true);
    
    87
    +
    
    88
    +  glyphIndexPromptLabel_ = new QLabel(tr("Grid Index:"), this);
    
    89
    +  charCodePromptLabel_ = new QLabel(tr("Char Code:"), this);
    
    90
    +  glyphNamePromptLabel_ = new QLabel(tr("Glyph Name:"), this);
    
    91
    +
    
    92
    +  bboxSizePromptLabel_ = new QLabel(tr("Bounding Box Size:"), this);
    
    93
    +  horiBearingPromptLabel_ = new QLabel(tr("Hori. Bearing:"), this);
    
    94
    +  horiAdvancePromptLabel_ = new QLabel(tr("Hori. Advance:"), this);
    
    95
    +  vertBearingPromptLabel_ = new QLabel(tr("Vert. Bearing:"), this);
    
    96
    +  vertAdvancePromptLabel_ = new QLabel(tr("Vert. Advance:"), this);
    
    97
    +
    
    98
    +  inkSizePromptLabel_ = new QLabel(tr("Ink Size:"), this);
    
    99
    +  bitmapOffsetPromptLabel_ = new QLabel(tr("Bitmap Offset:"), this);
    
    100
    +
    
    101
    +  glyphIndexLabel_ = new QLabel(this);
    
    102
    +  charCodeLabel_ = new QLabel(this);
    
    103
    +  glyphNameLabel_ = new QLabel(this);
    
    104
    +
    
    105
    +  bboxSizeLabel_ = new QLabel(this);
    
    106
    +  horiBearingLabel_ = new QLabel(this);
    
    107
    +  horiAdvanceLabel_ = new QLabel(this);
    
    108
    +  vertBearingLabel_ = new QLabel(this);
    
    109
    +  vertAdvanceLabel_ = new QLabel(this);
    
    110
    +
    
    111
    +  inkSizeLabel_ = new QLabel(this);
    
    112
    +  bitmapOffsetLabel_ = new QLabel(this);
    
    113
    +
    
    114
    +  bitmapWidget_ = new GlyphBitmapWidget(this);
    
    115
    +
    
    116
    +  setLabelSelectable(glyphIndexLabel_);
    
    117
    +  setLabelSelectable(charCodeLabel_);
    
    118
    +  setLabelSelectable(glyphNameLabel_);
    
    119
    +  setLabelSelectable(bboxSizeLabel_);
    
    120
    +  setLabelSelectable(horiBearingLabel_);
    
    121
    +  setLabelSelectable(horiAdvanceLabel_);
    
    122
    +  setLabelSelectable(vertBearingLabel_);
    
    123
    +  setLabelSelectable(vertAdvanceLabel_);
    
    124
    +  setLabelSelectable(inkSizeLabel_);
    
    125
    +  setLabelSelectable(bitmapOffsetLabel_);
    
    126
    +
    
    127
    +  unitLayout_ = new QHBoxLayout;
    
    128
    +  unitLayout_->addWidget(fontUnitButton_);
    
    129
    +  unitLayout_->addWidget(pointButton_);
    
    130
    +  unitLayout_->addWidget(pixelButton_);
    
    131
    +
    
    132
    +  layout_ = new QGridLayout;
    
    133
    +  layout_->addLayout(unitLayout_, 0, 0, 1, 2);
    
    134
    +  layout_->addItem(new QSpacerItem(0, 18), 1, 0, 1, 2);
    
    135
    +
    
    136
    +  layout_->addWidget(glyphIndexPromptLabel_, 2, 0);
    
    137
    +  layout_->addWidget(charCodePromptLabel_,   3, 0);
    
    138
    +  layout_->addWidget(glyphNamePromptLabel_,  4, 0);
    
    139
    +  layout_->addItem(new QSpacerItem(0, 18), 5, 0, 1, 2);
    
    140
    +
    
    141
    +  layout_->addWidget(bboxSizePromptLabel_,    6, 0);
    
    142
    +  layout_->addWidget(horiBearingPromptLabel_, 7, 0);
    
    143
    +  layout_->addWidget(horiAdvancePromptLabel_, 8, 0);
    
    144
    +  layout_->addWidget(vertBearingPromptLabel_, 9, 0);
    
    145
    +  layout_->addWidget(vertAdvancePromptLabel_, 10, 0);
    
    146
    +  layout_->addItem(new QSpacerItem(0, 18), 11, 0, 1, 2);
    
    147
    +
    
    148
    +  layout_->addWidget(inkSizePromptLabel_,      12, 0);
    
    149
    +  layout_->addWidget(bitmapOffsetPromptLabel_, 13, 0);
    
    150
    +
    
    151
    +  layout_->addWidget(glyphIndexLabel_, 2, 1);
    
    152
    +  layout_->addWidget(charCodeLabel_,   3, 1);
    
    153
    +  layout_->addWidget(glyphNameLabel_,  4, 1);
    
    154
    +
    
    155
    +  layout_->addWidget(bboxSizeLabel_,    6, 1);
    
    156
    +  layout_->addWidget(horiBearingLabel_, 7, 1);
    
    157
    +  layout_->addWidget(horiAdvanceLabel_, 8, 1);
    
    158
    +  layout_->addWidget(vertBearingLabel_, 9, 1);
    
    159
    +  layout_->addWidget(vertAdvanceLabel_, 10, 1);
    
    160
    +
    
    161
    +  layout_->addWidget(inkSizeLabel_,      12, 1);
    
    162
    +  layout_->addWidget(bitmapOffsetLabel_, 13, 1);
    
    163
    +  layout_->addItem(new QSpacerItem(0, 18), 14, 0, 1, 2);
    
    164
    +
    
    165
    +  layout_->addWidget(bitmapWidget_, 15, 0, 1, 2);
    
    166
    +
    
    167
    +  layout_->setColumnStretch(1, 1);
    
    168
    +  layout_->setRowStretch(15, 1);
    
    169
    +
    
    170
    +  setLayout(layout_);
    
    171
    +  setContentsMargins(12, 12, 12, 12);
    
    172
    +  setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    
    173
    +}
    
    174
    +
    
    175
    +
    
    176
    +void
    
    177
    +GlyphDetails::createConnections()
    
    178
    +{
    
    179
    +  connect(unitButtonGroup_, &QButtonGroup::idClicked,
    
    180
    +          this, &GlyphDetails::changeUnit);
    
    181
    +}
    
    182
    +
    
    183
    +
    
    184
    +void
    
    185
    +GlyphDetails::changeUnit(int unitId)
    
    186
    +{
    
    187
    +  QString unitSuffix;
    
    188
    +  double bboxW = -1, bboxH = -1;
    
    189
    +  double horiBearingX = -1, horiBearingY = -1;
    
    190
    +  double horiAdvance = -1;
    
    191
    +  double vertBearingX = -1, vertBearingY = -1;
    
    192
    +  double vertAdvance = -1;
    
    193
    +  switch (static_cast<DisplayUnit>(unitId))
    
    194
    +  {
    
    195
    +  case DU_FontUnit:
    
    196
    +    unitSuffix = "";
    
    197
    +    bboxW = fontUnitMetrics_.width;
    
    198
    +    bboxH = fontUnitMetrics_.height;
    
    199
    +    horiBearingX = fontUnitMetrics_.horiBearingX;
    
    200
    +    horiBearingY = fontUnitMetrics_.horiBearingY;
    
    201
    +    horiAdvance = fontUnitMetrics_.horiAdvance;
    
    202
    +    vertBearingX = fontUnitMetrics_.vertBearingX;
    
    203
    +    vertBearingY = fontUnitMetrics_.vertBearingY;
    
    204
    +    vertAdvance = fontUnitMetrics_.vertAdvance;
    
    205
    +    break;
    
    206
    +
    
    207
    +  case DU_Point:
    
    208
    +    unitSuffix = " pt";
    
    209
    +    // 1.125 = 72 / 64
    
    210
    +    bboxW = pixelMetrics_.width * 1.125 / dpi_;
    
    211
    +    bboxH = pixelMetrics_.height * 1.125 / dpi_;
    
    212
    +    horiBearingX = pixelMetrics_.horiBearingX * 1.125 / dpi_;
    
    213
    +    horiBearingY = pixelMetrics_.horiBearingY * 1.125 / dpi_;
    
    214
    +    horiAdvance = pixelMetrics_.horiAdvance * 1.125 / dpi_;
    
    215
    +    vertBearingX = pixelMetrics_.vertBearingX * 1.125 / dpi_;
    
    216
    +    vertBearingY = pixelMetrics_.vertBearingY * 1.125 / dpi_;
    
    217
    +    vertAdvance = pixelMetrics_.vertAdvance * 1.125 / dpi_;
    
    218
    +    break;
    
    219
    +    
    
    220
    +  case DU_Pixel:
    
    221
    +    unitSuffix = " px";
    
    222
    +    bboxW = pixelMetrics_.width/ 64.0;
    
    223
    +    bboxH = pixelMetrics_.height/ 64.0;
    
    224
    +    horiBearingX = pixelMetrics_.horiBearingX/ 64.0;
    
    225
    +    horiBearingY = pixelMetrics_.horiBearingY/ 64.0;
    
    226
    +    horiAdvance = pixelMetrics_.horiAdvance/ 64.0;
    
    227
    +    vertBearingX = pixelMetrics_.vertBearingX/ 64.0;
    
    228
    +    vertBearingY = pixelMetrics_.vertBearingY/ 64.0;
    
    229
    +    vertAdvance = pixelMetrics_.vertAdvance/ 64.0;
    
    230
    +    break;
    
    231
    +  }
    
    232
    +
    
    233
    +  auto tmpl = QString("%1") + unitSuffix;
    
    234
    +  auto tmplPair = QString("(%1, %2)") + unitSuffix;
    
    235
    +  bboxSizeLabel_->setText(tmplPair.arg(bboxW).arg(bboxH));
    
    236
    +  horiBearingLabel_->setText(tmplPair.arg(horiBearingX).arg(horiBearingY));
    
    237
    +  horiAdvanceLabel_->setText(tmpl.arg(horiAdvance));
    
    238
    +  vertBearingLabel_->setText(tmplPair.arg(vertBearingX).arg(vertBearingY));
    
    239
    +  vertAdvanceLabel_->setText(tmpl.arg(vertAdvance));
    
    240
    +}
    
    241
    +
    
    242
    +
    
    243
    +// end of glyphdetails.cpp

  • src/ftinspect/panels/glyphdetails.hpp
    1
    +// glyphdetails.hpp
    
    2
    +
    
    3
    +// Copyright (C) 2022 by Charlie Jiang.
    
    4
    +
    
    5
    +#pragma once
    
    6
    +
    
    7
    +#include "../rendering/glyphbitmap.hpp"
    
    8
    +
    
    9
    +#include <QWidget>
    
    10
    +#include <QLabel>
    
    11
    +#include <QGridLayout>
    
    12
    +#include <QBoxLayout>
    
    13
    +#include <QImage>
    
    14
    +#include <QRadioButton>
    
    15
    +#include <QButtonGroup>
    
    16
    +
    
    17
    +#include <freetype/freetype.h>
    
    18
    +
    
    19
    +struct GlyphCacheEntry;
    
    20
    +class Engine;
    
    21
    +class GlyphDetails
    
    22
    +: public QWidget
    
    23
    +{
    
    24
    +public:
    
    25
    +  GlyphDetails(QWidget* parent, Engine* engine);
    
    26
    +  ~GlyphDetails() override;
    
    27
    +
    
    28
    +  void updateGlyph(GlyphCacheEntry& ctxt,
    
    29
    +                   int charMapIndex);
    
    30
    +
    
    31
    +private:
    
    32
    +  Engine* engine_ = NULL;
    
    33
    +
    
    34
    +  enum DisplayUnit : int
    
    35
    +  {
    
    36
    +    DU_FontUnit,
    
    37
    +    DU_Point,
    
    38
    +    DU_Pixel
    
    39
    +  };
    
    40
    +
    
    41
    +  QButtonGroup* unitButtonGroup_;
    
    42
    +  QRadioButton* fontUnitButton_;
    
    43
    +  QRadioButton* pointButton_;
    
    44
    +  QRadioButton* pixelButton_;
    
    45
    +
    
    46
    +  QLabel* glyphIndexPromptLabel_;
    
    47
    +  QLabel* charCodePromptLabel_;
    
    48
    +  QLabel* glyphNamePromptLabel_;
    
    49
    +  QLabel* bboxSizePromptLabel_;
    
    50
    +  QLabel* horiBearingPromptLabel_;
    
    51
    +  QLabel* horiAdvancePromptLabel_;
    
    52
    +  QLabel* vertBearingPromptLabel_;
    
    53
    +  QLabel* vertAdvancePromptLabel_;
    
    54
    +  QLabel* inkSizePromptLabel_;
    
    55
    +  QLabel* bitmapOffsetPromptLabel_;
    
    56
    +
    
    57
    +  QLabel* glyphIndexLabel_;
    
    58
    +  QLabel* charCodeLabel_;
    
    59
    +  QLabel* glyphNameLabel_;
    
    60
    +  QLabel* bboxSizeLabel_;
    
    61
    +  QLabel* horiBearingLabel_;
    
    62
    +  QLabel* horiAdvanceLabel_;
    
    63
    +  QLabel* vertBearingLabel_;
    
    64
    +  QLabel* vertAdvanceLabel_;
    
    65
    +  QLabel* inkSizeLabel_;
    
    66
    +  QLabel* bitmapOffsetLabel_;
    
    67
    +
    
    68
    +  GlyphBitmapWidget* bitmapWidget_;
    
    69
    +
    
    70
    +  QHBoxLayout* unitLayout_;
    
    71
    +  QGridLayout* layout_;
    
    72
    +
    
    73
    +  int dpi_;
    
    74
    +  FT_Glyph_Metrics fontUnitMetrics_, pixelMetrics_;
    
    75
    +
    
    76
    +  void createLayout();
    
    77
    +  void createConnections();
    
    78
    +
    
    79
    +  void changeUnit(int unitId);
    
    80
    +};
    
    81
    +
    
    82
    +
    
    83
    +// end of glyphdetails.hpp

  • src/ftinspect/rendering/glyphbitmap.cpp
    ... ... @@ -9,25 +9,31 @@
    9 9
     #include "../engine/engine.hpp"
    
    10 10
     
    
    11 11
     #include <cmath>
    
    12
    +#include <utility>
    
    13
    +#include <qevent.h>
    
    12 14
     #include <QPainter>
    
    13 15
     #include <QStyleOptionGraphicsItem>
    
    14 16
     #include <freetype/ftbitmap.h>
    
    15 17
     
    
    16 18
     
    
    19
    +GlyphBitmap::GlyphBitmap(QImage* image,
    
    20
    +                         QRect rect)
    
    21
    +: image_(image),
    
    22
    +  boundingRect_(rect)
    
    23
    +{
    
    24
    +
    
    25
    +}
    
    26
    +
    
    27
    +
    
    17 28
     GlyphBitmap::GlyphBitmap(int glyphIndex, 
    
    18 29
                              FT_Glyph glyph,
    
    19 30
                              Engine* engine)
    
    20 31
     {
    
    21 32
       QRect bRect;
    
    22
    -  image_ = engine->tryDirectRenderColorLayers(glyphIndex, &bRect);
    
    23
    -  if (image_)
    
    24
    -  {
    
    25
    -    bRect.setTop(-bRect.top());
    
    26
    -    boundingRect_ = bRect; // QRect to QRectF
    
    27
    -    return;
    
    28
    -  }
    
    33
    +  image_ = engine->tryDirectRenderColorLayers(glyphIndex, &bRect, true);
    
    29 34
     
    
    30
    -  image_ = engine->convertGlyphToQImage(glyph, &bRect, true);
    
    35
    +  if (!image_)
    
    36
    +    image_ = engine->convertGlyphToQImage(glyph, &bRect, true);
    
    31 37
       boundingRect_ = bRect; // QRect to QRectF
    
    32 38
     }
    
    33 39
     
    
    ... ... @@ -60,8 +66,8 @@ GlyphBitmap::paint(QPainter* painter,
    60 66
                          image.convertToFormat(
    
    61 67
                            QImage::Format_ARGB32_Premultiplied));
    
    62 68
     #else
    
    63
    -  const qreal lod = option->levelOfDetailFromTransform(
    
    64
    -                              painter->worldTransform());
    
    69
    +  const qreal lod = QStyleOptionGraphicsItem::levelOfDetailFromTransform(
    
    70
    +      painter->worldTransform());
    
    65 71
     
    
    66 72
       painter->setPen(Qt::NoPen);
    
    67 73
     
    
    ... ... @@ -85,4 +91,69 @@ GlyphBitmap::paint(QPainter* painter,
    85 91
     }
    
    86 92
     
    
    87 93
     
    
    94
    +GlyphBitmapWidget::GlyphBitmapWidget(QWidget* parent)
    
    95
    +: QWidget(parent)
    
    96
    +{
    
    97
    +  
    
    98
    +}
    
    99
    +
    
    100
    +
    
    101
    +GlyphBitmapWidget::~GlyphBitmapWidget()
    
    102
    +{
    
    103
    +  releaseImage();
    
    104
    +}
    
    105
    +
    
    106
    +
    
    107
    +void
    
    108
    +GlyphBitmapWidget::updateImage(QImage* image,
    
    109
    +                               QRect rect)
    
    110
    +{
    
    111
    +  // XXX: really need to do this?
    
    112
    +  rect.moveTop(0);
    
    113
    +  rect.moveLeft(0);
    
    114
    +
    
    115
    +  delete bitmapItem_;
    
    116
    +  auto* copied = new QImage(image->copy());
    
    117
    +  bitmapItem_ = new GlyphBitmap(copied, rect);
    
    118
    +
    
    119
    +  repaint();
    
    120
    +}
    
    121
    +
    
    122
    +
    
    123
    +void
    
    124
    +GlyphBitmapWidget::releaseImage()
    
    125
    +{
    
    126
    +  delete bitmapItem_;
    
    127
    +  bitmapItem_ = NULL;
    
    128
    +  repaint();
    
    129
    +}
    
    130
    +
    
    131
    +
    
    132
    +void
    
    133
    +GlyphBitmapWidget::paintEvent(QPaintEvent* event)
    
    134
    +{
    
    135
    +  if (!bitmapItem_)
    
    136
    +    return;
    
    137
    +  auto s = size();
    
    138
    +  auto br = bitmapItem_->boundingRect();
    
    139
    +  double xScale = s.width() / br.width();
    
    140
    +  double yScale = s.height() / br.height();
    
    141
    +  auto scale = std::min(xScale, yScale);
    
    142
    +
    
    143
    +  QPainter painter(this);
    
    144
    +  painter.scale(scale, scale);
    
    145
    +
    
    146
    +  QStyleOptionGraphicsItem ogi;
    
    147
    +  ogi.exposedRect = br;
    
    148
    +  bitmapItem_->paint(&painter, &ogi, this);
    
    149
    +}
    
    150
    +
    
    151
    +
    
    152
    +QSize
    
    153
    +GlyphBitmapWidget::sizeHint() const
    
    154
    +{
    
    155
    +  return { 300, 300 };
    
    156
    +}
    
    157
    +
    
    158
    +
    
    88 159
     // end of glyphbitmap.cpp

  • src/ftinspect/rendering/glyphbitmap.hpp
    ... ... @@ -7,6 +7,8 @@
    7 7
     
    
    8 8
     #include <QGraphicsItem>
    
    9 9
     #include <QPen>
    
    10
    +#include <QPaintEvent>
    
    11
    +#include <QWidget>
    
    10 12
     
    
    11 13
     #include <ft2build.h>
    
    12 14
     #include <freetype/freetype.h>
    
    ... ... @@ -20,6 +22,8 @@ class GlyphBitmap
    20 22
     : public QGraphicsItem
    
    21 23
     {
    
    22 24
     public:
    
    25
    +  GlyphBitmap(QImage* image,
    
    26
    +              QRect rect);
    
    23 27
       GlyphBitmap(int glyphIndex,
    
    24 28
                   FT_Glyph glyph,
    
    25 29
                   Engine* engine);
    
    ... ... @@ -34,5 +38,25 @@ private:
    34 38
       QRectF boundingRect_;
    
    35 39
     };
    
    36 40
     
    
    41
    +// Sometimes we don't want a complicated QGraphicsView
    
    42
    +// for this kind of work...
    
    43
    +class GlyphBitmapWidget
    
    44
    +: public QWidget
    
    45
    +{
    
    46
    +public:
    
    47
    +  GlyphBitmapWidget(QWidget* parent);
    
    48
    +  ~GlyphBitmapWidget() override;
    
    49
    +
    
    50
    +  void updateImage(QImage* image, QRect rect);
    
    51
    +  void releaseImage();
    
    52
    +
    
    53
    +protected:
    
    54
    +  void paintEvent(QPaintEvent* event) override;
    
    55
    +  QSize sizeHint() const override;
    
    56
    +
    
    57
    +private:
    
    58
    +  GlyphBitmap* bitmapItem_ = NULL;
    
    59
    +};
    
    60
    +
    
    37 61
     
    
    38 62
     // end of glyphbitmap.hpp

  • src/ftinspect/rendering/glyphcontinuous.cpp
    ... ... @@ -197,7 +197,9 @@ GlyphContinuous::mouseReleaseEvent(QMouseEvent* event)
    197 197
         auto dist = event->pos() - mouseDownPostition_;
    
    198 198
         if (dist.manhattanLength() < ClickDragThreshold)
    
    199 199
         {
    
    200
    -      // TODO: clicked down, open overlay
    
    200
    +      auto gl = findGlyphByMouse(event->pos(), NULL);
    
    201
    +      if (gl)
    
    202
    +        emit updateGlyphDetails(gl, stringRenderer_.charMapIndex(), true);
    
    201 203
         }
    
    202 204
       }
    
    203 205
       else if (event->button() == Qt::RightButton)
    
    ... ... @@ -222,9 +224,12 @@ GlyphContinuous::paintByRenderer()
    222 224
           saveSingleGlyph(glyph, penPos, ctx);
    
    223 225
         });
    
    224 226
       stringRenderer_.setImageCallback(
    
    225
    -    [&](QImage* image, QRect pos, FT_Vector advance, GlyphContext& ctx)
    
    227
    +    [&](QImage* image,
    
    228
    +        QRect pos, 
    
    229
    +        FT_Vector penPos, FT_Vector advance,
    
    230
    +        GlyphContext& ctx)
    
    226 231
         {
    
    227
    -      saveSingleGlyphImage(image, pos, advance, ctx);
    
    232
    +      saveSingleGlyphImage(image, pos, penPos, advance, ctx);
    
    228 233
         });
    
    229 234
       stringRenderer_.setPreprocessCallback(
    
    230 235
         [&](FT_Glyph* ptr)
    
    ... ... @@ -413,12 +418,13 @@ GlyphContinuous::saveSingleGlyph(FT_Glyph glyph,
    413 418
       if (!currentWritingLine_)
    
    414 419
         return;
    
    415 420
     
    
    416
    -  currentWritingLine_->entries.push_back(std::move(GlyphCacheEntry{}));