Add synthetic bold hack to better support Geneva CY

This commit is contained in:
elasota
2021-04-16 00:25:30 -04:00
parent 141f840888
commit 3d3f839801
5 changed files with 221 additions and 13 deletions

View File

@@ -8,6 +8,7 @@ struct GpRenderedFontMetrics;
struct IGpFont
{
virtual void Destroy() = 0;
virtual IGpFontRenderedGlyph *Render(uint32_t unicodeCodePoint, unsigned int size, bool aa) = 0;
virtual IGpFontRenderedGlyph *Render(uint32_t unicodeCodePoint, unsigned int size, unsigned int xScale, unsigned int yScale, bool aa) = 0;
virtual bool GetLineSpacing(unsigned int size, int32_t &outSpacing) = 0;
virtual bool SupportScaling() const = 0;
};

View File

@@ -40,8 +40,9 @@ class GpFont_FreeType2 final : public IGpFont
{
public:
void Destroy() override;
IGpFontRenderedGlyph *Render(uint32_t unicodeCodePoint, unsigned int size, bool aa) override;
IGpFontRenderedGlyph *Render(uint32_t unicodeCodePoint, unsigned int size, unsigned int xScale, unsigned int yScale, bool aa) override;
bool GetLineSpacing(unsigned int size, int32_t &outSpacing) override;
bool SupportScaling() const override;
static GpFont_FreeType2 *Create(const FT_StreamRec_ &streamRec, GpIOStream *stream);
@@ -107,7 +108,7 @@ void GpFont_FreeType2::Destroy()
free(this);
}
IGpFontRenderedGlyph *GpFont_FreeType2::Render(uint32_t unicodeCodePoint, unsigned int size, bool aa)
IGpFontRenderedGlyph *GpFont_FreeType2::Render(uint32_t unicodeCodePoint, unsigned int size, unsigned int xScale, unsigned int yScale, bool aa)
{
if (m_currentSize != size)
{
@@ -117,6 +118,14 @@ IGpFontRenderedGlyph *GpFont_FreeType2::Render(uint32_t unicodeCodePoint, unsign
m_currentSize = size;
}
FT_Matrix transform;
transform.xx = xScale << 16;
transform.xy = 0;
transform.yx = 0;
transform.yy = yScale << 16;
FT_Set_Transform(m_face, &transform, nullptr);
FT_UInt glyphIndex = FT_Get_Char_Index(m_face, unicodeCodePoint);
if (!glyphIndex)
return nullptr;
@@ -247,6 +256,10 @@ bool GpFont_FreeType2::GetLineSpacing(unsigned int size, int32_t &outSpacing)
return true;
}
bool GpFont_FreeType2::SupportScaling() const
{
return true;
}
GpFont_FreeType2 *GpFont_FreeType2::Create(const FT_StreamRec_ &streamRec, GpIOStream *stream)
{
@@ -268,6 +281,8 @@ bool GpFont_FreeType2::FTLoad(const FT_Library &library, int typeFaceIndex)
if (errorCode != 0)
return false;
FT_Matrix transform;
return true;
}

View File

@@ -6,5 +6,6 @@ namespace PortabilityLayer
{
FontHacks_None,
FontHacks_Roboto,
FontHacks_SyntheticBold,
};
}

View File

