freetype-commit
[Top][All Lists]
Advanced

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

[freetype2-demos] gsoc-2022-chariri-3 1e38831 06/36: [ftinspect] Support


From: Werner Lemberg
Subject: [freetype2-demos] gsoc-2022-chariri-3 1e38831 06/36: [ftinspect] Support embedded bitmap, refactor rendering.
Date: Wed, 27 Jul 2022 06:32:44 -0400 (EDT)

branch: gsoc-2022-chariri-3
commit 1e38831a49ffe7d00f11c6b44513d09d9660f2d6
Author: Charlie Jiang <w@chariri.moe>
Commit: Charlie Jiang <w@chariri.moe>

    [ftinspect] Support embedded bitmap, refactor rendering.
    
    This commit supported embedded bitmap and more FreeType font types. Singular
    rendering widgets are refactored so they're more flexible about glyph and
    bitmap types.
    
    Replace `loadOutline` in `Engine` to `loadGlyph` and add other glyph
    formats. Move the rasterization from `GlyphBitmap` to `Engine` to decouple
    rendering from specific widgets. Engine will produce `QImage` object so
    render widgets can be agnostic about glyph type.
    
    Added "Enable Embedded Bitmap" checkbox to the GUI, so one can still force
    disable embedded bitmap output. Outline, points and point numbers showing
    are hidden when the glyph format isn't outline.
    
    LCD rendering is not yet supported because `convertLCDToARGB` and
    `convertLCDVToARGB` are not implemented.
    
    * src/ftinspect/engine/engine.cpp, src/ftinspect/engine/engine.hpp:
      Replace `loadOutline` to `loadGlyph`, and enable non-outline glyph types.
      Add `glyphToBitmap`, `convertBitmapTo8Bpp` and `convertBitmapToQImage`.
      Add necessary setting properties.
      TODO: Move `glyphFormatToName` and CharMap related code out from
      `engine.[ch]pp`.
    
    * src/ftinspect/rendering/glyphbitmap.cpp,
      src/ftinspect/rendering/glyphbitmap.hpp:
      Remove detailed rasterizing code, and use `Engine` to generate `QImage`.
    
    * src/ftinspect/panels/singular.cpp: Use `loadGlyph` instead of
      `loadOutline`, and remove code about pixel mode.
    
    * src/ftinspect/models/ttsettingscomboboxmodel.cpp,
      src/ftinspect/models/ttsettingscomboboxmodel.hpp:
      Make `SimpleComboBoxModel` a template class because the Anti-Aliasing
      setting combo box maps to multiple fields (load flag, render mode and
      RGB/BGR).
      Because Qt disallows template class with Q_OBJECT, we have to use mixin
      instead of inheritance. The new base class is named
      `SimpleComboBoxModelImpl` and subclass delegate function calls to it.
      Those models may subject to refactoring later.
    
    * src/ftinspect/rendering/renderutils.cpp,
      src/ftinspect/rendering/renderutils.hpp:
      Split `computeTransformationToOrigin` out from `transformOutlineToOrigin`.
    
    * src/ftinspect/rendering/glyphoutline.cpp,
      src/ftinspect/rendering/glyphoutline.hpp,
      src/ftinspect/rendering/glyphpoints.cpp,
      src/ftinspect/rendering/glyphpoints.hpp,
      src/ftinspect/rendering/glyphpointnumbers.cpp,
      src/ftinspect/rendering/glyphpointnumbers.hpp:
      Receive `FT_Glyph` instead of `FT_Outline*` as input, but don't preceed if
      the glyph isn't outline-typed.
---
 src/ftinspect/engine/engine.cpp                  | 229 +++++++++++++++++++++--
 src/ftinspect/engine/engine.hpp                  |  23 ++-
 src/ftinspect/models/ttsettingscomboboxmodel.cpp |  62 +-----
 src/ftinspect/models/ttsettingscomboboxmodel.hpp |  79 ++++++--
 src/ftinspect/panels/settingpanel.cpp            |  16 +-
 src/ftinspect/panels/settingpanel.hpp            |   1 +
 src/ftinspect/panels/singular.cpp                |  22 +--
 src/ftinspect/rendering/glyphbitmap.cpp          |  67 ++-----
 src/ftinspect/rendering/glyphbitmap.hpp          |  16 +-
 src/ftinspect/rendering/glyphoutline.cpp         |  14 +-
 src/ftinspect/rendering/glyphoutline.hpp         |   3 +-
 src/ftinspect/rendering/glyphpointnumbers.cpp    |  14 +-
 src/ftinspect/rendering/glyphpointnumbers.hpp    |   3 +-
 src/ftinspect/rendering/glyphpoints.cpp          |  15 +-
 src/ftinspect/rendering/glyphpoints.hpp          |   3 +-
 src/ftinspect/rendering/renderutils.cpp          |  19 +-
 src/ftinspect/rendering/renderutils.hpp          |   5 +
 17 files changed, 411 insertions(+), 180 deletions(-)

diff --git a/src/ftinspect/engine/engine.cpp b/src/ftinspect/engine/engine.cpp
index d6c9428..b9a2bff 100644
--- a/src/ftinspect/engine/engine.cpp
+++ b/src/ftinspect/engine/engine.cpp
@@ -5,12 +5,16 @@
 
 #include "engine.hpp"
 
+#include "../rendering/renderutils.hpp"
+#include "../rendering/graphicsdefault.hpp"
+
 #include <stdexcept>
 #include <stdint.h>
 
 #include <freetype/ftmodapi.h>
 #include <freetype/ftdriver.h>
 #include <freetype/ftlcdfil.h>
+#include <freetype/ftbitmap.h>
 
 
 /////////////////////////////////////////////////////////////////////////////
@@ -153,7 +157,7 @@ Engine::Engine()
   {
     // XXX error handling
   }
-
+  
   queryEngine();
 }
 
@@ -397,8 +401,8 @@ Engine::glyphName(int index)
 }
 
 
