mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Tweaks to font-rendering: fonts are now vertically hinted by finding the best overall scale that will make the most common horizontal features better aligned. Changed the font gamma to be greater when rendering with brighter colours.
This commit is contained in:
parent
d582a66917
commit
a1a43ea418
3 changed files with 205 additions and 57 deletions
|
|
@ -101,8 +101,8 @@ struct FontStyleHelpers
|
|||
};
|
||||
|
||||
//==============================================================================
|
||||
Typeface::Typeface (const String& name_, const String& style_) noexcept
|
||||
: name (name_), style (style_)
|
||||
Typeface::Typeface (const String& faceName, const String& styleName) noexcept
|
||||
: name (faceName), style (styleName)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -126,3 +126,134 @@ EdgeTable* Typeface::getEdgeTableForGlyph (int glyphNumber, const AffineTransfor
|
|||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct Typeface::HintingParams
|
||||
{
|
||||
HintingParams (Typeface& t)
|
||||
: top (0), middle (0), bottom (0)
|
||||
{
|
||||
Font font (&t);
|
||||
font = font.withHeight ((float) standardHeight);
|
||||
|
||||
top = getAverageY (font, "BDEFPRTZOQC", true);
|
||||
middle = getAverageY (font, "acegmnopqrsuvwxy", true);
|
||||
bottom = getAverageY (font, "BDELZOC", false);
|
||||
}
|
||||
|
||||
AffineTransform getVerticalHintingTransform (float fontSize) noexcept
|
||||
{
|
||||
if (cachedSize == fontSize)
|
||||
return cachedTransform;
|
||||
|
||||
const float t = fontSize * top;
|
||||
const float m = fontSize * middle;
|
||||
const float b = fontSize * bottom;
|
||||
|
||||
if (b < t + 2.0f)
|
||||
return AffineTransform();
|
||||
|
||||
Scaling s[] = { Scaling (t, m, b, 0.0f, 0.0f),
|
||||
Scaling (t, m, b, 1.0f, 0.0f),
|
||||
Scaling (t, m, b, 0.0f, 1.0f),
|
||||
Scaling (t, m, b, 1.0f, 1.0f) };
|
||||
|
||||
int best = 0;
|
||||
|
||||
for (int i = 1; i < numElementsInArray (s); ++i)
|
||||
if (s[i].drift < s[best].drift)
|
||||
best = i;
|
||||
|
||||
cachedSize = fontSize;
|
||||
|
||||
AffineTransform result (s[best].getTransform());
|
||||
cachedTransform = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
float cachedSize;
|
||||
AffineTransform cachedTransform;
|
||||
|
||||
struct Scaling
|
||||
{
|
||||
Scaling (float t, float m, float b, float direction1, float direction2) noexcept
|
||||
{
|
||||
float newT = std::floor (t) + direction1;
|
||||
float newB = std::floor (b) + direction2;
|
||||
float newM = newT + (newB - newT) * (m - t) / (b - t);
|
||||
|
||||
float middleOffset = newM - std::floor (newM);
|
||||
float nudge = middleOffset < 0.5f ? (middleOffset * -0.2f) : ((1.0f - middleOffset) * 0.2f);
|
||||
newT += nudge;
|
||||
newB += nudge;
|
||||
|
||||
scale = (newB - newT) / (b - t);
|
||||
offset = (newB / scale) - b;
|
||||
|
||||
drift = getDrift (t) + getDrift (m) + getDrift (b) + offset + 20.0f * std::abs (scale - 1.0f);
|
||||
}
|
||||
|
||||
AffineTransform getTransform() const noexcept
|
||||
{
|
||||
return AffineTransform::translation (0, offset).scaled (1.0f, scale);
|
||||
}
|
||||
|
||||
float getDrift (float n) const noexcept
|
||||
{
|
||||
n = (n + offset) * scale;
|
||||
const float diff = n - std::floor (n);
|
||||
return jmin (diff, 1.0f - diff);
|
||||
}
|
||||
|
||||
float offset, scale, drift;
|
||||
};
|
||||
|
||||
static float getAverageY (const Font& font, const char* chars, bool getTop)
|
||||
{
|
||||
GlyphArrangement ga;
|
||||
ga.addLineOfText (font, chars, 0, 0);
|
||||
|
||||
Array<float> y;
|
||||
DefaultElementComparator<float> sorter;
|
||||
|
||||
for (int i = 0; i < ga.getNumGlyphs(); ++i)
|
||||
{
|
||||
Path p;
|
||||
ga.getGlyph (i).createPath (p);
|
||||
Rectangle<float> bounds (p.getBounds());
|
||||
|
||||
if (! p.isEmpty())
|
||||
y.addSorted (sorter, getTop ? bounds.getY() : bounds.getBottom());
|
||||
}
|
||||
|
||||
float median = y[y.size() / 2];
|
||||
|
||||
int total = 0;
|
||||
int num = 0;
|
||||
|
||||
for (int i = 0; i < y.size(); ++i)
|
||||
{
|
||||
if (std::abs (median - y.getUnchecked(i)) < 0.05f * (float) standardHeight)
|
||||
{
|
||||
total += y.getUnchecked(i);
|
||||
++num;
|
||||
}
|
||||
}
|
||||
|
||||
return num < 4 ? 0.0f : total / (num * (float) standardHeight);
|
||||
}
|
||||
|
||||
enum { standardHeight = 100 };
|
||||
float top, middle, bottom;
|
||||
};
|
||||
|
||||
AffineTransform Typeface::getVerticalHintingTransform (float fontSize)
|
||||
{
|
||||
ScopedLock sl (hintingLock);
|
||||
|
||||
if (hintingParams == nullptr)
|
||||
hintingParams = new HintingParams (*this);
|
||||
|
||||
return hintingParams->getVerticalHintingTransform (fontSize);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,6 +134,11 @@ public:
|
|||
*/
|
||||
static void scanFolderForFonts (const File& folder);
|
||||
|
||||
/** Makes an attempt at estimating a good overall transform that will scale a font of
|
||||
the given size to align vertically with the pixel grid.
|
||||
*/
|
||||
AffineTransform getVerticalHintingTransform (float fontHeight);
|
||||
|
||||
protected:
|
||||
//==============================================================================
|
||||
String name, style;
|
||||
|
|
@ -143,6 +148,11 @@ protected:
|
|||
static Ptr getFallbackTypeface();
|
||||
|
||||
private:
|
||||
struct HintingParams;
|
||||
friend struct ContainerDeletePolicy<HintingParams>;
|
||||
ScopedPointer<HintingParams> hintingParams;
|
||||
CriticalSection hintingLock;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Typeface)
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue