freetype-commit
[Top][All Lists]
Advanced

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

[freetype2-demos] master 9a746ee 31/41: [ftinspect] Add transformation a


From: Werner Lemberg
Subject: [freetype2-demos] master 9a746ee 31/41: [ftinspect] Add transformation and scaling info to the composite glyph view.
Date: Mon, 3 Oct 2022 11:27:03 -0400 (EDT)

branch: master
commit 9a746eeafdd3b0a2eaff284f752f67e1eeaffcb3
Author: Charlie Jiang <w@chariri.moe>
Commit: Werner Lemberg <wl@gnu.org>

    [ftinspect] Add transformation and scaling info to the composite glyph view.
    
    Note: Untested since no font with non-1.0 scale subglyphs is found.
    
    * src/ftinspect/engine/fontinfo.cpp, src/ftinspect/engine/fontinfo.hpp:
      Fetch transformation and scaling info from the font.
    
    * src/ftinspect/models/fontinfomodels.cpp,
      src/ftinspect/models/fontinfomodels.hpp:
      Change the "Position" column to "Position and Transformation".
      Display the transformation info.
---
 src/ftinspect/engine/fontinfo.cpp       | 61 ++++++++++++++++++++----
 src/ftinspect/engine/fontinfo.hpp       | 32 +++++++++++--
 src/ftinspect/models/fontinfomodels.cpp | 83 +++++++++++++++++++++------------
 src/ftinspect/models/fontinfomodels.hpp |  4 +-
 4 files changed, 132 insertions(+), 48 deletions(-)

diff --git a/src/ftinspect/engine/fontinfo.cpp 
b/src/ftinspect/engine/fontinfo.cpp
index 5927409..e99dcb6 100644
--- a/src/ftinspect/engine/fontinfo.cpp
+++ b/src/ftinspect/engine/fontinfo.cpp
@@ -571,6 +571,21 @@ SFNTTableInfo::getForAll(Engine* engine,
 }
 
 
+
+FT_UInt16
+readUInt16(void* ptr)
+{
+  return bigEndianToNative(*static_cast<uint16_t*>(ptr));
+}
+
+
+double
+readF2Dot14(void* ptr)
+{
+  return static_cast<int16_t>(readUInt16(ptr)) / 16384.0;
+}
+
+
 void
 CompositeGlyphInfo::get(Engine* engine, 
                         std::vector<CompositeGlyphInfo>& list)