-FT_Outline*
-Engine::loadOutline(int glyphIndex)
+FT_Glyph
+Engine::loadGlyph(int glyphIndex)
 {
   update();
 
@@ -407,13 +411,11 @@ Engine::loadOutline(int glyphIndex)
 
   FT_Glyph glyph;
 
-  // XXX handle bitmap fonts
-
   // the `scaler' object is set up by the
   // `update' and `loadFont' methods
   if (FTC_ImageCache_LookupScaler(imageCache_,
                                   &scaler_,
-                                  loadFlags_ | FT_LOAD_NO_BITMAP,
+                                  loadFlags_,
                                   static_cast<unsigned int>(glyphIndex),
                                   &glyph,
                                   NULL))
@@ -422,21 +424,14 @@ Engine::loadOutline(int glyphIndex)
     return NULL;
   }
 
-  if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
-    return NULL;
-
-  FT_OutlineGlyph outlineGlyph = reinterpret_cast<FT_OutlineGlyph>(glyph);
-
-  return &outlineGlyph->outline;
+  return glyph;
 }
 
 
 FT_Glyph
 Engine::loadGlyphWithoutUpdate(int glyphIndex)
 {
-  // TODO bitmap fonts? color layered fonts?
   FT_Glyph glyph;
-  imageType_.flags |= FT_LOAD_NO_BITMAP;
   if (FTC_ImageCache_Lookup(imageCache_,
                             &imageType_,
                             glyphIndex,
@@ -451,6 +446,57 @@ Engine::loadGlyphWithoutUpdate(int glyphIndex)
 }
 
 
+bool
+Engine::glyphToBitmap(FT_Glyph src,
+                      FT_Glyph* out)
+{
+  if (src->format == FT_GLYPH_FORMAT_BITMAP)
+  {
+    *out = src;
+    return false;
+  }
+  if (src->format != FT_GLYPH_FORMAT_OUTLINE)
+  {
+    *out = NULL;
+    return false;
+    // TODO support SVG
+  }
+
+  if (src->format == FT_GLYPH_FORMAT_OUTLINE)
+  {
+    FT_Glyph out2 = src;
+    auto error = FT_Glyph_To_Bitmap(&out2, 
+                                    static_cast<FT_Render_Mode>(renderMode_),
+                                    nullptr,
+                                    false);
+    if (error)
+    {
+      *out = NULL;
+      return false;
+    }
+    *out = out2;
+    return true;
+  }
+
+  *out = NULL;
+  return false;
+}
+
+
+FT_Bitmap
+Engine::convertBitmapTo8Bpp(FT_Bitmap* bitmap)
+{
+  FT_Bitmap out;
+  out.buffer = NULL;
+  auto error = FT_Bitmap_Convert(library_, bitmap, &out, 1);
+  if (error)
+  {
+    // XXX handling?
+  }
+  return out;
+}
+
+
 int
 Engine::numberOfOpenedFonts()
 {
@@ -527,19 +573,19 @@ Engine::update()
   loadFlags_ = FT_LOAD_DEFAULT;
   if (doAutoHinting_)
     loadFlags_ |= FT_LOAD_FORCE_AUTOHINT;
-  loadFlags_ |= FT_LOAD_NO_BITMAP; // XXX handle bitmap fonts also
+
+  if (!embeddedBitmap_)
+    loadFlags_ |= FT_LOAD_NO_BITMAP;
 
   if (doHinting_)
   {
-    // TODO Differentiate RGB/BGR here?
-    unsigned long target = antiAliasingTarget_;
-    loadFlags_ |= target;
+    loadFlags_ |= antiAliasingTarget_;
   }
   else
   {
     loadFlags_ |= FT_LOAD_NO_HINTING;
 
-    if (!antiAliasingEnabled_) // XXX does this hold?
+    if (!antiAliasingEnabled_)
       loadFlags_ |= FT_LOAD_MONOCHROME;
   }
 
@@ -561,7 +607,7 @@ Engine::update()
     scaler_.x_res = dpi_;
     scaler_.y_res = dpi_;
   }
-  
+
   imageType_.width = static_cast<unsigned int>(pixelSize_);
   imageType_.height = static_cast<unsigned int>(pixelSize_);
   imageType_.flags = static_cast<int>(loadFlags_);
@@ -668,6 +714,149 @@ Engine::queryEngine()
 }
 
 
+void
+convertLCDToARGB(FT_Bitmap& bitmap,
+                 QImage& image,
+                 bool isBGR)
+{
+  // TODO to be implemented
+}
+
+
+void
+convertLCDVToARGB(FT_Bitmap& bitmap,
+                  QImage& image,
+                  bool isBGR)
+{
+  // TODO to be implemented
+}
+
+
+QImage*
+Engine::convertBitmapToQImage(FT_Glyph src,
+                              QRect* outRect)
+{
+  QImage* result = NULL;
+  FT_BitmapGlyph bitmapGlyph;
+  bool ownBitmapGlyph
+    = glyphToBitmap(src, reinterpret_cast<FT_Glyph*>(&bitmapGlyph));
+  if (!bitmapGlyph)
+    return result;
+  auto& bmap = bitmapGlyph->bitmap;
+  bool ownBitmap = false;
+
+  int width = bmap.width;
+  int height = bmap.rows;
+  QImage::Format format = QImage::Format_Indexed8; // goto crossing init
+
+  if (bmap.pixel_mode == FT_PIXEL_MODE_GRAY2
+      || bmap.pixel_mode == FT_PIXEL_MODE_GRAY4)
+  {
+    bmap = convertBitmapTo8Bpp(&bmap);
+    if (!bmap.buffer)
+      goto cleanup;
+    ownBitmap = true;
+  }
+
+  if (bmap.pixel_mode == FT_PIXEL_MODE_LCD)
+    width /= 3;
+  else if (bmap.pixel_mode == FT_PIXEL_MODE_LCD_V)
+    height /= 3;
+
+  if (outRect)
+  {
+    outRect->setLeft(bitmapGlyph->left);
+    outRect->setTop(-bitmapGlyph->top);
+    outRect->setWidth(width);
+    outRect->setHeight(height);
+  }
+
+  switch (bmap.pixel_mode)
+  {
+  case FT_PIXEL_MODE_MONO:
+    format = QImage::Format_Mono;
+    break;
+  case FT_PIXEL_MODE_GRAY:
+    format = QImage::Format_Indexed8;
+    break;
+  case FT_PIXEL_MODE_BGRA:
+    // XXX "ARGB" here means BGRA due to endianness - may be problematic
+    // on big-endian machines
+    format = QImage::Format_ARGB32_Premultiplied;
+    break;
+  case FT_PIXEL_MODE_LCD:
+  case FT_PIXEL_MODE_LCD_V:
+    format = QImage::Format_ARGB32;
+    break;
+  default:
+    goto cleanup;
+  }
+
+  switch (bmap.pixel_mode) 
+  {
+  case FT_PIXEL_MODE_MONO:
+  case FT_PIXEL_MODE_GRAY:
+  case FT_PIXEL_MODE_BGRA:
+    {
+      QImage image(bmap.buffer, 
+                   width, height, 
+                   bmap.pitch, 
+                   format);
+      if (bmap.pixel_mode == FT_PIXEL_MODE_GRAY)
+        
image.setColorTable(GraphicsDefault::deafultInstance()->grayColorTable);
+      else if (bmap.pixel_mode == FT_PIXEL_MODE_MONO)
+        
image.setColorTable(GraphicsDefault::deafultInstance()->monoColorTable);
+      result = new QImage(image.copy());
+      // Don't directly use `image` since we're destroying the image
+    }
+    break;
+  case FT_PIXEL_MODE_LCD:;
+    result = new QImage(width, height, format);
+    convertLCDToARGB(bmap, *result, lcdUsesBGR_);
+    break;
+  case FT_PIXEL_MODE_LCD_V:;
+    result = new QImage(width, height, format);
+    convertLCDVToARGB(bmap, *result, lcdUsesBGR_);
+    break;
+  }
+
+cleanup:
+  if (ownBitmapGlyph)
+    FT_Done_Glyph(reinterpret_cast<FT_Glyph>(bitmapGlyph));
+  if (ownBitmap)
+    FT_Bitmap_Done(library_, &bmap);
+
+  return result;
+}
+
+
+QHash<FT_Glyph_Format, QString> glyphFormatNamesCache;
+QHash<FT_Glyph_Format, QString>&
+glyphFormatNames()
+{
+  if (glyphFormatNamesCache.empty())
+  {
+    glyphFormatNamesCache[FT_GLYPH_FORMAT_NONE] = "None/Unknown";
+    glyphFormatNamesCache[FT_GLYPH_FORMAT_COMPOSITE] = "Composite";
+    glyphFormatNamesCache[FT_GLYPH_FORMAT_BITMAP] = "Bitmap";
+    glyphFormatNamesCache[FT_GLYPH_FORMAT_OUTLINE] = "Outline";
+    glyphFormatNamesCache[FT_GLYPH_FORMAT_PLOTTER] = "Plotter";
+    glyphFormatNamesCache[FT_GLYPH_FORMAT_SVG] = "SVG";
+  }
+  return glyphFormatNamesCache;
+}
+
+QString*
+glyphFormatToName(FT_Glyph_Format format)
+{
+  auto& names = glyphFormatNames();
+  auto it = names.find(format);
+  if (it == names.end())
+    return &names[FT_GLYPH_FORMAT_NONE];
+  return &it.value();
+}
+
+
 QHash<FT_Encoding, QString> encodingNamesCache;
 QHash<FT_Encoding, QString>&
 encodingNames()
diff --git a/src/ftinspect/engine/engine.hpp b/src/ftinspect/engine/engine.hpp
index 50be300..757655e 100644
--- a/src/ftinspect/engine/engine.hpp
+++ b/src/ftinspect/engine/engine.hpp
@@ -10,6 +10,8 @@
 #include <vector>
 #include <QString>
 #include <QMap>
+#include <QRect>
+#include <QImage>
 
 #include <ft2build.h>
 #include <freetype/freetype.h>
@@ -60,6 +62,10 @@ private:
   static int maxIndexForFaceAndCharMap(FT_CharMap charMap, unsigned max);
 };
 
