#pragma once #include "drape/pointers.hpp" #include "drape/texture.hpp" #include "drape/glyph_manager.hpp" #include "drape/dynamic_texture.hpp" #include "std/atomic.hpp" #include "std/condition_variable.hpp" #include "std/list.hpp" #include "std/map.hpp" #include "std/vector.hpp" #include "std/string.hpp" #include "std/thread.hpp" namespace dp { class GlyphPacker { public: GlyphPacker(m2::PointU const & size); bool PackGlyph(uint32_t width, uint32_t height, m2::RectU & rect); bool CanBePacked(uint32_t glyphsCount, uint32_t width, uint32_t height) const; m2::RectF MapTextureCoords(m2::RectU const & pixelRect) const; bool IsFull() const; private: m2::PointU m_size = m2::PointU(0, 0); m2::PointU m_cursor = m2::PointU(0, 0); uint32_t m_yStep = 0; bool m_isFull = false; }; class GlyphKey : public Texture::Key { public: GlyphKey(strings::UniChar unicodePoint) : m_unicodePoint(unicodePoint) {} Texture::ResourceType GetType() const { return Texture::Glyph; } strings::UniChar GetUnicodePoint() const { return m_unicodePoint; } private: strings::UniChar m_unicodePoint; }; class GlyphInfo : public Texture::ResourceInfo { typedef Texture::ResourceInfo TBase; public: GlyphInfo(m2::RectF const & texRect, GlyphManager::GlyphMetrics const & metrics) : TBase(texRect) , m_metrics(metrics) {} virtual Texture::ResourceType GetType() const { return Texture::Glyph; } GlyphManager::GlyphMetrics const & GetMetrics() const { return m_metrics; } private: GlyphManager::GlyphMetrics m_metrics; }; class GlyphGenerator { public: using TCompletionHandler = function; struct GlyphGenerationData { m2::RectU m_rect; GlyphManager::Glyph m_glyph; GlyphGenerationData(m2::RectU const & rect, GlyphManager::Glyph const & glyph) : m_rect(rect), m_glyph(glyph) {} }; GlyphGenerator(ref_ptr mng, TCompletionHandler const & completionHandler); ~GlyphGenerator(); void GenerateGlyph(m2::RectU const & rect, GlyphManager::Glyph const & glyph); bool IsSuspended() const; private: static void Routine(GlyphGenerator * generator); void WaitForGlyph(list & queue); ref_ptr m_mng; TCompletionHandler m_completionHandler; list m_queue; mutable mutex m_queueLock; atomic m_isRunning; condition_variable m_condition; bool m_isSuspended; thread m_thread; }; class GlyphIndex { public: GlyphIndex(m2::PointU size, ref_ptr mng); ~GlyphIndex(); // This function can return nullptr. ref_ptr MapResource(GlyphKey const & key, bool & newResource); void UploadResources(ref_ptr texture); bool CanBeGlyphPacked(uint32_t glyphsCount) const; bool HasAsyncRoutines() const; uint32_t GetAbsentGlyphsCount(strings::UniString const & text) const; // ONLY for unit-tests. DO NOT use this function anywhere else. size_t GetPendingNodesCount(); private: void OnGlyphGenerationCompletion(m2::RectU const & rect, GlyphManager::Glyph const & glyph); GlyphPacker m_packer; ref_ptr m_mng; unique_ptr m_generator; typedef map TResourceMapping; typedef pair TPendingNode; typedef vector TPendingNodes; TResourceMapping m_index; TPendingNodes m_pendingNodes; threads::Mutex m_lock; }; class FontTexture : public DynamicTexture { typedef DynamicTexture TBase; public: FontTexture(m2::PointU const & size, ref_ptr glyphMng, ref_ptr allocator) : m_index(size, glyphMng) { TBase::TextureParams params; params.m_size = size; params.m_format = TextureFormat::ALPHA; params.m_filter = gl_const::GLLinear; vector initData(params.m_size.x * params.m_size.y, 0); TBase::Init(allocator, make_ref(&m_index), params, make_ref(initData.data())); } ~FontTexture() { TBase::Reset(); } bool HasEnoughSpace(uint32_t newKeysCount) const override { return m_index.CanBeGlyphPacked(newKeysCount); } bool HasAsyncRoutines() const override { return m_index.HasAsyncRoutines(); } uint32_t GetAbsentGlyphsCount(strings::UniString const & text) const { return m_index.GetAbsentGlyphsCount(text); } private: GlyphIndex m_index; }; }