[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[freetype2-demos] gsoc-2022-chariri-2 4b0f225 28/30: [ftinspect] Add Fan
From: |
Werner Lemberg |
Subject: |
[freetype2-demos] gsoc-2022-chariri-2 4b0f225 28/30: [ftinspect] Add Fancy submode to "Continuous View" |
Date: |
Mon, 11 Jul 2022 07:17:41 -0400 (EDT) |
branch: gsoc-2022-chariri-2
commit 4b0f2251869f6f3a199cce847883808caf9dc478
Author: Charlie Jiang <w@chariri.moe>
Commit: Charlie Jiang <w@chariri.moe>
[ftinspect] Add Fancy submode to "Continuous View"
Fancy mode adds slanting and hori./vert. emboldening to the glyph.
`GlyphContinuous::paintChar` is broken down to better support additional
operations during rendering. Add proper cloning so the glyph and the
outline which are stored in the `GlyphContinuous` class can be safely
modified.
* src/ftinspect/rendering/glyphcontinuous.cpp,
src/ftinspect/rendering/glyphcontinuous.hpp: As described, refactored and
supported Fancy mode.
* src/ftinspect/rendering/glyphbitmap.cpp: Edited to match the new
`renderutils.cpp`.
* src/ftinspect/rendering/renderutils.cpp,
src/ftinspect/rendering/renderutils.hpp: Broken down
`transformOutlineToOrigin`, add `cloneOutline` and `cloneGlyph`.
* src/ftinspect/panels/continuous.cpp, src/ftinspect/panels/continuous.hpp:
Add necessary GUI components and data passing to support fancy mode.
---
src/ftinspect/panels/continuous.cpp | 88 +++++++++++++++-
src/ftinspect/panels/continuous.hpp | 14 +++
src/ftinspect/rendering/glyphbitmap.cpp | 3 +-
src/ftinspect/rendering/glyphcontinuous.cpp | 158 ++++++++++++++++++++++++----
src/ftinspect/rendering/glyphcontinuous.hpp | 30 +++++-
src/ftinspect/rendering/renderutils.cpp | 31 ++++--
src/ftinspect/rendering/renderutils.hpp | 9 +-
7 files changed, 290 insertions(+), 43 deletions(-)
diff --git a/src/ftinspect/panels/continuous.cpp
b/src/ftinspect/panels/continuous.cpp
index c296530..b3c955a 100644
--- a/src/ftinspect/panels/continuous.cpp
+++ b/src/ftinspect/panels/continuous.cpp
@@ -130,6 +130,10 @@ ContinuousTab::updateFromCurrentSubTab()
canvas_->setBeginIndex(allGlyphsTab_->glyphBeginindex());
canvas_->setLimitIndex(allGlyphsTab_->glyphLimitIndex());
canvas_->setCharMapIndex(allGlyphsTab_->charMapIndex());
+
+ canvas_->setFancyParams(allGlyphsTab_->xEmboldening(),
+ allGlyphsTab_->yEmboldening(),
+ allGlyphsTab_->slanting());
break;
}
}
@@ -143,6 +147,8 @@ ContinousAllGlyphsTab::ContinousAllGlyphsTab(QWidget*
parent)
QVector<CharMapInfo> tempCharMaps;
setCharMaps(tempCharMaps); // pass in an empty one
+ checkSubMode();
+ setDefaults();
createConnections();
}
@@ -169,6 +175,27 @@ ContinousAllGlyphsTab::subMode()
}
+double
+ContinousAllGlyphsTab::xEmboldening()
+{
+ return xEmboldeningSpinBox_->value();
+}
+
+
+double
+ContinousAllGlyphsTab::yEmboldening()
+{
+ return yEmboldeningSpinBox_->value();
+}
+
+
+double
+ContinousAllGlyphsTab::slanting()
+{
+ return slantSpinBox_->value();
+}
+
+
int
ContinousAllGlyphsTab::charMapIndex()
{
@@ -263,6 +290,18 @@ ContinousAllGlyphsTab::updateLimitIndex()
}
+void
+ContinousAllGlyphsTab::checkSubMode()
+{
+ auto isFancy = subMode() == GlyphContinuous::AG_Fancy;
+ xEmboldeningSpinBox_->setEnabled(isFancy);
+ yEmboldeningSpinBox_->setEnabled(isFancy);
+ slantSpinBox_->setEnabled(isFancy);
+
+ emit changed();
+}
+
+
void
ContinousAllGlyphsTab::createLayout()
{
@@ -276,13 +315,31 @@ ContinousAllGlyphsTab::createLayout()
// Note: in sync with the enum!!
modeSelector_->insertItem(GlyphContinuous::AG_AllGlyphs, tr("All Glyphs"));
- modeSelector_->insertItem(GlyphContinuous::AG_Fancy, tr("Fancy"));
+ modeSelector_->insertItem(GlyphContinuous::AG_Fancy,
+ tr("Fancy (Embolding & Slanting)"));
modeSelector_->insertItem(GlyphContinuous::AG_Stroked, tr("Stroked"));
modeSelector_->insertItem(GlyphContinuous::AG_Waterfall, tr("Waterfall"));
modeSelector_->setCurrentIndex(GlyphContinuous::AG_AllGlyphs);
modeLabel_ = new QLabel(tr("Mode:"), this);
charMapLabel_ = new QLabel(tr("Char Map:"), this);
+ xEmboldeningLabel_ = new QLabel(tr("Hori. Embolding (for Fancy):"), this);
+ yEmboldeningLabel_ = new QLabel(tr("Vert. Embolding (for Fancy):"), this);
+ slantLabel_ = new QLabel(tr("Slanting (for Fancy):"), this);
+
+ xEmboldeningSpinBox_ = new QDoubleSpinBox(this);
+ yEmboldeningSpinBox_ = new QDoubleSpinBox(this);
+ slantSpinBox_ = new QDoubleSpinBox(this);
+
+ xEmboldeningSpinBox_->setSingleStep(0.005);
+ xEmboldeningSpinBox_->setMinimum(-0.1);
+ xEmboldeningSpinBox_->setMaximum(0.1);
+ yEmboldeningSpinBox_->setSingleStep(0.005);
+ yEmboldeningSpinBox_->setMinimum(-0.1);
+ yEmboldeningSpinBox_->setMaximum(0.1);
+ slantSpinBox_->setSingleStep(0.02);
+ slantSpinBox_->setMinimum(-1);
+ slantSpinBox_->setMaximum(1);
layout_ = new QGridLayout;
layout_->addWidget(indexSelector_, 0, 0, 1, 2);
@@ -291,7 +348,15 @@ ContinousAllGlyphsTab::createLayout()
layout_->addWidget(modeSelector_, 1, 1);
layout_->addWidget(charMapSelector_, 2, 1);
+ layout_->addWidget(xEmboldeningLabel_, 1, 2);
+ layout_->addWidget(yEmboldeningLabel_, 2, 2);
+ layout_->addWidget(slantLabel_, 3, 2);
+ layout_->addWidget(xEmboldeningSpinBox_, 1, 3);
+ layout_->addWidget(yEmboldeningSpinBox_, 2, 3);
+ layout_->addWidget(slantSpinBox_, 3, 3);
+
layout_->setColumnStretch(1, 1);
+ layout_->setColumnStretch(3, 1);
setLayout(layout_);
}
@@ -302,9 +367,19 @@ ContinousAllGlyphsTab::createConnections()
connect(indexSelector_, &GlyphIndexSelector::currentIndexChanged,
this, &ContinousAllGlyphsTab::changed);
connect(modeSelector_, QOverload<int>::of(&QComboBox::currentIndexChanged),
- this, &ContinousAllGlyphsTab::changed);
+ this, &ContinousAllGlyphsTab::checkSubMode);
connect(charMapSelector_,
QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &ContinousAllGlyphsTab::charMapChanged);
+
+ connect(xEmboldeningSpinBox_,
+ QOverload<double>::of(&QDoubleSpinBox::valueChanged),
+ this, &ContinousAllGlyphsTab::changed);
+ connect(yEmboldeningSpinBox_,
+ QOverload<double>::of(&QDoubleSpinBox::valueChanged),
+ this, &ContinousAllGlyphsTab::changed);
+ connect(slantSpinBox_,
+ QOverload<double>::of(&QDoubleSpinBox::valueChanged),
+ this, &ContinousAllGlyphsTab::changed);
}
@@ -339,4 +414,13 @@ ContinousAllGlyphsTab::charMapChanged()
}
+void
+ContinousAllGlyphsTab::setDefaults()
+{
+ xEmboldeningSpinBox_->setValue(0.04);
+ yEmboldeningSpinBox_->setValue(0.04);
+ slantSpinBox_->setValue(0.22);
+}
+
+
// end of continuous.cpp
diff --git a/src/ftinspect/panels/continuous.hpp
b/src/ftinspect/panels/continuous.hpp
index fb37928..c716aca 100644
--- a/src/ftinspect/panels/continuous.hpp
+++ b/src/ftinspect/panels/continuous.hpp
@@ -79,6 +79,9 @@ public:
int glyphBeginindex();
int glyphLimitIndex();
GlyphContinuous::SubModeAllGlyphs subMode();
+ double xEmboldening();
+ double yEmboldening();
+ double slanting();
// -1: Glyph order, otherwise the char map index in the original list
int charMapIndex();
@@ -92,6 +95,8 @@ public:
// This doesn't trigger either.
void updateLimitIndex();
+ void checkSubMode();
+
signals:
void changed();
@@ -106,6 +111,13 @@ private:
QLabel* modeLabel_;
QLabel* charMapLabel_;
+ QLabel* xEmboldeningLabel_;
+ QLabel* yEmboldeningLabel_;
+ QLabel* slantLabel_;
+
+ QDoubleSpinBox* xEmboldeningSpinBox_;
+ QDoubleSpinBox* yEmboldeningSpinBox_;
+ QDoubleSpinBox* slantSpinBox_;
QGridLayout* layout_;
@@ -116,6 +128,8 @@ private:
QString formatIndex(int index);
void charMapChanged();
+
+ void setDefaults();
};
diff --git a/src/ftinspect/rendering/glyphbitmap.cpp
b/src/ftinspect/rendering/glyphbitmap.cpp
index 20bf92e..78623a6 100644
--- a/src/ftinspect/rendering/glyphbitmap.cpp
+++ b/src/ftinspect/rendering/glyphbitmap.cpp
@@ -24,7 +24,8 @@ GlyphBitmap::GlyphBitmap(FT_Outline* outline,
{
// make a copy of the outline since we are going to manipulate it
FT_BBox cbox;
- transformed_ = transformOutlineToOrigin(lib, outline, &cbox);
+ transformed_ = cloneOutline(lib, outline);
+ transformOutlineToOrigin(&transformed_, &cbox);
boundingRect_.setCoords(cbox.xMin / 64, -cbox.yMax / 64,
cbox.xMax / 64, -cbox.yMin / 64);
}
diff --git a/src/ftinspect/rendering/glyphcontinuous.cpp
b/src/ftinspect/rendering/glyphcontinuous.cpp
index 524af4c..33e4954 100644
--- a/src/ftinspect/rendering/glyphcontinuous.cpp
+++ b/src/ftinspect/rendering/glyphcontinuous.cpp
@@ -38,12 +38,9 @@ GlyphContinuous::paintEvent(QPaintEvent* event)
switch (modeAG_)
{
case AG_AllGlyphs:
- paintAGAllGlyphs(&painter);
- break;
- // TODO more modes
case AG_Fancy:
- break;
case AG_Stroked:
+ paintAG(&painter);
break;
case AG_Waterfall:
break;
@@ -71,7 +68,7 @@ GlyphContinuous::wheelEvent(QWheelEvent* event)
void
-GlyphContinuous::paintAGAllGlyphs(QPainter* painter)
+GlyphContinuous::paintAG(QPainter* painter)
{
for (int i = beginIndex_; i < limitIndex_; i++)
{
@@ -79,11 +76,85 @@ GlyphContinuous::paintAGAllGlyphs(QPainter* painter)
if (charMapIndex_ >= 0)
index = engine_->glyphIndexFromCharCode(i, charMapIndex_);
- if (!paintChar(painter, index))
+ if (!loadGlyph(index))
break;
+ // All Glyphs need no tranformation, and Waterfall isn't handled here.
+ switch (modeAG_)
+ {
+ case AG_Fancy:
+ transformGlyphAGFancy();
+ break;
+ case AG_Stroked:
+ transformGlyphAGStroked();
+ break;
+ default:;
+ }
+
+ if (!paintChar(painter))
+ break;
+ cleanCloned();
+
displayingCount_++;
}
+ cleanCloned();
+}
+
+
+void
+GlyphContinuous::transformGlyphAGFancy()
+{
+ // adopted from ftview.c:289
+ /***************************************************************/
+ /* */
+ /* 2*2 affine transformation matrix, 16.16 fixed float format */
+ /* */
+ /* Shear matrix: */
+ /* */
+ /* | x' | | 1 k | | x | x' = x + ky */
+ /* | | = | | * | | <==> */
+ /* | y' | | 0 1 | | y | y' = y */
+ /* */
+ /* outline' shear outline */
+ /* */
+ /***************************************************************/
+
+ FT_Matrix shear;
+ FT_Pos xstr, ystr;
+
+ shear.xx = 1 << 16;
+ shear.xy = (FT_Fixed)(slant_ * (1 << 16));
+ shear.yx = 0;
+ shear.yy = 1 << 16;
+
+ xstr = (FT_Pos)(metrics_.y_ppem * 64 * boldX_);
+ ystr = (FT_Pos)(metrics_.y_ppem * 64 * boldY_);
+
+ if (!isGlyphCloned_)
+ cloneGlyph();
+
+ if (glyph_->format != FT_GLYPH_FORMAT_OUTLINE)
+ return; // TODO suuport non-outline: code below all depend on `outline_`!
+
+ FT_Outline_Transform(&outline_, &shear);
+ FT_Outline_EmboldenXY(&outline_, xstr, ystr);
+
+ if (glyph_->advance.x)
+ glyph_->advance.x += xstr;
+
+ if (glyph_->advance.y)
+ glyph_->advance.y += ystr;
+
+ //glyph_->metrics.width += xstr;
+ //glyph_->metrics.height += ystr;
+ //glyph_->metrics.horiAdvance += xstr;
+ //glyph_->metrics.vertAdvance += ystr;
+}
+
+
+void
+GlyphContinuous::transformGlyphAGStroked()
+{
}
@@ -101,16 +172,11 @@ GlyphContinuous::prePaint()
bool
-GlyphContinuous::paintChar(QPainter* painter,
- int index)
+GlyphContinuous::paintChar(QPainter* painter)
{
- auto glyph = engine_->loadGlyphWithoutUpdate(index);
- if (!glyph)
- return false;
-
// ftview.c:557
- int width = glyph->advance.x ? glyph->advance.x >> 16
- : metrics_.y_ppem / 2;
+ int width = glyph_->advance.x ? glyph_->advance.x >> 16
+ : metrics_.y_ppem / 2;
if (!checkFitX(x_ + width))
{
@@ -122,7 +188,7 @@ GlyphContinuous::paintChar(QPainter* painter,
}
x_++; // extra space
- if (glyph->advance.x == 0)
+ if (glyph_->advance.x == 0)
{
// Draw a red square to indicate
painter->fillRect(x_, y_ - width, width, width,
@@ -136,15 +202,15 @@ GlyphContinuous::paintChar(QPainter* painter,
// First translate the outline
- if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
+ if (glyph_->format != FT_GLYPH_FORMAT_OUTLINE)
return true; // XXX only outline is supported - need to impl others later
FT_BBox cbox;
// Don't forget to free this when returning
- auto outline = transformOutlineToOrigin(
- engine_->ftLibrary(),
- &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline,
- &cbox);
+ if (!isOutlineCloned_ && !isGlyphCloned_)
+ cloneOutline();
+
+ transformOutlineToOrigin(&outline_, &cbox);
auto outlineWidth = (cbox.xMax - cbox.xMin) / 64;
auto outlineHeight = (cbox.yMax - cbox.yMin) / 64;
@@ -175,12 +241,11 @@ GlyphContinuous::paintChar(QPainter* painter,
bitmap.pixel_mode = aaEnabled ? FT_PIXEL_MODE_GRAY : FT_PIXEL_MODE_MONO;
FT_Error error = FT_Outline_Get_Bitmap(engine_->ftLibrary(),
- &outline,
+ &outline_,
&bitmap);
if (error)
{
// XXX error handling
- FT_Outline_Done(engine_->ftLibrary(), &outline);
return true;
}
@@ -189,12 +254,59 @@ GlyphContinuous::paintChar(QPainter* painter,
image.convertToFormat(QImage::Format_ARGB32_Premultiplied));
x_ += width;
+
+ return true;
+}
- FT_Outline_Done(engine_->ftLibrary(), &outline);
+
+bool
+GlyphContinuous::loadGlyph(int index)
+{
+ glyph_ = engine_->loadGlyphWithoutUpdate(index);
+ isGlyphCloned_ = false;
+ if (!glyph_)
+ return false;
+ if (glyph_->format == FT_GLYPH_FORMAT_OUTLINE)
+ {
+ isOutlineCloned_ = false;
+ outline_ = reinterpret_cast<FT_OutlineGlyph>(glyph_)->outline;
+ }
return true;
}
+void
+GlyphContinuous::cloneGlyph()
+{
+ glyph_ = ::cloneGlyph(glyph_);
+ isGlyphCloned_ = true;
+}
+
+
+void
+GlyphContinuous::cloneOutline()
+{
+ outline_ = ::cloneOutline(engine_->ftLibrary(), &outline_);
+ isOutlineCloned_ = true;
+}
+
+
+void
+GlyphContinuous::cleanCloned()
+{
+ if (isGlyphCloned_)
+ {
+ FT_Done_Glyph(glyph_);
+ isGlyphCloned_ = false;
+ }
+ if (isOutlineCloned_)
+ {
+ FT_Outline_Done(engine_->ftLibrary(), &outline_);
+ isOutlineCloned_ = false;
+ }
+}
+
+
bool
GlyphContinuous::checkFitX(int x)
{
diff --git a/src/ftinspect/rendering/glyphcontinuous.hpp
b/src/ftinspect/rendering/glyphcontinuous.hpp
index 9a87e7e..5206170 100644
--- a/src/ftinspect/rendering/glyphcontinuous.hpp
+++ b/src/ftinspect/rendering/glyphcontinuous.hpp
@@ -7,6 +7,8 @@
#include "graphicsdefault.hpp"
#include <QWidget>
#include <freetype/freetype.h>
+#include <freetype/ftglyph.h>
+#include <freetype/ftoutln.h>
class Engine;
class GlyphContinuous
@@ -39,6 +41,12 @@ public:
void setCharMapIndex(int index) { charMapIndex_ = index; }
void setMode(Mode mode) { mode_ = mode; }
void setSubModeAllGlyphs(SubModeAllGlyphs modeAg) { modeAG_ = modeAg; }
+ void setFancyParams(double boldX, double boldY, double slant)
+ {
+ boldX_ = boldX;
+ boldY_ = boldY;
+ slant_ = slant;
+ }
signals:
void wheelNavigate(int steps);
@@ -53,21 +61,33 @@ private:
Engine* engine_;
GraphicsDefault* graphicsDefault_;
+ Mode mode_ = AllGlyphs;
+ SubModeAllGlyphs modeAG_ = AG_AllGlyphs;
int beginIndex_;
int limitIndex_;
int charMapIndex_;
- Mode mode_ = AllGlyphs;
- SubModeAllGlyphs modeAG_ = AG_AllGlyphs;
+ double boldX_ = 0.04, boldY_ = 0.04, slant_ = 0.22;
int displayingCount_ = 0;
FT_Size_Metrics metrics_;
int x_ = 0, y_ = 0;
int stepY_ = 0;
-
- void paintAGAllGlyphs(QPainter* painter);
+ FT_Glyph glyph_;
+ FT_Outline outline_;
+ // when glyph is cloned, outline is factually also cloned
+ // but `isOutlineCloned` won't be set!
+ bool isGlyphCloned_ = false, isOutlineCloned_ = false;
+
+ void paintAG(QPainter* painter);
+ void transformGlyphAGFancy();
+ void transformGlyphAGStroked();
void prePaint();
// return if there's enough space to paint the current char
- bool paintChar(QPainter* painter, int index);
+ bool paintChar(QPainter* painter);
+ bool loadGlyph(int index);
+ void cloneGlyph();
+ void cloneOutline();
+ void cleanCloned();
bool checkFitX(int x);
bool checkFitY(int y);
diff --git a/src/ftinspect/rendering/renderutils.cpp
b/src/ftinspect/rendering/renderutils.cpp
index 9866db8..260f499 100644
--- a/src/ftinspect/rendering/renderutils.cpp
+++ b/src/ftinspect/rendering/renderutils.cpp
@@ -5,16 +5,30 @@
#include "renderutils.hpp"
FT_Outline
-transformOutlineToOrigin(FT_Library library,
- FT_Outline* outline,
- FT_BBox* outControlBox)
+cloneOutline(FT_Library library,
+ FT_Outline* src)
{
FT_Outline transformed;
- FT_Outline_New(library,
- static_cast<unsigned int>(outline->n_points),
- outline->n_contours, &transformed);
- FT_Outline_Copy(outline, &transformed);
+ FT_Outline_New(library, static_cast<unsigned int>(src->n_points),
+ src->n_contours, &transformed);
+ FT_Outline_Copy(src, &transformed);
+ return transformed;
+}
+
+FT_Glyph
+cloneGlyph(FT_Glyph src)
+{
+ FT_Glyph target = NULL;
+ FT_Glyph_Copy(src, &target);
+ return target;
+}
+
+
+void
+transformOutlineToOrigin(FT_Outline* outline,
+ FT_BBox* outControlBox)
+{
FT_BBox cbox;
FT_Outline_Get_CBox(outline, &cbox);
@@ -23,11 +37,10 @@ transformOutlineToOrigin(FT_Library library,
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(&transformed, -cbox.xMin, -cbox.yMin);
+ FT_Outline_Translate(outline, -cbox.xMin, -cbox.yMin);
if (outControlBox)
*outControlBox = cbox;
- return transformed;
}
diff --git a/src/ftinspect/rendering/renderutils.hpp
b/src/ftinspect/rendering/renderutils.hpp
index ba4caf4..55175fa 100644
--- a/src/ftinspect/rendering/renderutils.hpp
+++ b/src/ftinspect/rendering/renderutils.hpp
@@ -4,12 +4,15 @@
#pragma once
+#include <freetype/ftglyph.h>
#include <freetype/ftoutln.h>
// The constructed `outline` must be freed by the caller
-FT_Outline transformOutlineToOrigin(FT_Library library,
- FT_Outline* outline,
- FT_BBox* outControlBox);
+FT_Outline cloneOutline(FT_Library library, FT_Outline* src);
+FT_Glyph cloneGlyph(FT_Glyph src);
+
+void transformOutlineToOrigin(FT_Outline* outline,
+ FT_BBox* outControlBox);
// end of renderutils.hpp
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [freetype2-demos] gsoc-2022-chariri-2 4b0f225 28/30: [ftinspect] Add Fancy submode to "Continuous View",
Werner Lemberg <=