+// Some helper functions.
+
+QString* glyphFormatToName(FT_Glyph_Format format);
+
 // FreeType specific data.
 
 class Engine
@@ -92,11 +98,17 @@ public:
   int loadFont(int fontIndex,
                long faceIndex,
                int namedInstanceIndex); // return number of glyphs
-  FT_Outline* loadOutline(int glyphIndex);
+  FT_Glyph loadGlyph(int glyphIndex);
 
   // Sometimes the engine is already updated, and we want to be faster
   FT_Glyph loadGlyphWithoutUpdate(int glyphIndex);
 
+  // Return `true` if you need to free `out`
+  // `out` will be set to NULL in cases of error
+  bool glyphToBitmap(FT_Glyph src, FT_Glyph* out);
+  FT_Bitmap convertBitmapTo8Bpp(FT_Bitmap* bitmap);
+  QImage* convertBitmapToQImage(FT_Glyph src, QRect* outRect);
+
   // reload current triplet, but with updated settings, useful for updating
   // `ftSize_` only
   void reloadFont(); 
@@ -126,7 +138,7 @@ public:
   FontFileManager& fontFileManager() { return fontFileManager_; }
   EngineDefaultValues& engineDefaults() { return engineDefaults_; }
   bool antiAliasingEnabled() { return antiAliasingEnabled_; }
-
+  bool embeddedBitmapEnabled() { return embeddedBitmap_; }
 
   //////// Setters (direct or indirect)
 
