#include "FontRenderer.h"

#include "CoreDefs.h"
#include "IGpFont.h"
#include "GpIOStream.h"
#include "IGpFontRenderedGlyph.h"
#include "MacRomanConversion.h"
#include "MemoryManager.h"
#include "RenderedFont.h"
#include "GpRenderedFontMetrics.h"
#include "GpRenderedGlyphMetrics.h"

#include "PLBigEndian.h"
#include "PLCore.h"
#include "PLDrivers.h"
#include "PLPasStr.h"
#include "DeflateCodec.h"

#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <new>

namespace PortabilityLayer
{
	class RenderedFontImpl final : public RenderedFont
	{
	public:
		bool GetGlyph(unsigned int character, const GpRenderedGlyphMetrics *&outMetricsPtr, const void *&outData) const override;
		const GpRenderedFontMetrics &GetMetrics() const override;
		size_t MeasureString(const uint8_t *chars, size_t len) const override;
		bool IsAntiAliased() const override;

		void Destroy() override;

		void SetCharData(unsigned int charID, const void *data, size_t dataOffset, const GpRenderedGlyphMetrics &metrics);
		void SetFontMetrics(const GpRenderedFontMetrics &metrics);

		static RenderedFont *Load(GpIOStream *stream);
		bool Save(GpIOStream *stream) const;

		static RenderedFontImpl *Create(size_t glyphDataSize, bool aa);

	private:
		struct CacheHeader
		{
			BEUInt32_t m_cacheVersion;
			BEUInt32_t m_glyphDataSize;

			BEUInt32_t m_isAA;
		};

		struct SerializedGlyphMetrics
		{
			BEUInt32_t m_glyphDataPitch;

			BEUInt32_t m_glyphWidth;
			BEUInt32_t m_glyphHeight;

			BEInt16_t m_bearingX;
			BEInt16_t m_bearingY;
			BEInt16_t m_advanceX;
			BEInt16_t m_bitmapOffsetX;
			BEInt16_t m_bitmapOffsetY;
		};

		struct SerializedFontMetrics
		{
			BEInt32_t m_ascent;
			BEInt32_t m_descent;
			BEInt32_t m_linegap;
		};

		static const uint32_t kRFontCacheVersion = 3;

		RenderedFontImpl(void *data, size_t dataSize, bool aa);
		~RenderedFontImpl();

		bool LoadInternal(GpIOStream *stream, size_t dataSize);

		static SerializedGlyphMetrics SerializeGlyphMetrics(const GpRenderedGlyphMetrics &metrics);
		static GpRenderedGlyphMetrics DeserializeGlyphMetrics(const SerializedGlyphMetrics &metrics);

		static SerializedFontMetrics SerializeFontMetrics(const GpRenderedFontMetrics &metrics);
		static GpRenderedFontMetrics DeserializeFontMetrics(const SerializedFontMetrics &metrics);

		size_t m_dataOffsets[256];
		GpRenderedGlyphMetrics m_glyphMetrics[256];

		GpRenderedFontMetrics m_fontMetrics;
		bool m_isAntiAliased;

		void *m_data;
		size_t m_dataSize;
	};

	class FontRendererImpl final : public FontRenderer
	{
	public:
		RenderedFont *RenderFont(IGpFont *font, int size, bool aa, FontHacks fontHacks) override;
		RenderedFont *LoadCache(GpIOStream *stream) override;
		bool SaveCache(const RenderedFont *rfont, GpIOStream *stream) override;

		static FontRendererImpl *GetInstance();

	private:
		static void SynthesizeBoldAA(IGpFontRenderedGlyph *&glyph, unsigned int xScale, unsigned int yScale, bool aa, uint8_t character, int size, FontHacks fontHacks);

		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];
		if (!dataOffset)
			return false;

		outMetricsPtr = m_glyphMetrics + character;
		outData = static_cast<const uint8_t*>(m_data) + dataOffset;