@@ -140,15 +140,7 @@ namespace PortabilityLayer
*outVariationFlags = ms_fontPresets[preset].m_variationFlags;
if (outAA)
{
bool aa = ms_fontPresets[preset].m_aa;
FontFamilyID_t fontFamily = ms_fontPresets[preset].m_familyID;
if (m_hasPreinstalledFonts && (fontFamily == FontFamilyIDs::kApplication || fontFamily == FontFamilyIDs::kSystem))
*outAA = false;
else
*outAA = aa;
}
*outAA = ms_fontPresets[preset].m_aa;
if (outFamilyID)
{

View File

@@ -101,9 +101,31 @@ namespace PortabilityLayer
static FontRendererImpl *GetInstance();
private:
static void SynthesizeBoldAA(IGpFontRenderedGlyph *&glyph, unsigned int xScale, unsigned int yScale, bool aa);
static FontRendererImpl ms_instance;
};
class ReRenderedGlyph final : public IGpFontRenderedGlyph
{
public:
const GpRenderedGlyphMetrics &GetMetrics() const override;
const void *GetData() const override;
void Destroy() override;
void *GetMutableData();
GpRenderedGlyphMetrics &GetMutableMetrics();
static ReRenderedGlyph *Create(unsigned int width, unsigned int height, bool aa);
private:
explicit ReRenderedGlyph(void *data, unsigned int width, unsigned int height, size_t pitch, size_t dataSize);
GpRenderedGlyphMetrics m_metrics;
void *m_data;
size_t m_dataSize;
};
bool RenderedFontImpl::GetGlyph(unsigned int character, const GpRenderedGlyphMetrics *&outMetricsPtr, const void *&outData) const
{
const size_t dataOffset = m_dataOffsets[character];
@@ -347,13 +369,38 @@ namespace PortabilityLayer
for (unsigned int i = 0; i < numCharacters; i++)
glyphs[i] = nullptr;
unsigned int xScale = 1;
unsigned int yScale = 1;
bool syntheticBoldAA = false;
if (fontHacks == FontHacks_SyntheticBold)
{
if (aa)
{
syntheticBoldAA = true;
xScale = 16;
yScale = 16;
}
}
for (unsigned int i = 0; i < numCharacters; i++)
{
uint16_t unicodeCodePoint = MacRoman::ToUnicode(i);
if (unicodeCodePoint == 0xffff)
continue;
glyphs[i] = font->Render(unicodeCodePoint, size, aa);
glyphs[i] = font->Render(unicodeCodePoint, size, xScale, yScale, aa);
}
if (fontHacks == FontHacks_SyntheticBold)
{
if (syntheticBoldAA)
{
for (unsigned int i = 0; i < numCharacters; i++)
{
if (glyphs[i])
SynthesizeBoldAA(glyphs[i], xScale, yScale, syntheticBoldAA);
}
}
}
size_t glyphDataSize = GP_SYSTEM_MEMORY_ALIGNMENT; // So we can use 0 to mean no data
@@ -465,6 +512,97 @@ namespace PortabilityLayer
return true;
}
void FontRendererImpl::SynthesizeBoldAA(IGpFontRenderedGlyph *&glyph, unsigned int xScale, unsigned int yScale, bool aa)
{
GpRenderedGlyphMetrics metrics = glyph->GetMetrics();
const void *existingData = glyph->GetData();
uint32_t existingWidth = metrics.m_glyphWidth;
uint32_t existingHeight = metrics.m_glyphHeight;
uint32_t newWidth = (existingWidth + xScale - 1) / xScale + 1;
uint32_t newHeight = (existingHeight + yScale - 1) / yScale;
ReRenderedGlyph *newGlyph = ReRenderedGlyph::Create(newWidth, newHeight, aa);
if (!newGlyph)
return;
uint16_t *fattenAccumulateBuffer = static_cast<uint16_t*>(MemoryManager::GetInstance()->Alloc(newWidth * sizeof(uint16_t)));
if (!fattenAccumulateBuffer)
{
newGlyph->Destroy();
return;
}
GpRenderedGlyphMetrics &newMetrics = newGlyph->GetMutableMetrics();
newMetrics.m_advanceX = metrics.m_advanceX + 1;
newMetrics.m_bearingX = metrics.m_bearingX;
newMetrics.m_bearingY = metrics.m_bearingY;
const size_t existingDataPitch = metrics.m_glyphDataPitch;
const size_t newPitch = newMetrics.m_glyphDataPitch;
uint8_t *newData = static_cast<uint8_t*>(newGlyph->GetMutableData());
for (unsigned int outY = 0; outY < newHeight; outY++)
{
memset(fattenAccumulateBuffer, 0, newWidth * sizeof(uint16_t));
for (unsigned int subY = 0; subY < yScale; subY++)
{
unsigned int originalY = subY + outY * yScale;
if (originalY >= existingHeight)
break;
const uint8_t *existingRow = static_cast<const uint8_t*>(existingData) + originalY * existingDataPitch;
unsigned int streakCounter = 0;
unsigned int outX = 0;
unsigned int outSubX = 0;
for (unsigned int originalX = 0; originalX < newWidth * xScale; originalX++)
{
if (originalX < existingWidth)
{
//if (existingRow[originalX / 8] & (1 << (originalX & 7)))
uint8_t v = ((existingRow[originalX / 2] >> ((originalX & 1) * 4)) & 0xf);
if (v >= 8)
streakCounter = xScale + 1;
}
if (streakCounter > 0)
{
streakCounter--;
fattenAccumulateBuffer[outX]++;
}
outSubX++;
if (outSubX == xScale)
{
outSubX = 0;
outX++;
}
}
}
uint8_t *outRow = newData + outY * newPitch;
unsigned int divisor = xScale * yScale;
for (unsigned int x = 0; x < newWidth; x++)
{
uint32_t fraction = static_cast<uint32_t>(fattenAccumulateBuffer[x]) * 15;
fraction = (fraction * 2 + divisor) / (divisor * 2);
uint8_t *outByte = outRow + (x / 2);
(*outByte) |= fraction << ((x & 1) * 4);
size_t outOffset = outByte - newData;
}
}
MemoryManager::GetInstance()->Release(fattenAccumulateBuffer);
glyph->Destroy();
glyph = newGlyph;
}
FontRendererImpl *FontRendererImpl::GetInstance()
{
return &ms_instance;
@@ -472,6 +610,67 @@ namespace PortabilityLayer
FontRendererImpl FontRendererImpl::ms_instance;
const GpRenderedGlyphMetrics &ReRenderedGlyph::GetMetrics() const
{
return m_metrics;
}
const void *ReRenderedGlyph::GetData() const
{
return m_data;
}
void ReRenderedGlyph::Destroy()
{
this->~ReRenderedGlyph();
PortabilityLayer::MemoryManager::GetInstance()->Release(this);
}
void *ReRenderedGlyph::GetMutableData()
{
return m_data;
}
GpRenderedGlyphMetrics &ReRenderedGlyph::GetMutableMetrics()
{
return m_metrics;
}
ReRenderedGlyph *ReRenderedGlyph::Create(unsigned int width, unsigned int height, bool aa)
{
size_t pitchRequired = 0;
if (aa)
pitchRequired = (width + 1) / 2;
else
pitchRequired = (width + 7) / 8;
pitchRequired = pitchRequired + (GP_SYSTEM_MEMORY_ALIGNMENT - 1);
pitchRequired -= pitchRequired % GP_SYSTEM_MEMORY_ALIGNMENT;
size_t baseRequired = sizeof(ReRenderedGlyph);
baseRequired = baseRequired + (GP_SYSTEM_MEMORY_ALIGNMENT - 1);
baseRequired -= baseRequired % GP_SYSTEM_MEMORY_ALIGNMENT;
size_t totalRequired = baseRequired + pitchRequired * height;
void *storage = MemoryManager::GetInstance()->Alloc(totalRequired);
if (!storage)
return nullptr;
uint8_t *data = static_cast<uint8_t*>(storage) + baseRequired;
memset(data, 0, pitchRequired * height);
return new (storage) ReRenderedGlyph(data, width, height, pitchRequired, totalRequired - baseRequired);
}
ReRenderedGlyph::ReRenderedGlyph(void *data, unsigned int width, unsigned int height, size_t pitch, size_t dataSize)
: m_data(data)
, m_dataSize(dataSize)
{
m_metrics.m_glyphWidth = width;
m_metrics.m_glyphHeight = height;
m_metrics.m_glyphDataPitch = pitch;
}
FontRenderer *FontRenderer::GetInstance()
{
return FontRendererImpl::GetInstance();