@@ -150,7 +162,10 @@ public:
   void setShowSegments(bool showSegments) { showSegments_ = showSegments; }
   void setGamma(double gamma) { gamma_ = gamma; }
   void setAntiAliasingTarget(int target) { antiAliasingTarget_ = target; }
+  void setRenderMode(int mode) { renderMode_ = mode; }
   void setAntiAliasingEnabled(bool enabled) { antiAliasingEnabled_ = enabled; }
+  void setEmbeddedBitmap(bool force) { embeddedBitmap_ = force; }
+  void setLCDUsesBGR(bool isBGR) { lcdUsesBGR_ = isBGR; }
 
   // Note: These 3 functions now takes actual mode/version from FreeType,
   // instead of values from enum in MainGUI!
@@ -203,10 +218,12 @@ private:
   bool doVerticalHinting_;
   bool doBlueZoneHinting_;
   bool showSegments_;
+  bool embeddedBitmap_;
   int antiAliasingTarget_;
+  bool lcdUsesBGR_;
+  int renderMode_;
 
   double gamma_;
-
   unsigned long loadFlags_;
 
   void queryEngine();
diff --git a/src/ftinspect/models/ttsettingscomboboxmodel.cpp 
b/src/ftinspect/models/ttsettingscomboboxmodel.cpp
index c5a3975..4b058ad 100644
--- a/src/ftinspect/models/ttsettingscomboboxmodel.cpp
+++ b/src/ftinspect/models/ttsettingscomboboxmodel.cpp
@@ -190,48 +190,6 @@ 
HintingModeComboBoxModel::setCurrentEngineType(HintingEngineType type)
 }
 
 
-/////////////////////////////////////////////////////////////////////////////
-//
-// SimpleComboBoxModel
-//
-/////////////////////////////////////////////////////////////////////////////
-
-
-SimpleComboBoxModel::SimpleComboBoxModel(QObject* parent)
-: QAbstractListModel(parent)
-{
-}
-
-
-int
-SimpleComboBoxModel::rowCount(const QModelIndex& parent) const
-{
-  return items_.size();
-}
-
-
-QVariant
-SimpleComboBoxModel::data(const QModelIndex& index, int role) const
-{
-  if (role != Qt::DisplayRole)
-    return QVariant {};
-
-  int r = index.row();
-  if (r < 0 || r >= items_.size())
-    return QVariant {};
-  return items_[r].displayName;
-}
-
-
-int
-SimpleComboBoxModel::indexToValue(int index)
-{
-  if (index < 0 || index >= items_.size())
-    return -1;
-  return items_[index].value;
-}
-
-
 /////////////////////////////////////////////////////////////////////////////
 //
 // LCDFilterComboBoxModel
@@ -240,7 +198,7 @@ SimpleComboBoxModel::indexToValue(int index)
 
 
 LCDFilterComboBoxModel::LCDFilterComboBoxModel(QObject* parent)