		return true;
	}

	const GpRenderedFontMetrics &RenderedFontImpl::GetMetrics() const
	{
		return m_fontMetrics;
	}

	size_t RenderedFontImpl::MeasureString(const uint8_t *chars, size_t len) const
	{
		size_t measure = 0;

		for (size_t i = 0; i < len; i++)
		{
			const GpRenderedGlyphMetrics &metrics = m_glyphMetrics[chars[i]];
			measure += metrics.m_advanceX;
		}

		return measure;
	}

	bool RenderedFontImpl::IsAntiAliased() const
	{
		return m_isAntiAliased;
	}

	void RenderedFontImpl::Destroy()
	{
		this->~RenderedFontImpl();
		DisposePtr(this);
	}

	void RenderedFontImpl::SetCharData(unsigned int charID, const void *data, size_t dataOffset, const GpRenderedGlyphMetrics &metrics)
	{
		m_dataOffsets[charID] = dataOffset;
		m_glyphMetrics[charID] = metrics;
		memcpy(static_cast<uint8_t*>(m_data) + dataOffset, data, metrics.m_glyphDataPitch * metrics.m_glyphHeight);
	}

	void RenderedFontImpl::SetFontMetrics(const GpRenderedFontMetrics &metrics)
	{
		m_fontMetrics = metrics;
	}

	RenderedFont *RenderedFontImpl::Load(GpIOStream *stream)
	{
		CacheHeader header;
		if (stream->Read(&header, sizeof(header)) != sizeof(header))
			return nullptr;

		if (header.m_cacheVersion != kRFontCacheVersion)
			return nullptr;

		RenderedFontImpl *rfont = RenderedFontImpl::Create(header.m_glyphDataSize, header.m_isAA != 0);
		if (!rfont)
			return nullptr;

		if (!rfont->LoadInternal(stream, header.m_glyphDataSize))
		{
			rfont->Destroy();
			return nullptr;
		}

		return rfont;
	}

	bool RenderedFontImpl::Save(GpIOStream *stream) const
	{
		CacheHeader header;
		header.m_cacheVersion = kRFontCacheVersion;
		header.m_glyphDataSize = static_cast<uint32_t>(this->m_dataSize);
		header.m_isAA = m_isAntiAliased ? 1 : 0;

		GpUFilePos_t headerPos = stream->Tell();

		if (stream->Write(&header, sizeof(header)) != sizeof(header))
			return false;

		if (!stream->WriteExact(m_data, m_dataSize))
			return false;

		for (size_t i = 0; i < sizeof(m_dataOffsets) / sizeof(m_dataOffsets[0]); i++)
		{
			BEUInt32_t dataOffset = BEUInt32_t(static_cast<uint32_t>(m_dataOffsets[i]));
			if (!stream->WriteExact(&dataOffset, sizeof(dataOffset)))
				return false;
		}

		for (size_t i = 0; i < sizeof(m_glyphMetrics) / sizeof(m_glyphMetrics[0]); i++)
		{
			SerializedGlyphMetrics serialized = SerializeGlyphMetrics(m_glyphMetrics[i]);

			if (!stream->WriteExact(&serialized, sizeof(serialized)))
				return false;
		}

		SerializedFontMetrics fontMetrics = SerializeFontMetrics(m_fontMetrics);

		if (!stream->WriteExact(&fontMetrics, sizeof(fontMetrics)))
			return false;

		return true;
	}

	RenderedFontImpl *RenderedFontImpl::Create(size_t glyphDataSize, bool aa)
	{
		size_t alignedPrefixSize = sizeof(RenderedFontImpl) + GP_SYSTEM_MEMORY_ALIGNMENT - 1;
		alignedPrefixSize -= alignedPrefixSize % GP_SYSTEM_MEMORY_ALIGNMENT;

		if (SIZE_MAX - alignedPrefixSize < glyphDataSize)
			return nullptr;

		const size_t allocSize = alignedPrefixSize + glyphDataSize;

		void *storage = NewPtr(allocSize);
		if (!storage)
			return nullptr;

		memset(storage, 0, allocSize);

		return new (storage) RenderedFontImpl(static_cast<uint8_t*>(storage) + alignedPrefixSize, glyphDataSize, aa);
	}

	RenderedFontImpl::RenderedFontImpl(void *data, size_t dataSize, bool aa)
		: m_data(data)
		, m_dataSize(dataSize)
		, m_isAntiAliased(aa)
	{
		memset(m_glyphMetrics, 0, sizeof(m_glyphMetrics));
		memset(&m_fontMetrics, 0, sizeof(m_fontMetrics));
		memset(m_dataOffsets, 0, sizeof(m_dataOffsets));
	}

	RenderedFontImpl::~RenderedFontImpl()
	{
	}

	bool RenderedFontImpl::LoadInternal(GpIOStream *stream, size_t dataSize)
	{
		PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance();

		if (!stream->ReadExact(m_data, m_dataSize))
			return false;

		for (size_t i = 0; i < sizeof(m_dataOffsets) / sizeof(m_dataOffsets[0]); i++)
		{
			BEUInt32_t dataOffset;
			if (!stream->ReadExact(&dataOffset, sizeof(dataOffset)))
				return false;

			m_dataOffsets[i] = dataOffset;
		}

		for (size_t i = 0; i < sizeof(m_glyphMetrics) / sizeof(m_glyphMetrics[0]); i++)
		{
			SerializedGlyphMetrics glyphMetrics;
			if (!stream->ReadExact(&glyphMetrics, sizeof(glyphMetrics)))
				return false;

			m_glyphMetrics[i] = DeserializeGlyphMetrics(glyphMetrics);
		}

		SerializedFontMetrics fontMetrics;
		if (!stream->ReadExact(&fontMetrics, sizeof(fontMetrics)))
			return false;

		m_fontMetrics = DeserializeFontMetrics(fontMetrics);

		return true;
	}

	RenderedFontImpl::SerializedGlyphMetrics RenderedFontImpl::SerializeGlyphMetrics(const GpRenderedGlyphMetrics &metrics)
	{
		SerializedGlyphMetrics result;
		result.m_advanceX = metrics.m_advanceX;
		result.m_bearingX = metrics.m_bearingX;
		result.m_bearingY = metrics.m_bearingY;
		result.m_glyphDataPitch = static_cast<uint32_t>(metrics.m_glyphDataPitch);
		result.m_glyphHeight = metrics.m_glyphHeight;
		result.m_glyphWidth = metrics.m_glyphWidth;
		result.m_bitmapOffsetX = metrics.m_bitmapOffsetX;
		result.m_bitmapOffsetY = metrics.m_bitmapOffsetY;

		return result;
	}

	GpRenderedGlyphMetrics RenderedFontImpl::DeserializeGlyphMetrics(const SerializedGlyphMetrics &metrics)
	{
		GpRenderedGlyphMetrics result;
		result.m_advanceX = metrics.m_advanceX;
		result.m_bearingX = metrics.m_bearingX;
		result.m_bearingY = metrics.m_bearingY;
		result.m_glyphDataPitch = static_cast<uint32_t>(metrics.m_glyphDataPitch);
		result.m_glyphHeight = metrics.m_glyphHeight;
		result.m_glyphWidth = metrics.m_glyphWidth;
		result.m_bitmapOffsetX = metrics.m_bitmapOffsetX;
		result.m_bitmapOffsetY = metrics.m_bitmapOffsetY;

		return result;
	}

	RenderedFontImpl::SerializedFontMetrics RenderedFontImpl::SerializeFontMetrics(const GpRenderedFontMetrics &metrics)
	{
		SerializedFontMetrics result;
		result.m_ascent = metrics.m_ascent;
		result.m_descent = metrics.m_descent;
		result.m_linegap = metrics.m_linegap;

		return result;
	}

	GpRenderedFontMetrics RenderedFontImpl::DeserializeFontMetrics(const SerializedFontMetrics &metrics)
	{
		GpRenderedFontMetrics result;
		result.m_ascent = metrics.m_ascent;
		result.m_descent = metrics.m_descent;
		result.m_linegap = metrics.m_linegap;

		return result;
	}


	RenderedFont *FontRendererImpl::RenderFont(IGpFont *font, int size, bool aa, FontHacks fontHacks)
	{
		const unsigned int numCharacters = 256;

		if (size < 1)
			return nullptr;

		int32_t lineSpacing;
		if (!font->GetLineSpacing(size, lineSpacing))
			return nullptr;

		IGpFontRenderedGlyph *glyphs[numCharacters];

		for (unsigned int i = 0; i < numCharacters; i++)
			glyphs[i] = nullptr;

		bool isSyntheticBold = false;
		if (fontHacks == FontHacks_SyntheticBold_OpenSans)
			isSyntheticBold = true;

		unsigned int xScale = 1;
		unsigned int yScale = 1;
		bool syntheticBoldAA = false;
		if (isSyntheticBold)
		{
			if (aa)
			{
				syntheticBoldAA = true;
				xScale = 8;
				yScale = 8;
			}
		}

		for (unsigned int i = 0; i < numCharacters; i++)
		{
			uint16_t unicodeCodePoint = MacRoman::ToUnicode(i);
			if (unicodeCodePoint == 0xffff)
				continue;

			glyphs[i] = font->Render(unicodeCodePoint, size, xScale, yScale, aa);
		}

		if (isSyntheticBold)
		{
			if (syntheticBoldAA)
			{
				for (unsigned int i = 0; i < numCharacters; i++)
				{
					if (glyphs[i])
						SynthesizeBoldAA(glyphs[i], xScale, yScale, syntheticBoldAA, i, size, fontHacks);
				}
			}
		}

		size_t glyphDataSize = GP_SYSTEM_MEMORY_ALIGNMENT;	// So we can use 0 to mean no data
		size_t numUsedGlyphs = 0;
		for (unsigned int i = 0; i < numCharacters; i++)
		{
			if (glyphs[i])
			{
				const GpRenderedGlyphMetrics &metrics = glyphs[i]->GetMetrics();
				glyphDataSize += metrics.m_glyphDataPitch * metrics.m_glyphHeight;
			}
		}

		RenderedFontImpl *rfont = RenderedFontImpl::Create(glyphDataSize, aa);
		if (rfont)
		{
			size_t fillOffset = GP_SYSTEM_MEMORY_ALIGNMENT;

			size_t numUsedGlyphs = 0;
			for (unsigned int i = 0; i < numCharacters; i++)
			{
				if (glyphs[i])
				{
					IGpFontRenderedGlyph *glyph = glyphs[i];
					
					GpRenderedGlyphMetrics metrics = glyph->GetMetrics();
					const void *data = glyph->GetData();

					if (fontHacks == FontHacks_Roboto && !aa)
					{
						if (size < 32)
						{
							// 'r' is shifted up 1 pixel
							if (i == 'r' && size < 32)
							{
								metrics.m_bearingY--;
							}

							// ':' doesn't have enough spacing
							if (i == ':')
							{
								metrics.m_bearingX++;
								metrics.m_advanceX++;
							}
						}
					}

					/*
					if (fontHacks == FontHacks_SyntheticBold_OpenSans && size == 12)
					{
						if (i == 'i')
							metrics.m_bearingX++;
					}

					if (fontHacks == FontHacks_SyntheticBold_OpenSans && size == 9)
					{
						if (i == 'V')
							metrics.m_advanceX++;
					}
					*/

					rfont->SetCharData(i, data, fillOffset, metrics);

					fillOffset += metrics.m_glyphDataPitch * metrics.m_glyphHeight;
				}
			}
		}

		// Compute metrics
		GpRenderedFontMetrics fontMetrics;
		fontMetrics.m_linegap = lineSpacing;
		fontMetrics.m_ascent = 0;
		fontMetrics.m_descent = 0;

		bool measuredAnyGlyphs = false;
		for (char capChar = 'A'; capChar <= 'Z'; capChar++)
		{
			const GpRenderedGlyphMetrics *glyphMetrics;
			const void *glyphData;
			if (rfont->GetGlyph(static_cast<unsigned int>(capChar), glyphMetrics, glyphData) && glyphMetrics != nullptr)
			{
				const int32_t ascent = glyphMetrics->m_bearingY;
				const int32_t descent = static_cast<int32_t>(glyphMetrics->m_glyphHeight) - ascent;

				if (!measuredAnyGlyphs)
				{
					fontMetrics.m_ascent = ascent;
					fontMetrics.m_descent = descent;
					measuredAnyGlyphs = true;
				}
				else
				{
					if (ascent > fontMetrics.m_ascent)
						fontMetrics.m_ascent = ascent;

					if (descent > fontMetrics.m_descent)
						fontMetrics.m_descent = descent;
				}
			}
		}

		rfont->SetFontMetrics(fontMetrics);

		for (unsigned int i = 0; i < numCharacters; i++)
		{
			if (glyphs[i])
				glyphs[i]->Destroy();
		}

		return rfont;
	}

	RenderedFont *FontRendererImpl::LoadCache(GpIOStream *stream)
	{
		return RenderedFontImpl::Load(stream);
	}

	bool FontRendererImpl::SaveCache(const RenderedFont *rfont, GpIOStream *stream)
	{
		if (!static_cast<const RenderedFontImpl*>(rfont)->Save(stream))
			return false;

		return true;
	}

	void FontRendererImpl::SynthesizeBoldAA(IGpFontRenderedGlyph *&glyph, unsigned int xScale, unsigned int yScale, bool aa, uint8_t character, int size, FontHacks fontHacks)
	{
		unsigned int extraWidth = 1;

		GpRenderedGlyphMetrics metrics = glyph->GetMetrics();
		const void *existingData = glyph->GetData();

		uint32_t existingWidth = metrics.m_glyphWidth;
		uint32_t existingHeight = metrics.m_glyphHeight;

		uint32_t leftPadding = 0;
		uint32_t topPadding = 0;

		{
			const int32_t leftCoord = metrics.m_bitmapOffsetX;
			int32_t leftCoordRemainder = leftCoord % static_cast<int32_t>(xScale);

			if (leftCoordRemainder > 0)
				leftPadding = leftCoordRemainder;
			else if (leftCoordRemainder < 0)
				leftPadding = leftCoordRemainder + static_cast<int32_t>(xScale);

			const int32_t topCoord = metrics.m_bitmapOffsetY;
			int32_t topCoordRemainder = topCoord % static_cast<int32_t>(yScale);

			if (topCoordRemainder != 0)
			{
				if (topCoordRemainder < 0)
					topCoordRemainder += static_cast<int32_t>(yScale);

				topPadding = static_cast<int32_t>(yScale) - topCoordRemainder;
			}
		}

		uint32_t paddedWidth = existingWidth + leftPadding;
		uint32_t paddedHeight = existingHeight + topPadding;

		uint32_t newWidth = (paddedWidth + xScale - 1) / xScale + extraWidth;
		uint32_t newHeight = (paddedHeight + 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 + static_cast<int16_t>(extraWidth);
		newMetrics.m_bearingX = (metrics.m_bitmapOffsetX - static_cast<int16_t>(leftPadding)) / static_cast<int16_t>(xScale);
		newMetrics.m_bearingY = (metrics.m_bitmapOffsetY + static_cast<int16_t>(topPadding)) / static_cast<int16_t>(yScale);
		newMetrics.m_bitmapOffsetX = newMetrics.m_bearingX;
		newMetrics.m_bitmapOffsetY = newMetrics.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++)
			{
				uint32_t originalY = subY + outY * yScale;
				if (originalY < topPadding)
					continue;

				originalY -= topPadding;
				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 unpaddedOriginalX = 0; unpaddedOriginalX < newWidth * xScale; unpaddedOriginalX++)
				{
					if (unpaddedOriginalX > leftPadding)
					{
						uint32_t originalX = unpaddedOriginalX - leftPadding;

						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;
	}

	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();
	}
}
