|
|
|
@@ -2377,47 +2377,8 @@ void LowLevelGraphicsSoftwareRenderer::drawHorizontalLine (const int y, float le |
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
class LowLevelGraphicsSoftwareRenderer::CachedGlyph
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CachedGlyph() : glyph (0), lastAccessCount (0) {}
|
|
|
|
|
|
|
|
void draw (SavedState& state, float x, const float y) const
|
|
|
|
{
|
|
|
|
if (snapToIntegerCoordinate)
|
|
|
|
x = std::floor (x + 0.5f);
|
|
|
|
|
|
|
|
if (edgeTable != nullptr)
|
|
|
|
state.fillEdgeTable (*edgeTable, x, roundToInt (y));
|
|
|
|
}
|
|
|
|
|
|
|
|
void generate (const Font& newFont, const int glyphNumber)
|
|
|
|
{
|
|
|
|
font = newFont;
|
|
|
|
snapToIntegerCoordinate = newFont.getTypeface()->isHinted();
|
|
|
|
glyph = glyphNumber;
|
|
|
|
|
|
|
|
const float fontHeight = font.getHeight();
|
|
|
|
edgeTable = font.getTypeface()->getEdgeTableForGlyph (glyphNumber,
|
|
|
|
AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight)
|
|
|
|
#if JUCE_MAC || JUCE_IOS
|
|
|
|
.translated (0.0f, -0.5f)
|
|
|
|
#endif
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Font font;
|
|
|
|
int glyph, lastAccessCount;
|
|
|
|
bool snapToIntegerCoordinate;
|
|
|
|
|
|
|
|
private:
|
|
|
|
ScopedPointer <EdgeTable> edgeTable;
|
|
|
|
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CachedGlyph);
|
|
|
|
};
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
class LowLevelGraphicsSoftwareRenderer::GlyphCache : private DeletedAtShutdown
|
|
|
|
template <class CachedGlyphType, class RenderTargetType>
|
|
|
|
class GlyphCache : private DeletedAtShutdown
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
GlyphCache()
|
|
|
|
@@ -2428,27 +2389,35 @@ public: |
|
|
|
|
|
|
|
~GlyphCache()
|
|
|
|
{
|
|
|
|
clearSingletonInstance();
|
|
|
|
getSingletonPointer() = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
juce_DeclareSingleton_SingleThreaded_Minimal (GlyphCache);
|
|
|
|
static GlyphCache& getInstance()
|
|
|
|
{
|
|
|
|
GlyphCache*& g = getSingletonPointer();
|
|
|
|
|
|
|
|
if (g == nullptr)
|
|
|
|
g = new GlyphCache();
|
|
|
|
|
|
|
|
return *g;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
void drawGlyph (SavedState& state, const Font& font, const int glyphNumber, float x, float y)
|
|
|
|
void drawGlyph (RenderTargetType& target, const Font& font, const int glyphNumber, float x, float y)
|
|
|
|
{
|
|
|
|
++accessCounter;
|
|
|
|
int oldestCounter = std::numeric_limits<int>::max();
|
|
|
|
CachedGlyph* oldest = nullptr;
|
|
|
|
CachedGlyphType* oldest = nullptr;
|
|
|
|
|
|
|
|
for (int i = glyphs.size(); --i >= 0;)
|
|
|
|
{
|
|
|
|
CachedGlyph* const glyph = glyphs.getUnchecked (i);
|
|
|
|
CachedGlyphType* const glyph = glyphs.getUnchecked (i);
|
|
|
|
|
|
|
|
if (glyph->glyph == glyphNumber && glyph->font == font)
|
|
|
|
{
|
|
|
|
++hits;
|
|
|
|
glyph->lastAccessCount = accessCounter;
|
|
|
|
glyph->draw (state, x, y);
|
|
|
|
glyph->draw (target, x, y);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
@@ -2471,35 +2440,68 @@ public: |
|
|
|
jassert (oldest != nullptr);
|
|
|
|
oldest->lastAccessCount = accessCounter;
|
|
|
|
oldest->generate (font, glyphNumber);
|
|
|
|
oldest->draw (state, x, y);
|
|
|
|
oldest->draw (target, x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
friend class OwnedArray <CachedGlyph>;
|
|
|
|
OwnedArray <CachedGlyph> glyphs;
|
|
|
|
friend class OwnedArray <CachedGlyphType>;
|
|
|
|
OwnedArray <CachedGlyphType> glyphs;
|
|
|
|
int accessCounter, hits, misses;
|
|
|
|
|
|
|
|
void addNewGlyphSlots (int num)
|
|
|
|
{
|
|
|
|
while (--num >= 0)
|
|
|
|
glyphs.add (new CachedGlyph());
|
|
|
|
glyphs.add (new CachedGlyphType());
|
|
|
|
}
|
|
|
|
|
|
|
|
static GlyphCache*& getSingletonPointer() noexcept
|
|
|
|
{
|
|
|
|
static GlyphCache* g = nullptr;
|
|
|
|
return g;
|
|
|
|
}
|
|
|
|
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GlyphCache);
|
|
|
|
};
|
|
|
|
|
|
|
|
juce_ImplementSingleton_SingleThreaded (LowLevelGraphicsSoftwareRenderer::GlyphCache);
|
|
|
|
//==============================================================================
|
|
|
|
class CachedGlyphEdgeTable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CachedGlyphEdgeTable() : glyph (0), lastAccessCount (0) {}
|
|
|
|
|
|
|
|
void draw (LowLevelGraphicsSoftwareRenderer::SavedState& state, float x, const float y) const
|
|
|
|
{
|
|
|
|
if (snapToIntegerCoordinate)
|
|
|
|
x = std::floor (x + 0.5f);
|
|
|
|
|
|
|
|
void LowLevelGraphicsSoftwareRenderer::setFont (const Font& newFont)
|
|
|
|
{
|
|
|
|
currentState->font = newFont;
|
|
|
|
}
|
|
|
|
if (edgeTable != nullptr)
|
|
|
|
state.fillEdgeTable (*edgeTable, x, roundToInt (y));
|
|
|
|
}
|
|
|
|
|
|
|
|
Font LowLevelGraphicsSoftwareRenderer::getFont()
|
|
|
|
{
|
|
|
|
return currentState->font;
|
|
|
|
}
|
|
|
|
void generate (const Font& newFont, const int glyphNumber)
|
|
|
|
{
|
|
|
|
font = newFont;
|
|
|
|
snapToIntegerCoordinate = newFont.getTypeface()->isHinted();
|
|
|
|
glyph = glyphNumber;
|
|
|
|
|
|
|
|
const float fontHeight = font.getHeight();
|
|
|
|
edgeTable = font.getTypeface()->getEdgeTableForGlyph (glyphNumber,
|
|
|
|
AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight)
|
|
|
|
#if JUCE_MAC || JUCE_IOS
|
|
|
|
.translated (0.0f, -0.5f)
|
|
|
|
#endif
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Font font;
|
|
|
|
int glyph, lastAccessCount;
|
|
|
|
bool snapToIntegerCoordinate;
|
|
|
|
|
|
|
|
private:
|
|
|
|
ScopedPointer <EdgeTable> edgeTable;
|
|
|
|
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CachedGlyphEdgeTable);
|
|
|
|
};
|
|
|
|
|
|
|
|
void LowLevelGraphicsSoftwareRenderer::drawGlyph (int glyphNumber, const AffineTransform& transform)
|
|
|
|
{
|
|
|
|
@@ -2507,18 +2509,23 @@ void LowLevelGraphicsSoftwareRenderer::drawGlyph (int glyphNumber, const AffineT |
|
|
|
|
|
|
|
if (transform.isOnlyTranslation() && currentState->isOnlyTranslated)
|
|
|
|
{
|
|
|
|
GlyphCache::getInstance()->drawGlyph (*currentState, f, glyphNumber,
|
|
|
|
transform.getTranslationX(),
|
|
|
|
transform.getTranslationY());
|
|
|
|
GlyphCache <CachedGlyphEdgeTable, SavedState>::getInstance()
|
|
|
|
.drawGlyph (*currentState, f, glyphNumber,
|
|
|
|
transform.getTranslationX(),
|
|
|
|
transform.getTranslationY());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const float fontHeight = f.getHeight();
|
|
|
|
currentState->drawGlyph (f, glyphNumber, AffineTransform::scale (fontHeight * f.getHorizontalScale(), fontHeight)
|
|
|
|
.followedBy (transform));
|
|
|
|
currentState->drawGlyph (f, glyphNumber,
|
|
|
|
AffineTransform::scale (fontHeight * f.getHorizontalScale(), fontHeight)
|
|
|
|
.followedBy (transform));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LowLevelGraphicsSoftwareRenderer::setFont (const Font& newFont) { currentState->font = newFont; }
|
|
|
|
Font LowLevelGraphicsSoftwareRenderer::getFont() { return currentState->font; }
|
|
|
|
|
|
|
|
#if JUCE_MSVC
|
|
|
|
#pragma warning (pop)
|
|
|
|
|
|
|
|
|