-: SimpleComboBoxModel(parent)
+: QAbstractListModel(parent)
 {
   items_[LCDFilter_Default] = {
     FT_LCD_FILTER_DEFAULT,
@@ -269,34 +227,34 @@ LCDFilterComboBoxModel::LCDFilterComboBoxModel(QObject* 
parent)
 
 
 AntiAliasingComboBoxModel::AntiAliasingComboBoxModel(QObject* parent)
-: SimpleComboBoxModel(parent)
+: QAbstractListModel(parent)
 {
   items_[AntiAliasing_None] = {
-    FT_LOAD_TARGET_MONO,
+    {FT_LOAD_TARGET_MONO, FT_RENDER_MODE_MONO, false},
     "None"
   };
   items_[AntiAliasing_Normal] = {
-    FT_LOAD_TARGET_NORMAL,
+    {FT_LOAD_TARGET_NORMAL, FT_RENDER_MODE_NORMAL, false},
     "Normal"
   };
   items_[AntiAliasing_Light] = {
-    FT_LOAD_TARGET_LIGHT,
+    {FT_LOAD_TARGET_LIGHT, FT_RENDER_MODE_LIGHT, false},
     "Light"
   };
   items_[AntiAliasing_LCD] = {
-    FT_LOAD_TARGET_LCD,
+    {FT_LOAD_TARGET_LCD, FT_RENDER_MODE_LCD, false},
     "LCD (RGB)"
   };
   items_[AntiAliasing_LCD_BGR] = {
-    FT_LOAD_TARGET_LCD,
+    {FT_LOAD_TARGET_LCD, FT_RENDER_MODE_LCD, true},
     "LCD (BGR)"
   };
   items_[AntiAliasing_LCD_Vertical] = {
-    FT_LOAD_TARGET_LCD_V,
+    {FT_LOAD_TARGET_LCD_V, FT_RENDER_MODE_LCD_V, false},
     "LCD (vert. RGB)"
   };
   items_[AntiAliasing_LCD_Vertical_BGR] = {
-    FT_LOAD_TARGET_LCD_V, // XXX Bug: No difference between RGB and BGR?
+    {FT_LOAD_TARGET_LCD_V, FT_RENDER_MODE_LCD_V, true},
     "LCD (vert. BGR)"
   };
 
@@ -312,7 +270,7 @@ AntiAliasingComboBoxModel::data(const QModelIndex& index,
     if (index.row() == AntiAliasing_Light && !lightAntiAliasingEnabled_)
       return QApplication::palette().color(QPalette::Disabled, 
                                            QPalette::Text);
-  return SimpleComboBoxModel::data(index, role);
+  return SimpleComboBoxModelImpl::data(index, role);
 }
 
 
diff --git a/src/ftinspect/models/ttsettingscomboboxmodel.hpp 
b/src/ftinspect/models/ttsettingscomboboxmodel.hpp
index 9bf1666..a445f1a 100644
--- a/src/ftinspect/models/ttsettingscomboboxmodel.hpp
+++ b/src/ftinspect/models/ttsettingscomboboxmodel.hpp
@@ -71,25 +71,47 @@ public:
 
 
 // A simple key-displayName-value model for QComboBox.
-class SimpleComboBoxModel
-: public QAbstractListModel
+template <class T>
+class SimpleComboBoxModelImpl
 {
-  Q_OBJECT
 public:
   struct ComboBoxItem
   {
-    int value;
+    T value;
     QString displayName;
   };
 
-  explicit SimpleComboBoxModel(QObject* parent);
-  ~SimpleComboBoxModel() override = default;
+  SimpleComboBoxModelImpl() {}
+  virtual ~SimpleComboBoxModelImpl() = default;
 
-  int rowCount(const QModelIndex& parent) const;
-  QVariant data(const QModelIndex& index,
-                int role) const;
+  virtual int
+  rowCount(const QModelIndex& parent) const
+  {
+    return items_.size();
+  }
 
-  int indexToValue(int index);
+
+  virtual QVariant
+  data(const QModelIndex& index,
+                int role) const
+  {
+    if (role != Qt::DisplayRole)
+      return QVariant{};
+
+    int r = index.row();
+    if (r < 0 || r >= items_.size())
+      return QVariant{};
+    return items_[r].displayName;
+  }
+
+
+  virtual T
+  indexToValue(int index)
+  {
+    if (index < 0 || index >= items_.size())
+      return T();
+    return items_[index].value;
+  }
 
 protected:
   QHash<int, ComboBoxItem> items_;
@@ -97,7 +119,8 @@ protected:
 
 
 class LCDFilterComboBoxModel
-: public SimpleComboBoxModel
+: public QAbstractListModel,
+  public SimpleComboBoxModelImpl<int>
 {
   Q_OBJECT
 public:
@@ -108,9 +131,24 @@ public:
     QString displayName;
   };
 
+
   explicit LCDFilterComboBoxModel(QObject* parent);
   virtual ~LCDFilterComboBoxModel() = default;
 
+
+  int rowCount(const QModelIndex& parent) const override
+  {
+    return SimpleComboBoxModelImpl::rowCount(parent);
+  }
+
+
+  QVariant
+  data(const QModelIndex& index,
+       int role) const override
+  {
+    return SimpleComboBoxModelImpl::data(index, role);
+  }
+
 public:
   enum LCDFilter : int
   {
@@ -122,8 +160,18 @@ public:
 };
 
 
+struct AASetting
+{
+  // No default value for braced init - No C++14, what a pain!
+  int loadFlag;
+  int renderMode;
+  bool isBGR;
+};
+
+
 class AntiAliasingComboBoxModel
-: public SimpleComboBoxModel
+: public QAbstractListModel,
+  public SimpleComboBoxModelImpl<AASetting>
 {
   Q_OBJECT
 public:
@@ -136,6 +184,13 @@ public:
                 int role) const;
   Qt::ItemFlags flags(const QModelIndex& index) const;
 
+
+  int rowCount(const QModelIndex& parent) const override
+  {
+    return SimpleComboBoxModelImpl::rowCount(parent);
+  }
+
+
   void setLightAntiAliasingEnabled(bool enabled)
   {
     lightAntiAliasingEnabled_ = enabled;
diff --git a/src/ftinspect/panels/settingpanel.cpp 
b/src/ftinspect/panels/settingpanel.cpp
index 25d5c06..c78af33 100644
--- a/src/ftinspect/panels/settingpanel.cpp
+++ b/src/ftinspect/panels/settingpanel.cpp
@@ -172,8 +172,12 @@ SettingPanel::syncSettings()
   engine_->setLcdFilter(
     static_cast<FT_LcdFilter>(lcdFilterComboboxModel_->indexToValue(
       lcdFilterComboBox_->currentIndex())));
-  engine_->setAntiAliasingTarget(antiAliasingComboBoxModel_->indexToValue(
-    antiAliasingComboBox_->currentIndex()));
+
+  auto aaSettings = antiAliasingComboBoxModel_->indexToValue(
+    antiAliasingComboBox_->currentIndex());
+  engine_->setAntiAliasingTarget(aaSettings.loadFlag);
+  engine_->setRenderMode(aaSettings.renderMode);
+
   engine_->setAntiAliasingEnabled(antiAliasingComboBox_->currentIndex()
     != AntiAliasingComboBoxModel::AntiAliasing_None);
   engine_->setHinting(hintingCheckBox_->isChecked());
@@ -184,6 +188,9 @@ SettingPanel::syncSettings()
   engine_->setShowSegments(segmentDrawingCheckBox_->isChecked());
 
   engine_->setGamma(gammaSlider_->value());
+
+  engine_->setEmbeddedBitmap(embeddedBitmapCheckBox_->isChecked());
+  engine_->setLCDUsesBGR(aaSettings.isBGR);
 }
 
 
@@ -218,6 +225,8 @@ SettingPanel::createConnections()
 
   connect(autoHintingCheckBox_, &QCheckBox::clicked,
           this, &SettingPanel::checkAutoHinting);
+  connect(embeddedBitmapCheckBox_, &QCheckBox::clicked,
+          this, &SettingPanel::repaintNeeded);
 }
 
 
@@ -239,6 +248,7 @@ SettingPanel::createLayout()
   verticalHintingCheckBox_ = new QCheckBox(tr("Vertical Hinting"), this);
   blueZoneHintingCheckBox_ = new QCheckBox(tr("Blue-Zone Hinting"), this);
   segmentDrawingCheckBox_ = new QCheckBox(tr("Segment Drawing"), this);
+  embeddedBitmapCheckBox_ = new QCheckBox(tr("Enable Embedded Bitmap"), this);
 
   antiAliasingLabel_ = new QLabel(tr("Anti-Aliasing"), this);
   antiAliasingLabel_->setAlignment(Qt::AlignRight);
@@ -329,6 +339,7 @@ SettingPanel::createLayout()
   generalTabLayout_->addSpacing(20); // XXX px
   generalTabLayout_->addStretch(1);
   generalTabLayout_->addLayout(gammaLayout_);
+  generalTabLayout_->addWidget(embeddedBitmapCheckBox_);
   generalTabLayout_->addSpacing(20); // XXX px
   generalTabLayout_->addStretch(1);
 
@@ -376,6 +387,7 @@ SettingPanel::setDefaults()
   horizontalHintingCheckBox_->setChecked(true);
   verticalHintingCheckBox_->setChecked(true);
   blueZoneHintingCheckBox_->setChecked(true);
+  embeddedBitmapCheckBox_->setChecked(false);
 
   gammaSlider_->setValue(18); // 1.8
 }
diff --git a/src/ftinspect/panels/settingpanel.hpp 
b/src/ftinspect/panels/settingpanel.hpp
index b27c531..cdfc667 100644
--- a/src/ftinspect/panels/settingpanel.hpp
+++ b/src/ftinspect/panels/settingpanel.hpp
@@ -63,6 +63,7 @@ private:
   QCheckBox* blueZoneHintingCheckBox_;
   QCheckBox* segmentDrawingCheckBox_;
   QCheckBox* autoHintingCheckBox_;
+  QCheckBox* embeddedBitmapCheckBox_;
 
   AntiAliasingComboBoxModel* antiAliasingComboBoxModel_;
   HintingModeComboBoxModel* hintingModeComboBoxModel_;
diff --git a/src/ftinspect/panels/singular.cpp 
b/src/ftinspect/panels/singular.cpp
index db2bc1f..0fb50a6 100644
--- a/src/ftinspect/panels/singular.cpp
+++ b/src/ftinspect/panels/singular.cpp
@@ -87,29 +87,21 @@ SingularTab::drawGlyph()
   }
 
   syncSettings();
-  FT_Outline* outline = engine_->loadOutline(currentGlyphIndex_);
-  if (outline)
+  FT_Glyph glyph = engine_->loadGlyph(currentGlyphIndex_);
+  if (glyph)
   {
     if (showBitmapCheckBox_->isChecked())
     {
-      // XXX support LCD
-      FT_Pixel_Mode pixelMode = FT_PIXEL_MODE_GRAY;
-      if (!engine_->antiAliasingEnabled())
-        pixelMode = FT_PIXEL_MODE_MONO;
-
       currentGlyphBitmapItem_
-        = new GlyphBitmap(outline,
-          engine_->ftLibrary(),
-          pixelMode,
-          graphicsDefault_->monoColorTable,
-          graphicsDefault_->grayColorTable);
+        = new GlyphBitmap(glyph,
+                          engine_);
       glyphScene_->addItem(currentGlyphBitmapItem_);
     }
 
     if (showOutlinesCheckBox_->isChecked())
     {
       currentGlyphOutlineItem_ = new 
GlyphOutline(graphicsDefault_->outlinePen, 
-                                                  outline);
+                                                  glyph);
       glyphScene_->addItem(currentGlyphOutlineItem_);
     }
 
@@ -117,7 +109,7 @@ SingularTab::drawGlyph()
     {
       currentGlyphPointsItem_ = new GlyphPoints(graphicsDefault_->onPen,
                                                 graphicsDefault_->offPen,
-                                                outline);
+                                                glyph);
       glyphScene_->addItem(currentGlyphPointsItem_);
 
       if (showPointNumbersCheckBox_->isChecked())
@@ -125,7 +117,7 @@ SingularTab::drawGlyph()
         currentGlyphPointNumbersItem_
           = new GlyphPointNumbers(graphicsDefault_->onPen,
                                   graphicsDefault_->offPen,
-                                  outline);
+                                  glyph);
         glyphScene_->addItem(currentGlyphPointNumbersItem_);
       }
     }
