[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[freetype2-demos] master 1d3d862 15/41: [ftinspect] Support color layers
From: |
Werner Lemberg |
Subject: |
[freetype2-demos] master 1d3d862 15/41: [ftinspect] Support color layers. |
Date: |
Mon, 3 Oct 2022 11:27:01 -0400 (EDT) |
branch: master
commit 1d3d8628b85edb85bc8c6435f57248b96baac039
Author: Charlie Jiang <w@chariri.moe>
Commit: Werner Lemberg <wl@gnu.org>
[ftinspect] Support color layers.
* src/ftinspect/engine/rendering.cpp:
Add implementation of `tryDirectRenderColorLayers`.
* src/ftinspect/engine/engine.cpp, src/ftinspect/engine/engine.hpp:
Implement `loadPaletteInfos` and `loadPalette`.
Add `currentFontHasColorLayers` and a group of getters/setters supporting
color layer rendering.
Also reorder fields as the number of fields grows.
* src/ftinspect/panels/settingpanel.cpp,
src/ftinspect/panels/settingpanel.hpp:
Implement `populatePalettes` and reorder functions.
Fix `checkPalette` about combo box enabling state and reset the cache when
the palette settings change.
Uncomment functional code.
* src/ftinspect/engine/paletteinfo.cpp,
src/ftinspect/engine/paletteinfo.hpp: New files adding `PaletteInfo`.
Retrieving palette names using SFNT name tables is not supported yet.
* src/ftinspect/panels/singular.cpp:
Call `Engine::loadPalette` when drawing.
* src/ftinspect/CMakeLists.txt, src/ftinspect/meson.build: Updated.
---
src/ftinspect/CMakeLists.txt | 1 +
src/ftinspect/engine/engine.cpp | 54 +++++++++++++++
src/ftinspect/engine/engine.hpp | 35 ++++++++--
src/ftinspect/engine/paletteinfo.cpp | 33 +++++++++
src/ftinspect/engine/paletteinfo.hpp | 24 +++++++
src/ftinspect/engine/rendering.cpp | 126 +++++++++++++++++++++++++++++++++-
src/ftinspect/meson.build | 1 +
src/ftinspect/panels/settingpanel.cpp | 70 ++++++++++++++-----
src/ftinspect/panels/settingpanel.hpp | 3 +-
src/ftinspect/panels/singular.cpp | 2 +-
10 files changed, 324 insertions(+), 25 deletions(-)
diff --git a/src/ftinspect/CMakeLists.txt b/src/ftinspect/CMakeLists.txt
index 40e2903..a8eaea6 100644
--- a/src/ftinspect/CMakeLists.txt
+++ b/src/ftinspect/CMakeLists.txt
@@ -23,6 +23,7 @@ add_executable(ftinspect
"engine/engine.cpp"
"engine/fontfilemanager.cpp"
"engine/rendering.cpp"
+ "engine/paletteinfo.cpp"
"glyphcomponents/glyphbitmap.cpp"
"glyphcomponents/glyphoutline.cpp"
diff --git a/src/ftinspect/engine/engine.cpp b/src/ftinspect/engine/engine.cpp
index 85e3e0b..f46b075 100644
--- a/src/ftinspect/engine/engine.cpp
+++ b/src/ftinspect/engine/engine.cpp
@@ -268,6 +268,7 @@ Engine::loadFont(int fontIndex,
{
int numGlyphs = -1;
fontType_ = FontType_Other;
+ palette_ = NULL;
update();
@@ -326,6 +327,7 @@ Engine::loadFont(int fontIndex,
ftSize_ = NULL;
curFamilyName_ = QString();
curStyleName_ = QString();
+ curPaletteInfos_.clear();
}
else
{
@@ -341,6 +343,7 @@ Engine::loadFont(int fontIndex,
fontType_ = FontType_TrueType;
else
fontType_ = FontType_Other;
+ loadPaletteInfos();
}
curNumGlyphs_ = numGlyphs;
@@ -352,6 +355,7 @@ void
Engine::reloadFont()
{
update();
+ palette_ = NULL;
if (!scaler_.face_id)
return;
imageType_.face_id = scaler_.face_id;
@@ -367,6 +371,25 @@ Engine::reloadFont()
}
+void
+Engine::loadPalette()
+{
+ palette_ = NULL;
+ if (paletteData_.num_palettes == 0
+ || paletteIndex_ < 0
+ || paletteData_.num_palettes <= paletteIndex_)
+ return;
+
+ if (!ftSize_)
+ return;
+
+ FT_Palette_Select(ftSize_->face,
+ static_cast<FT_UShort>(paletteIndex_),
+ &palette_);
+ // XXX error handling
+}
+
+
void
Engine::removeFont(int fontIndex, bool closeFile)
{
@@ -413,6 +436,15 @@ Engine::currentFontHasEmbeddedBitmap()
}
+bool
+Engine::currentFontHasColorLayers()
+{
+ if (!ftFallbackFace_)
+ return false;
+ return FT_HAS_COLOR(ftFallbackFace_);
+}
+
+
std::vector<int>
Engine::currentFontFixedSizes()
{
@@ -676,6 +708,7 @@ Engine::resetCache()
FTC_Manager_Reset(cacheManager_);
ftFallbackFace_ = NULL;
ftSize_ = NULL;
+ palette_ = NULL;
}
@@ -778,4 +811,25 @@ Engine::queryEngine()
}
}
+
+void
+Engine::loadPaletteInfos()
+{
+ curPaletteInfos_.clear();
+
+ if (FT_Palette_Data_Get(ftFallbackFace_, &paletteData_))
+ {
+ // XXX Error handling
+ paletteData_.num_palettes = 0;
+ return;
+ }
+
+ // size never exceeds max val of ushort.
+ curPaletteInfos_.reserve(paletteData_.num_palettes);
+ for (int i = 0; i < paletteData_.num_palettes; ++i)
+ curPaletteInfos_.emplace_back(ftFallbackFace_, paletteData_, i, nullptr);
+ // no `NULL` here - we need `std::nullptr_t`
+}
+
+
// end of engine.cpp
diff --git a/src/ftinspect/engine/engine.hpp b/src/ftinspect/engine/engine.hpp
index 6fe142a..333bfa0 100644
--- a/src/ftinspect/engine/engine.hpp
+++ b/src/ftinspect/engine/engine.hpp
@@ -7,6 +7,7 @@
#include "fontfilemanager.hpp"
+#include "paletteinfo.hpp"
#include "rendering.hpp"
#include <memory>
@@ -19,6 +20,7 @@
#include <freetype/ftoutln.h>
#include <freetype/ftcache.h>
#include <freetype/ftlcdfil.h>
+#include <freetype/ftcolor.h>
// This structure maps the (font, face, instance) index triplet to abstract
@@ -94,6 +96,8 @@ public:
//////// Getters
FT_Library ftLibrary() const { return library_; }
+ FTC_Manager cacheManager() { return cacheManager_; }
+ FTC_ImageCache imageCacheManager() { return imageCache_; }
FontFileManager& fontFileManager() { return fontFileManager_; }
EngineDefaultValues& engineDefaults() { return engineDefaults_; }
RenderingEngine* renderingEngine() { return renderingEngine_.get(); }
@@ -101,13 +105,20 @@ public:
int numberOfOpenedFonts();
// (for current fonts)
+ FT_Face currentFallbackFtFace() { return ftFallbackFace_; }
+ FT_Size currentFtSize() { return ftSize_; }
bool renderReady(); // Can we render bitmaps? (implys `fontValid`)
bool fontValid(); // Is the current font valid (valid font may be unavailable
// to render, such as non-scalable font with invalid sizes)
+
int currentFontType() const { return fontType_; }
const QString& currentFamilyName() { return curFamilyName_; }
const QString& currentStyleName() { return curStyleName_; }
int currentFontNumberOfGlyphs() { return curNumGlyphs_; }
+
+ std::vector<PaletteInfo>& currentFontPalettes() { return curPaletteInfos_; }
+ FT_Color* currentPalette() { return palette_; }
+ FT_Palette_Data& currentFontPaletteData() { return paletteData_; }
QString glyphName(int glyphIndex);
long numberOfFaces(int fontIndex);
@@ -118,18 +129,23 @@ public:
bool currentFontTricky();
bool currentFontBitmapOnly();
bool currentFontHasEmbeddedBitmap();
+ bool currentFontHasColorLayers();
std::vector<int> currentFontFixedSizes();
// (settings)
int dpi() { return dpi_; }
+ FTC_ImageType imageType() { return &imageType_; }
bool antiAliasingEnabled() { return antiAliasingEnabled_; }
bool embeddedBitmapEnabled() { return embeddedBitmap_; }
+ bool useColorLayer() { return useColorLayer_; }
+ int paletteIndex() { return paletteIndex_; }
FT_Render_Mode
renderMode()
{
return static_cast<FT_Render_Mode>(renderMode_);
}
+
//////// Setters (direct or indirect)
void setDPI(int d) { dpi_ = d; }
@@ -154,7 +170,8 @@ public:
void setRenderMode(int mode) { renderMode_ = mode; }
void setAntiAliasingEnabled(bool enabled) { antiAliasingEnabled_ = enabled; }
void setEmbeddedBitmapEnabled(bool enabled) { embeddedBitmap_ = enabled; }
-
+ void setUseColorLayer(bool colorLayer) { useColorLayer_ = colorLayer; }
+ void setPaletteIndex(int index) { paletteIndex_ = index; }
// (settings without backing fields)
// Note: These 3 functions now takes actual mode/version from FreeType,
@@ -179,16 +196,22 @@ private:
FontFileManager fontFileManager_;
+ // font info
int curFontIndex_ = -1;
QString curFamilyName_;
QString curStyleName_;
int curNumGlyphs_ = -1;
+ std::vector<PaletteInfo> curPaletteInfos_;
+ int fontType_;
+ // basic objects
FT_Library library_;
FTC_Manager cacheManager_;
FTC_ImageCache imageCache_;
FTC_SBitCache sbitsCache_;
+ EngineDefaultValues engineDefaults_;
+ // settings
FTC_ScalerRec scaler_ = {};
FTC_ImageTypeRec imageType_; // for `loadGlyphWithoutUpdate`
// Sometimes the font may be valid (i.e. a face object can be retrieved), but
@@ -196,10 +219,8 @@ private:
// Therefore, we use a fallback face for all non-rendering work.
FT_Face ftFallbackFace_; // Never perform rendering or write to this!
FT_Size ftSize_;
-
- EngineDefaultValues engineDefaults_;
-
- int fontType_;
+ FT_Palette_Data paletteData_ = {};
+ FT_Color* palette_ = NULL;
bool antiAliasingEnabled_ = true;
bool usingPixelSize_ = false;
@@ -214,6 +235,8 @@ private:
bool doBlueZoneHinting_;
bool showSegments_;
bool embeddedBitmap_;
+ bool useColorLayer_;
+ int paletteIndex_ = -1;
int antiAliasingTarget_;
int renderMode_;
@@ -222,6 +245,8 @@ private:
std::unique_ptr<RenderingEngine> renderingEngine_;
void queryEngine();
+ void loadPaletteInfos();
+
// Safe to put the impl to the cpp.
template <class Func>
void withFace(FaceID id, Func func);
diff --git a/src/ftinspect/engine/paletteinfo.cpp
b/src/ftinspect/engine/paletteinfo.cpp
new file mode 100644
index 0000000..7abd2ae
--- /dev/null
+++ b/src/ftinspect/engine/paletteinfo.cpp
@@ -0,0 +1,33 @@
+// paletteinfo.cpp
+
+// Copyright (C) 2022 by Charlie Jiang.
+
+#include "paletteinfo.hpp"
+
+//#include "fontinfo.hpp"
+
+PaletteInfo::PaletteInfo(FT_Face face,
+ FT_Palette_Data& data,
+ int index,
+ std::vector<SFNTName> const* sfntNames)
+: index(index)
+{
+ if (sfntNames && data.palette_name_ids)
+ {
+ auto id = data.palette_name_ids[index];
+ name = "(unsupported)";
+ //for (auto& obj : *sfntNames)
+ //{
+ // if (obj.nameID == id && obj.strValid)
+ // {
+ // name = obj.str;
+ // break;
+ // }
+ //}
+ }
+ else
+ name = "(unnamed)";
+}
+
+
+// end of paletteinfo.cpp
diff --git a/src/ftinspect/engine/paletteinfo.hpp
b/src/ftinspect/engine/paletteinfo.hpp
new file mode 100644
index 0000000..8d66df7
--- /dev/null
+++ b/src/ftinspect/engine/paletteinfo.hpp
@@ -0,0 +1,24 @@
+// paletteinfo.hpp
+
+// Copyright (C) 2022 by Charlie Jiang.
+
+#pragma once
+
+#include <vector>
+#include <QString>
+
+#include <freetype/freetype.h>
+#include <freetype/ftcolor.h>
+
+struct SFNTName;
+struct PaletteInfo
+{
+ int index;
+ QString name;
+
+ PaletteInfo(FT_Face face, FT_Palette_Data& data, int index,
+ std::vector<SFNTName> const* sfntNames);
+};
+
+
+// end of paletteinfo.hpp
diff --git a/src/ftinspect/engine/rendering.cpp
b/src/ftinspect/engine/rendering.cpp
index 7c7e8c7..76f5eae 100644
--- a/src/ftinspect/engine/rendering.cpp
+++ b/src/ftinspect/engine/rendering.cpp
@@ -304,7 +304,131 @@ RenderingEngine::tryDirectRenderColorLayers(int
glyphIndex,
QRect* outRect,
bool inverseRectY)
{
- return NULL; // TODO: impl
+ auto& paletteData = engine_->currentFontPaletteData();
+ auto paletteIndex = engine_->paletteIndex();
+ auto palette = engine_->currentPalette();
+ if (palette == NULL
+ || !engine_->useColorLayer()
+ || paletteIndex >= paletteData.num_palettes)
+ return NULL;
+
+ FT_LayerIterator iter = {};
+
+ FT_UInt layerGlyphIdx = 0;
+ FT_UInt layerColorIdx = 0;
+
+ bool next = FT_Get_Color_Glyph_Layer(engine_->currentFtSize()->face,
+ glyphIndex,
+ &layerGlyphIdx,
+ &layerColorIdx,
+ &iter);
+ if (!next)
+ return NULL;
+
+ // temporarily change lf
+ auto imageType = engine_->imageType();
+ auto oldLoadFlags = imageType->flags;
+ auto loadFlags = oldLoadFlags;
+ loadFlags &= ~FT_LOAD_COLOR;
+ loadFlags |= FT_LOAD_RENDER;
+
+ loadFlags &= ~FT_LOAD_TARGET_(0xF);
+ loadFlags |= FT_LOAD_TARGET_NORMAL;
+ imageType->flags = loadFlags;
+
+ FT_Bitmap bitmap = {};
+ FT_Bitmap_Init(&bitmap);
+
+ FT_Vector bitmapOffset = {};
+ bool failed = false;
+
+ do
+ {
+ FT_Vector slotOffset;
+ FT_Glyph glyph;
+ if (FTC_ImageCache_Lookup(engine_->imageCacheManager(),
+ imageType,
+ layerGlyphIdx,
+ &glyph,
+ NULL))
+ {
+ // XXX Error handling
+ failed = true;
+ break;
+ }
+
+ if (glyph->format != FT_GLYPH_FORMAT_BITMAP)
+ continue;
+
+ auto bitmapGlyph = reinterpret_cast<FT_BitmapGlyph>(glyph);
+ slotOffset.x = bitmapGlyph->left << 6;
+ slotOffset.y = bitmapGlyph->top << 6;
+
+ FT_Color color = {};
+
+ if (layerColorIdx == 0xFFFF)
+ {
+ // TODO: FT_Palette_Get_Foreground_Color: #1134
+ if (paletteData.palette_flags
+ && (paletteData.palette_flags[paletteIndex]
+ & FT_PALETTE_FOR_DARK_BACKGROUND))
+ {
+ /* white opaque */
+ color.blue = 0xFF;
+ color.green = 0xFF;
+ color.red = 0xFF;
+ color.alpha = 0xFF;
+ }
+ else
+ {
+ /* black opaque */
+ color.blue = 0x00;
+ color.green = 0x00;
+ color.red = 0x00;
+ color.alpha = 0xFF;
+ }
+ }
+ else if (layerColorIdx < paletteData.num_palette_entries)
+ color = palette[layerColorIdx];
+ else
+ continue;
+
+ if (FT_Bitmap_Blend(engine_->ftLibrary(),
+ &bitmapGlyph->bitmap, slotOffset,
+ &bitmap, &bitmapOffset,
+ color))
+ {
+ // XXX error
+ failed = true;
+ break;
+ }
+ } while (FT_Get_Color_Glyph_Layer(engine_->currentFtSize()->face,
+ glyphIndex,
+ &layerGlyphIdx,
+ &layerColorIdx,
+ &iter));
+
+ imageType->flags = oldLoadFlags;
+ if (failed)
+ {
+ FT_Bitmap_Done(engine_->ftLibrary(), &bitmap);
+ return NULL;
+ }
+
+ auto img = convertBitmapToQImage(&bitmap);
+ if (outRect)
+ {
+ outRect->moveLeft(static_cast<int>(bitmapOffset.x >> 6));
+ if (inverseRectY)
+ outRect->moveTop(static_cast<int>(-bitmapOffset.y >> 6));
+ else
+ outRect->moveTop(static_cast<int>(bitmapOffset.y >> 6));
+ outRect->setSize(img->size());
+ }
+
+ FT_Bitmap_Done(engine_->ftLibrary(), &bitmap);
+
+ return img;
}
diff --git a/src/ftinspect/meson.build b/src/ftinspect/meson.build
index 02f1eed..05c5854 100644
--- a/src/ftinspect/meson.build
+++ b/src/ftinspect/meson.build
@@ -24,6 +24,7 @@ if qt5_dep.found()
'engine/engine.cpp',
'engine/fontfilemanager.cpp',
'engine/rendering.cpp',
+ 'engine/paletteinfo.cpp',
'glyphcomponents/glyphbitmap.cpp',
'glyphcomponents/glyphoutline.cpp',
diff --git a/src/ftinspect/panels/settingpanel.cpp
b/src/ftinspect/panels/settingpanel.cpp
index 07e4572..f07691c 100644
--- a/src/ftinspect/panels/settingpanel.cpp
+++ b/src/ftinspect/panels/settingpanel.cpp
@@ -49,13 +49,6 @@ SettingPanel::lsbRsbDeltaEnabled()
}
-void
-SettingPanel::populatePalettes()
-{
- // TODO: Impl
-}
-
-
void
SettingPanel::checkAllSettings()
{
@@ -193,8 +186,10 @@ SettingPanel::checkAntiAliasing()
void
SettingPanel::checkPalette()
{
- paletteComboBox_->setEnabled(colorLayerCheckBox_->isChecked());
- emit repaintNeeded();
+ paletteComboBox_->setEnabled(colorLayerCheckBox_->isChecked()
+ && paletteComboBox_->count() > 0);
+ engine_->resetCache();
+ emit fontReloadNeeded();
}
@@ -267,6 +262,47 @@ SettingPanel::resetColorBlocks()
}
+void
+SettingPanel::populatePalettes()
+{
+ auto needToReload = false;
+ auto& newPalettes = engine_->currentFontPalettes();
+ auto newSize = static_cast<int>(newPalettes.size()); // this never exceeds!
+ if (newSize != paletteComboBox_->count())
+ needToReload = true;
+ else
+ for (int i = 0; i < newSize; ++i)
+ {
+ auto oldNameVariant = paletteComboBox_->itemData(i);
+ if (!oldNameVariant.canConvert<QString>())
+ {
+ needToReload = true;
+ break;
+ }
+ if (oldNameVariant.toString() != newPalettes[i].name)
+ {
+ needToReload = true;
+ break;
+ }
+ }
+ if (!needToReload)
+ return;
+
+ {
+ QSignalBlocker blocker(paletteComboBox_);
+ paletteComboBox_->clear();
+ for (int i = 0; i < newSize; ++i)
+ paletteComboBox_->addItem(
+ QString("%1: %2")
+ .arg(i)
+ .arg(newPalettes[i].name),
+ newPalettes[i].name);
+ }
+
+ emit fontReloadNeeded();
+}
+
+
void
SettingPanel::onFontChanged()
{
@@ -296,10 +332,12 @@ SettingPanel::onFontChanged()
checkHinting();
engine_->reloadFont();
- //auto hasColor = engine_->currentFontHasColorLayers();
- //colorLayerCheckBox_->setEnabled(hasColor);
- //if (!hasColor)
- // colorLayerCheckBox_->setChecked(false);
+ auto hasColor = engine_->currentFontHasColorLayers();
+ colorLayerCheckBox_->setEnabled(hasColor);
+ if (!hasColor)
+ colorLayerCheckBox_->setChecked(false);
+ paletteComboBox_->setEnabled(colorLayerCheckBox_->isChecked()
+ && paletteComboBox_->count() > 0);
populatePalettes();
//mmgxPanel_->reloadFont();
blockSignals(blockState);
@@ -341,9 +379,9 @@ SettingPanel::applySettings()
engine_->renderingEngine()->setGamma(gammaSlider_->value() / 10.0);
engine_->setEmbeddedBitmapEnabled(embeddedBitmapCheckBox_->isChecked());
- //engine_->setPaletteIndex(paletteComboBox_->currentIndex());
+ engine_->setPaletteIndex(paletteComboBox_->currentIndex());
- //engine_->setUseColorLayer(colorLayerCheckBox_->isChecked());
+ engine_->setUseColorLayer(colorLayerCheckBox_->isChecked());
//engine_->setLCDUsesBGR(aaSettings.isBGR);
//engine_->setLCDSubPixelPositioning(
// antiAliasingComboBox_->currentIndex()
@@ -593,7 +631,7 @@ SettingPanel::createConnections()
this, &SettingPanel::repaintNeeded);
connect(paletteComboBox_,
QOverload<int>::of(&QComboBox::currentIndexChanged),
- this, &SettingPanel::repaintNeeded);
+ this, &SettingPanel::checkPalette);
connect(gammaSlider_, &QSlider::valueChanged,
this, &SettingPanel::updateGamma);
diff --git a/src/ftinspect/panels/settingpanel.hpp
b/src/ftinspect/panels/settingpanel.hpp
index 7f1d5e3..73c309a 100644
--- a/src/ftinspect/panels/settingpanel.hpp
+++ b/src/ftinspect/panels/settingpanel.hpp
@@ -111,8 +111,6 @@ private:
//////// Other funcs
- void populatePalettes();
-
void checkAllSettings();
void checkHinting();
void checkHintingMode();
@@ -125,6 +123,7 @@ private:
void openForegroundPicker();
void updateGamma();
void resetColorBlocks();
+ void populatePalettes();
};
diff --git a/src/ftinspect/panels/singular.cpp
b/src/ftinspect/panels/singular.cpp
index 60ffef6..14dbae5 100644
--- a/src/ftinspect/panels/singular.cpp
+++ b/src/ftinspect/panels/singular.cpp
@@ -90,8 +90,8 @@ SingularTab::drawGlyph()
glyphView_->setBackgroundBrush(
QColor(engine_->renderingEngine()->background()));
-
applySettings();
+ engine_->loadPalette();
FT_Glyph glyph = engine_->loadGlyph(currentGlyphIndex_);
if (glyph)
{
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [freetype2-demos] master 1d3d862 15/41: [ftinspect] Support color layers.,
Werner Lemberg <=