@@ -641,7 +656,7 @@ CompositeGlyphInfo::get(Engine* engine,
     if (loc + 16 > end)
       continue;
 
-    auto len = static_cast<FT_Int16>(buffer[loc] << 8 | buffer[loc + 1]);
+    auto len = static_cast<FT_Int16>(readUInt16(buffer + loc));
     loc += 10;  // skip header
     if (len >= 0) // not a composite one
       continue;
@@ -652,18 +667,18 @@ CompositeGlyphInfo::get(Engine* engine,
     {
       if (loc + 6 > end)
         break;
-      auto flags = static_cast<FT_UInt16>(buffer[loc] << 8 | buffer[loc + 1]);
+      auto flags = readUInt16(buffer + loc);
       loc += 2;
-      auto index = static_cast<FT_UInt16>(buffer[loc] << 8 | buffer[loc + 1]);
+      auto index = readUInt16(buffer + loc);
       loc += 2;
       FT_Int16 arg1, arg2;
 
       // 
https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#composite-glyph-description
       if (flags & 0x0001)
       {
-        arg1 = static_cast<FT_Int16>(buffer[loc] << 8 | buffer[loc + 1]);
+        arg1 = static_cast<FT_Int16>(readUInt16(buffer + loc));
         loc += 2;
-        arg2 = static_cast<FT_Int16>(buffer[loc] << 8 | buffer[loc + 1]);
+        arg2 = static_cast<FT_Int16>(readUInt16(buffer + loc));
         loc += 2;
       }
       else
@@ -672,17 +687,43 @@ CompositeGlyphInfo::get(Engine* engine,
         arg2 = buffer[loc + 1];
         loc += 2;
       }
+
+      subglyphs.emplace_back(index, flags,
+                             flags & 0x0002 ? SubGlyph::PT_Offset
+                                            : SubGlyph::PT_Align,
+                             std::pair<short, short>(arg1, arg2),
+                             (flags & 0x0800) != 0);
+      // TODO: Use "Default behavior" when neither SCALED_COMPONENT_OFFSET
+      //       and UNSCALED_COMPONENT_OFFSET are set.
+
+      auto& glyph = subglyphs.back();
       if (flags & 0x0008)
+      {
+        glyph.transformationType = SubGlyph::TT_UniformScale;
+        glyph.transformation[0] = readF2Dot14(buffer + loc);
         loc += 2;
+      }
       else if (flags & 0x0040)
+      {
+        glyph.transformationType = SubGlyph::TT_XYScale;
+        glyph.transformation[0] = readF2Dot14(buffer + loc);
+        glyph.transformation[1] = readF2Dot14(buffer + loc + 2);
         loc += 4;
+      }
       else if (flags & 0x0080)
+      {
+        glyph.transformationType = SubGlyph::TT_Matrix;
+        glyph.transformation[0] = readF2Dot14(buffer + loc);
+        glyph.transformation[1] = readF2Dot14(buffer + loc + 2);
+        glyph.transformation[2] = readF2Dot14(buffer + loc + 4);
+        glyph.transformation[3] = readF2Dot14(buffer + loc + 6);
         loc += 8;
-
-      subglyphs.emplace_back(index, flags,
-                             flags & 0x0002 ? SubGlyph::PT_Offset
-                                            : SubGlyph::PT_Align,
-                             std::pair<short, short>(arg1, arg2));
+      }
+      else
+      {
+        glyph.transformationType = SubGlyph::TT_UniformScale;
+        glyph.transformation[0] = 1.0;
+      }
 
       if (!(flags & 0x0020))
         break;
diff --git a/src/ftinspect/engine/fontinfo.hpp 
b/src/ftinspect/engine/fontinfo.hpp
index f28dc81..5a5fb1b 100644
--- a/src/ftinspect/engine/fontinfo.hpp
+++ b/src/ftinspect/engine/fontinfo.hpp
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <set>
+#include <cstring>
 #include <QDateTime>
 #include <QByteArray>
 #include <QString>
@@ -248,27 +249,44 @@ struct CompositeGlyphInfo
 {
   struct SubGlyph
   {
-    enum PositionType
+    enum PositionType : uint8_t
     {
       PT_Offset, // Child's points are added with a xy-offset
       PT_Align // One point of the child is aligned with one point of the 
parent
     };
+    enum TransformationType : uint8_t
+    {
+      TT_UniformScale, // uniform scale for x- and y-axis
+      TT_XYScale, // separate scale for x- and y-axis
+      TT_Matrix // 2x2 matrix
+    };
     unsigned short index;
     unsigned short flag;
     PositionType positionType;
     // For PT_Offset: <deltaX, deltaY>
     // For PT_Align:  <childPoint, parentPoint>
     std::pair<short, short> position;
+    bool positionScaled;
+    TransformationType transformationType;
+    // For TT_UniformScale: transformation[0] is the scale
+    // For TT_XYScale: transformation[0]: x-scale; transformation[1]: y-scale
+    // For TT_Matrix: transformation is layouted as
+    //                [xscale, scale01, scale10, yscale]
+    double transformation[4];
+
 
     SubGlyph(unsigned short index,
              unsigned short flag,
              PositionType positionType,
-             std::pair<short, short> position)
+             std::pair<short, short> position,
+             bool positionScaled)
     : index(index),
       flag(flag),
       positionType(positionType),
-      position(std::move(position))
-    { }
+      position(std::move(position)),
+      positionScaled(positionScaled)
+    {
+    }
 
 
     friend bool
@@ -278,7 +296,11 @@ struct CompositeGlyphInfo
       return lhs.index == rhs.index
         && lhs.flag == rhs.flag
         && lhs.positionType == rhs.positionType
-        && lhs.position == rhs.position;
+        && lhs.position == rhs.position
+        && lhs.positionScaled == rhs.positionScaled
+        && lhs.transformationType == rhs.transformationType
+        && !std::memcmp(lhs.transformation, rhs.transformation,
+                        4 * sizeof(double));
     }
 
 
diff --git a/src/ftinspect/models/fontinfomodels.cpp 
b/src/ftinspect/models/fontinfomodels.cpp
index ea63e03..107c42d 100644
--- a/src/ftinspect/models/fontinfomodels.cpp
+++ b/src/ftinspect/models/fontinfomodels.cpp
@@ -571,6 +571,53 @@ CompositeGlyphsInfoModel::parent(const QModelIndex& child) 
const
 }
 
 
+QString
+generatePositionTransformationText(CompositeGlyphInfo::SubGlyph const& info)
+{
+  QString result;
+  switch (info.transformationType)
+  {
+  case CompositeGlyphInfo::SubGlyph::TT_UniformScale:
+    result += QString("scale: %1, ")
+                .arg(QString::number(info.transformation[0]));
+    break;
+  case CompositeGlyphInfo::SubGlyph::TT_XYScale: 
+    result += QString("xy scale: (%1, %2), ")
+                .arg(QString::number(info.transformation[0]),
+                     QString::number(info.transformation[1]));
+    break;
+  case CompositeGlyphInfo::SubGlyph::TT_Matrix:
+    result += QString("2x2 scale: [%1, %2; %3, %4], ")
+                .arg(QString::number(info.transformation[0]),
+                     QString::number(info.transformation[1]),
+                     QString::number(info.transformation[2]),
+                     QString::number(info.transformation[3]));
+    break;
+  }
+
+  auto pos = info.position;
+  switch (info.positionType)
+  {
+  case CompositeGlyphInfo::SubGlyph::PT_Offset:
+    if (info.positionScaled)
+      result += QString("scaled offset: (%1, %2)")
+                  .arg(QString::number(info.position.first),
+                       QString::number(info.position.second));
+    else
+      result += QString("offset: (%1, %2)")
+                  .arg(QString::number(info.position.first),
+                       QString::number(info.position.second));
+    break;
+  case CompositeGlyphInfo::SubGlyph::PT_Align:
+      result += QString("anchor points: %1 (parent) <- %2 (this glyph)")
+                  .arg(QString::number(info.position.first),
+                       QString::number(info.position.second));
+    break;
+  }
+  return result;
+}
+
+
 QVariant
 CompositeGlyphsInfoModel::data(const QModelIndex& index,
                                int role) const
@@ -584,25 +631,6 @@ CompositeGlyphsInfoModel::data(const QModelIndex& index,
   auto& n = nodes_[id];
   auto glyphIdx = n.glyphIndex;
 
-  if (role == Qt::ToolTipRole && index.column() == CGIM_Position)
-  {
-    if (!n.subGlyphInfo)
-      return {};
-    auto pos = n.subGlyphInfo->position;
-    switch (n.subGlyphInfo->positionType)
-    {
-    case CompositeGlyphInfo::SubGlyph::PT_Offset:
-      return QString("Add a offset (%1, %2) to the subglyph's points")
-          .arg(pos.first)
-          .arg(pos.second);
-    case CompositeGlyphInfo::SubGlyph::PT_Align:
-      return QString("Align parent's point %1 to subglyph's point %2")
-          .arg(pos.first)
-          .arg(pos.second);
-    }
-    return {};
-  }
-
   if (role == Qt::DecorationRole && index.column() == CGIM_Glyph)
   {
     auto glyphIndex = n.glyphIndex;
@@ -628,19 +656,12 @@ CompositeGlyphsInfoModel::data(const QModelIndex& index,
   case CGIM_Flag:
     if (!n.subGlyphInfo)
       return {};
-    return QString::number(n.subGlyphInfo->flag, 16).rightJustified(4, '0');
-  case CGIM_Position:
+    return QString("0x%1").arg(n.subGlyphInfo->flag, 4, 16, QLatin1Char('0'));
+  case CGIM_PositionTransformation:
   {
     if (!n.subGlyphInfo)
       return {};
-    auto pos = n.subGlyphInfo->position;
-    switch (n.subGlyphInfo->positionType)
-    {
-    case CompositeGlyphInfo::SubGlyph::PT_Offset:
-      return QString("Offset (%1, %2)").arg(pos.first).arg(pos.second);
-    case CompositeGlyphInfo::SubGlyph::PT_Align:
-      return QString("Align %1 -> %2").arg(pos.first).arg(pos.second);
-    }
+    return generatePositionTransformationText(*n.subGlyphInfo);
   }
   default:;
   }
@@ -665,8 +686,8 @@ CompositeGlyphsInfoModel::headerData(int section,
     return tr("Glyph");
   case CGIM_Flag:
     return tr("Flags");
-  case CGIM_Position:
-    return tr("Position");
+  case CGIM_PositionTransformation:
+    return tr("Position and Transformation");
   default:;
   }
   return {};
diff --git a/src/ftinspect/models/fontinfomodels.hpp 
b/src/ftinspect/models/fontinfomodels.hpp
index 22d4aab..ab73c80 100644
--- a/src/ftinspect/models/fontinfomodels.hpp
+++ b/src/ftinspect/models/fontinfomodels.hpp
@@ -259,9 +259,9 @@ public:
 
   enum Columns : int
   {
-    CGIM_Glyph = 0, // TODO: transformation, scale? consider more flags?
+    CGIM_Glyph = 0,
     CGIM_Flag = 1,
-    CGIM_Position = 2,
+    CGIM_PositionTransformation = 2,
     CGIM_Max
   };
 



reply via email to

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