diff --git a/src/ftinspect/rendering/glyphbitmap.cpp 
b/src/ftinspect/rendering/glyphbitmap.cpp
index 78623a6..5ccc4e7 100644
--- a/src/ftinspect/rendering/glyphbitmap.cpp
+++ b/src/ftinspect/rendering/glyphbitmap.cpp
@@ -6,34 +6,26 @@
 #include "glyphbitmap.hpp"
 
 #include "renderutils.hpp"
+#include "../engine/engine.hpp"
 
 #include <cmath>
 #include <QPainter>
 #include <QStyleOptionGraphicsItem>
+#include <freetype/ftbitmap.h>
 
 
-GlyphBitmap::GlyphBitmap(FT_Outline* outline,
-                         FT_Library lib,
-                         FT_Pixel_Mode pxlMode,
-                         const QVector<QRgb>& monoColorTbl,
-                         const QVector<QRgb>& grayColorTbl)
-: library_(lib),
-  pixelMode_(pxlMode),
-  monoColorTable_(monoColorTbl),
-  grayColorTable_(grayColorTbl)
+GlyphBitmap::GlyphBitmap(FT_Glyph glyph,
+                         Engine* engine)
 {
-  // make a copy of the outline since we are going to manipulate it
-  FT_BBox cbox;
-  transformed_ = cloneOutline(lib, outline);
-  transformOutlineToOrigin(&transformed_, &cbox);
-  boundingRect_.setCoords(cbox.xMin / 64, -cbox.yMax / 64,
-                  cbox.xMax / 64, -cbox.yMin / 64);
+  QRect bRect;
+  image_ = engine->convertBitmapToQImage(glyph, &bRect);
+  boundingRect_ = bRect; // QRectF to QRect
 }
 
 
 GlyphBitmap::~GlyphBitmap()
 {
-  FT_Outline_Done(library_, &transformed_);
+  delete image_;
 }
 
 QRectF
@@ -48,40 +40,9 @@ GlyphBitmap::paint(QPainter* painter,
                    const QStyleOptionGraphicsItem* option,
                    QWidget*)
 {
-  FT_Bitmap bitmap;
-
-  int height = static_cast<int>(ceil(boundingRect_.height()));
-  int width = static_cast<int>(ceil(boundingRect_.width()));
-  QImage::Format format = QImage::Format_Indexed8;
-
-  // XXX cover LCD and color
-  if (pixelMode_ == FT_PIXEL_MODE_MONO)
-    format = QImage::Format_Mono;
-
-  QImage image(QSize(width, height), format);
-
-  if (pixelMode_ == FT_PIXEL_MODE_MONO)
-    image.setColorTable(monoColorTable_);
-  else
-    image.setColorTable(grayColorTable_);
-
-  image.fill(0);
-
-  bitmap.rows = static_cast<unsigned int>(height);
-  bitmap.width = static_cast<unsigned int>(width);
-  bitmap.buffer = image.bits();
-  bitmap.pitch = image.bytesPerLine();
-  bitmap.pixel_mode = pixelMode_;
-
-  FT_Error error = FT_Outline_Get_Bitmap(library_,
-                                         &transformed_,
-                                         &bitmap);
-  if (error)
-  {
-    // XXX error handling
+  if (!image_)
     return;
-  }
-
+  
   // `drawImage' doesn't work as expected:
   // the larger the zoom, the more the pixel rectangle positions
   // deviate from the grid lines
@@ -95,11 +56,11 @@ GlyphBitmap::paint(QPainter* painter,
 
   painter->setPen(Qt::NoPen);
 
-  for (int x = 0; x < image.width(); x++)
-    for (int y = 0; y < image.height(); y++)
+  for (int x = 0; x < image_->width(); x++)
+    for (int y = 0; y < image_->height(); y++)
     {
       // be careful not to lose the alpha channel
-      QRgb p = image.pixel(x, y);
+      QRgb p = image_->pixel(x, y);
       painter->fillRect(QRectF(x + boundingRect_.left() - 1 / lod / 2,
                                y + boundingRect_.top() - 1 / lod / 2,
                                1 + 1 / lod,
@@ -109,7 +70,9 @@ GlyphBitmap::paint(QPainter* painter,
                                qBlue(p),
                                qAlpha(p)));
     }
+    
 #endif
+
 }
 
 
diff --git a/src/ftinspect/rendering/glyphbitmap.hpp 
b/src/ftinspect/rendering/glyphbitmap.hpp
index 79b8d70..4e771ca 100644
--- a/src/ftinspect/rendering/glyphbitmap.hpp
+++ b/src/ftinspect/rendering/glyphbitmap.hpp
@@ -10,18 +10,18 @@
 
 #include <ft2build.h>
 #include <freetype/freetype.h>
+#include <freetype/ftglyph.h>
 #include <freetype/ftoutln.h>
 
 
+class Engine;
+
 class GlyphBitmap
 : public QGraphicsItem
 {
 public:
-  GlyphBitmap(FT_Outline* outline,
-              FT_Library library,
-              FT_Pixel_Mode pixelMode,
-              const QVector<QRgb>& monoColorTable,
-              const QVector<QRgb>& grayColorTable);
+  GlyphBitmap(FT_Glyph glyph,
+              Engine* engine);
   ~GlyphBitmap() override;
   QRectF boundingRect() const override;
   void paint(QPainter* painter,
@@ -29,11 +29,7 @@ public:
              QWidget* widget) override;
 
 private:
-  FT_Outline transformed_;
-  FT_Library library_;
-  unsigned char pixelMode_;
-  const QVector<QRgb>& monoColorTable_;
-  const QVector<QRgb>& grayColorTable_;
+  QImage* image_ = NULL;
   QRectF boundingRect_;
 };
 
diff --git a/src/ftinspect/rendering/glyphoutline.cpp 
b/src/ftinspect/rendering/glyphoutline.cpp
index 4047227..2e13a31 100644
--- a/src/ftinspect/rendering/glyphoutline.cpp
+++ b/src/ftinspect/rendering/glyphoutline.cpp
@@ -88,10 +88,16 @@ static FT_Outline_Funcs outlineFuncs =
 
 
 GlyphOutline::GlyphOutline(const QPen& pen,
-                           FT_Outline* outline)
-: outlinePen_(pen),
-  outline_(outline)
+                           FT_Glyph glyph)
+: outlinePen_(pen)
 {
+  if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
+  {
+    outline_ = NULL;
+    return;
+  }
+  outline_ = &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline;
+
   FT_BBox cbox;
 
   qreal halfPenWidth = outlinePen_.widthF();
@@ -117,6 +123,8 @@ GlyphOutline::paint(QPainter* painter,
                     const QStyleOptionGraphicsItem*,
                     QWidget*)
 {
+  if (!outline_)
+    return;
   painter->setPen(outlinePen_);
 
   QPainterPath path;
diff --git a/src/ftinspect/rendering/glyphoutline.hpp 
b/src/ftinspect/rendering/glyphoutline.hpp
index ec7cf61..37c53a3 100644
--- a/src/ftinspect/rendering/glyphoutline.hpp
+++ b/src/ftinspect/rendering/glyphoutline.hpp
@@ -10,6 +10,7 @@
 
 #include <ft2build.h>
 #include <freetype/freetype.h>
+#include <freetype/ftglyph.h>
 #include <freetype/ftoutln.h>
 
 
@@ -18,7 +19,7 @@ class GlyphOutline
 {
 public:
   GlyphOutline(const QPen& pen,
-               FT_Outline* outline);
+               FT_Glyph glyph);
   QRectF boundingRect() const override;
   void paint(QPainter* painter,
              const QStyleOptionGraphicsItem* option,
diff --git a/src/ftinspect/rendering/glyphpointnumbers.cpp 
b/src/ftinspect/rendering/glyphpointnumbers.cpp
index bddee89..f52ed9d 100644
--- a/src/ftinspect/rendering/glyphpointnumbers.cpp
+++ b/src/ftinspect/rendering/glyphpointnumbers.cpp
@@ -12,11 +12,17 @@
 
 GlyphPointNumbers::GlyphPointNumbers(const QPen& onP,
                                      const QPen& offP,
-                                     FT_Outline* outln)
+                                     FT_Glyph glyph)
 : onPen_(onP),
-  offPen_(offP),
-  outline_(outln)
+  offPen_(offP)
 {
+  if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
+  {
+    outline_ = NULL;
+    return;
+  }
+  outline_ = &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline;
+
   FT_BBox cbox;
 
   FT_Outline_Get_CBox(outline_, &cbox);
@@ -41,6 +47,8 @@ GlyphPointNumbers::paint(QPainter* painter,
                          const QStyleOptionGraphicsItem* option,
                          QWidget*)
 {
+  if (!outline_)
+    return;
   const qreal lod = option->levelOfDetailFromTransform(
                               painter->worldTransform());
 
diff --git a/src/ftinspect/rendering/glyphpointnumbers.hpp 
b/src/ftinspect/rendering/glyphpointnumbers.hpp
index 3002647..ded1ce1 100644
--- a/src/ftinspect/rendering/glyphpointnumbers.hpp
+++ b/src/ftinspect/rendering/glyphpointnumbers.hpp
@@ -10,6 +10,7 @@
 
 #include <ft2build.h>
 #include <freetype/freetype.h>
+#include <freetype/ftglyph.h>
 #include <freetype/ftoutln.h>
 
 
@@ -19,7 +20,7 @@ class GlyphPointNumbers
 public:
   GlyphPointNumbers(const QPen& onPen,
                     const QPen& offPen,
-                    FT_Outline* outline);
+                    FT_Glyph glyph);
   QRectF boundingRect() const override;
   void paint(QPainter* painter,
              const QStyleOptionGraphicsItem* option,
diff --git a/src/ftinspect/rendering/glyphpoints.cpp 
b/src/ftinspect/rendering/glyphpoints.cpp
index 08960e6..4b35670 100644
--- a/src/ftinspect/rendering/glyphpoints.cpp
+++ b/src/ftinspect/rendering/glyphpoints.cpp
@@ -11,11 +11,17 @@
 
 GlyphPoints::GlyphPoints(const QPen& onP,
                          const QPen& offP,
-                         FT_Outline* outln)
+                         FT_Glyph glyph)
 : onPen_(onP),
-  offPen_(offP),
-  outline_(outln)
+  offPen_(offP)
 {
+  if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
+  {
+    outline_ = NULL;
+    return;
+  }
+  outline_ = &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline;
+
   FT_BBox cbox;
 
   qreal halfPenWidth = qMax(onPen_.widthF(), offPen_.widthF()) / 2;
@@ -41,6 +47,9 @@ GlyphPoints::paint(QPainter* painter,
                    const QStyleOptionGraphicsItem* option,
                    QWidget*)
 {
+  if (!outline_)
+    return;
+
   const qreal lod = option->levelOfDetailFromTransform(
                               painter->worldTransform());
 
diff --git a/src/ftinspect/rendering/glyphpoints.hpp 
b/src/ftinspect/rendering/glyphpoints.hpp
index be3b5a4..d0f5d66 100644
--- a/src/ftinspect/rendering/glyphpoints.hpp
+++ b/src/ftinspect/rendering/glyphpoints.hpp
@@ -10,6 +10,7 @@
 
 #include <ft2build.h>
 #include <freetype/freetype.h>
+#include <freetype/ftglyph.h>
 #include <freetype/ftoutln.h>
 
 
@@ -19,7 +20,7 @@ class GlyphPoints
 public:
   GlyphPoints(const QPen& onPen,
               const QPen& offPen,
-              FT_Outline* outline);
+              FT_Glyph glyph);
   QRectF boundingRect() const override;
   void paint(QPainter* painter,
              const QStyleOptionGraphicsItem* option,
diff --git a/src/ftinspect/rendering/renderutils.cpp 
b/src/ftinspect/rendering/renderutils.cpp
index 260f499..e8316cd 100644
--- a/src/ftinspect/rendering/renderutils.cpp
+++ b/src/ftinspect/rendering/renderutils.cpp
@@ -28,6 +28,19 @@ cloneGlyph(FT_Glyph src)
 void
 transformOutlineToOrigin(FT_Outline* outline,
                          FT_BBox* outControlBox)
+{
+  FT_Pos x, y;
+  computeTransformationToOrigin(outline,
+                                &x, &y,
+                                outControlBox);
+  FT_Outline_Translate(outline, x, y);
+}
+
+
+void computeTransformationToOrigin(FT_Outline* outline,
+                                   FT_Pos* outXOffset,
+                                   FT_Pos* outYOffset,
+                                   FT_BBox* outControlBox)
 {
   FT_BBox cbox;
   FT_Outline_Get_CBox(outline, &cbox);
@@ -37,8 +50,10 @@ transformOutlineToOrigin(FT_Outline* outline,
   cbox.xMax = (cbox.xMax + 63) & ~63;
   cbox.yMax = (cbox.yMax + 63) & ~63;
   // we shift the outline to the origin for rendering later on
-  FT_Outline_Translate(outline, -cbox.xMin, -cbox.yMin);
-
+  if (outXOffset)
+    *outXOffset = -cbox.xMin;
+  if (outYOffset)
+    *outYOffset = -cbox.yMin;
   if (outControlBox)
     *outControlBox = cbox;
 }
diff --git a/src/ftinspect/rendering/renderutils.hpp 
b/src/ftinspect/rendering/renderutils.hpp
index 55175fa..3d284b9 100644
--- a/src/ftinspect/rendering/renderutils.hpp
+++ b/src/ftinspect/rendering/renderutils.hpp
@@ -14,5 +14,10 @@ FT_Glyph cloneGlyph(FT_Glyph src);
 void transformOutlineToOrigin(FT_Outline* outline,
                               FT_BBox* outControlBox);
 
+void computeTransformationToOrigin(FT_Outline* outline,
+                                   FT_Pos* outXOffset,
+                                   FT_Pos* outYOffset,
+                                   FT_BBox* outControlBox);
+
 
 // end of renderutils.hpp



reply via email to

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