From 9e5b9a663d2c45626db07f24b40ca0d4301b9b30 Mon Sep 17 00:00:00 2001 From: "r.kuznetsov" Date: Wed, 14 Oct 2015 18:19:39 +0300 Subject: [PATCH] Improved glyphs appearing --- drape/font_texture.cpp | 26 +++++- drape/glyph_manager.cpp | 122 ++++++++++++++++++++----- drape/glyph_manager.hpp | 12 ++- drape/texture_manager.cpp | 14 ++- drape/texture_manager.hpp | 3 + drape_frontend/gui/button.cpp | 2 +- drape_frontend/gui/button.hpp | 4 +- drape_frontend/gui/copyright_label.cpp | 24 +++-- drape_frontend/gui/country_status.cpp | 30 +++--- drape_frontend/gui/gui_text.cpp | 67 +++++++++++++- drape_frontend/gui/gui_text.hpp | 47 ++++++++-- drape_frontend/gui/layer_render.cpp | 10 +- drape_frontend/gui/ruler.cpp | 18 ++-- drape_frontend/gui/shape.cpp | 4 +- drape_frontend/path_text_shape.cpp | 12 ++- drape_frontend/text_handle.cpp | 27 +++++- drape_frontend/text_handle.hpp | 22 ++++- drape_frontend/text_layout.cpp | 6 ++ drape_frontend/text_layout.hpp | 3 + drape_frontend/text_shape.cpp | 10 +- 20 files changed, 368 insertions(+), 95 deletions(-) diff --git a/drape/font_texture.cpp b/drape/font_texture.cpp index 0dd228d1c3..ea2bacbbd9 100644 --- a/drape/font_texture.cpp +++ b/drape/font_texture.cpp @@ -143,7 +143,12 @@ GlyphIndex::GlyphIndex(m2::PointU size, ref_ptr mng) : m_packer(size) , m_mng(mng) , m_generator(new GlyphGenerator(mng, bind(&GlyphIndex::OnGlyphGenerationCompletion, this, _1, _2))) -{} +{ + // Cache invalid glyph. + GlyphKey const key = GlyphKey(m_mng->GetInvalidGlyph().m_code); + bool newResource = false; + MapResource(key, newResource); +} GlyphIndex::~GlyphIndex() { @@ -173,6 +178,12 @@ ref_ptr GlyphIndex::MapResource(GlyphKey const & key, boo if (!m_packer.PackGlyph(glyph.m_image.m_width, glyph.m_image.m_height, r)) { glyph.m_image.Destroy(); + LOG(LWARNING, ("Glyphs packer could not pack a glyph", uniChar)); + + auto invalidGlyph = m_index.find(m_mng->GetInvalidGlyph().m_code); + if (invalidGlyph != m_index.end()) + return make_ref(&invalidGlyph->second); + return nullptr; } @@ -190,9 +201,6 @@ bool GlyphIndex::HasAsyncRoutines() const void GlyphIndex::OnGlyphGenerationCompletion(m2::RectU const & rect, GlyphManager::Glyph const & glyph) { - if (!glyph.m_image.m_data) - return; - threads::MutexGuard g(m_lock); m_pendingNodes.emplace_back(rect, glyph); } @@ -208,6 +216,16 @@ void GlyphIndex::UploadResources(ref_ptr texture) m_pendingNodes.swap(pendingNodes); } + for (auto it = pendingNodes.begin(); it != pendingNodes.end();) + { + m_mng->MarkGlyphReady(it->second); + + if (!it->second.m_image.m_data) + it = pendingNodes.erase(it); + else + ++it; + } + buffer_vector ranges; buffer_vector maxHeights; ranges.push_back(0); diff --git a/drape/glyph_manager.cpp b/drape/glyph_manager.cpp index a75eb7fe74..432b929fe8 100644 --- a/drape/glyph_manager.cpp +++ b/drape/glyph_manager.cpp @@ -10,6 +10,10 @@ #include "base/math.hpp" #include "base/timer.hpp" +#include "std/mutex.hpp" +#include "std/unique_ptr.hpp" +#include "std/unordered_set.hpp" + #include #include FT_TYPES_H #include FT_SYSTEM_H @@ -61,6 +65,7 @@ namespace { uint32_t const kSdfBorder = 4; +int const kInvalidFont = -1; template void ParseUniBlocks(string const & uniBlocksFile, ToDo toDo) @@ -205,6 +210,8 @@ public: true }; + result.m_code = unicodePoint; + FT_Done_Glyph(glyph); return result; @@ -217,6 +224,7 @@ public: GlyphManager::Glyph resultGlyph; resultGlyph.m_metrics = glyph.m_metrics; resultGlyph.m_fontIndex = glyph.m_fontIndex; + resultGlyph.m_code = glyph.m_code; sdf_image::SdfImage img(glyph.m_image.m_bitmapRows, glyph.m_image.m_bitmapPitch, glyph.m_image.m_data->data(), m_sdfScale * kSdfBorder); @@ -263,11 +271,23 @@ public: static void Close(FT_Stream){} + void MarkGlyphReady(strings::UniChar code) + { + m_readyGlyphs.insert(code); + } + + bool IsGlyphReady(strings::UniChar code) const + { + return m_readyGlyphs.find(code) != m_readyGlyphs.end(); + } + private: ReaderPtr m_fontReader; FT_StreamRec_ m_stream; FT_Face m_fontFace; uint32_t m_sdfScale; + + unordered_set m_readyGlyphs; }; } @@ -326,7 +346,7 @@ struct GlyphManager::Impl FT_Library m_library; TUniBlocks m_blocks; TUniBlockIter m_lastUsedBlock; - vector m_fonts; + vector> m_fonts; uint32_t m_baseGlyphHeight; }; @@ -377,8 +397,8 @@ GlyphManager::GlyphManager(GlyphManager::Params const & params) vector charCodes; try { - m_impl->m_fonts.emplace_back(params.m_sdfScale, GetPlatform().GetReader(fontName), m_impl->m_library); - m_impl->m_fonts.back().GetCharcodes(charCodes); + m_impl->m_fonts.emplace_back(make_unique(params.m_sdfScale, GetPlatform().GetReader(fontName), m_impl->m_library)); + m_impl->m_fonts.back()->GetCharcodes(charCodes); } catch(RootException const & e) { @@ -455,18 +475,20 @@ GlyphManager::GlyphManager(GlyphManager::Params const & params) GlyphManager::~GlyphManager() { - for (Font & f : m_impl->m_fonts) - f.DestroyFont(); + for (unique_ptr const & f : m_impl->m_fonts) + f->DestroyFont(); FREETYPE_CHECK(FT_Done_FreeType(m_impl->m_library)); delete m_impl; } -GlyphManager::Glyph GlyphManager::GetGlyph(strings::UniChar unicodePoint) +int GlyphManager::GetFontIndex(strings::UniChar unicodePoint) { TUniBlockIter iter = m_impl->m_blocks.end(); if (m_impl->m_lastUsedBlock != m_impl->m_blocks.end() && m_impl->m_lastUsedBlock->HasSymbol(unicodePoint)) + { iter = m_impl->m_lastUsedBlock; + } else { if (iter == m_impl->m_blocks.end() || !iter->HasSymbol(unicodePoint)) @@ -480,39 +502,65 @@ GlyphManager::Glyph GlyphManager::GetGlyph(strings::UniChar unicodePoint) } if (iter == m_impl->m_blocks.end() || !iter->HasSymbol(unicodePoint)) - return GetInvalidGlyph(); + return kInvalidFont; m_impl->m_lastUsedBlock = iter; - int fontIndex = -1; - UnicodeBlock const & block = *iter; + return FindFontIndexInBlock(*m_impl->m_lastUsedBlock, unicodePoint); +} + +int GlyphManager::GetFontIndexImmutable(strings::UniChar unicodePoint) const +{ + TUniBlockIter iter = lower_bound(m_impl->m_blocks.begin(), m_impl->m_blocks.end(), unicodePoint, + [](UnicodeBlock const & block, strings::UniChar const & v) + { + return block.m_end < v; + }); + + if (iter == m_impl->m_blocks.end() || !iter->HasSymbol(unicodePoint)) + return kInvalidFont; + + return FindFontIndexInBlock(*iter, unicodePoint); +} + +int GlyphManager::FindFontIndexInBlock(UnicodeBlock const & block, strings::UniChar unicodePoint) const +{ + int fontIndex = kInvalidFont; ASSERT(block.HasSymbol(unicodePoint), ()); do { - if (fontIndex != -1) + if (fontIndex != kInvalidFont) { ASSERT_LESS(fontIndex, m_impl->m_fonts.size(), ()); - Font const & f = m_impl->m_fonts[fontIndex]; - if (f.HasGlyph(unicodePoint)) - { - Glyph glyph = f.GetGlyph(unicodePoint, m_impl->m_baseGlyphHeight); - glyph.m_fontIndex = fontIndex; - return glyph; - } + unique_ptr const & f = m_impl->m_fonts[fontIndex]; + if (f->HasGlyph(unicodePoint)) + return fontIndex; } - fontIndex = block.GetFontOffset(fontIndex); - } while(fontIndex != -1); + } + while(fontIndex != kInvalidFont); - return GetInvalidGlyph(); + return kInvalidFont; +} + +GlyphManager::Glyph GlyphManager::GetGlyph(strings::UniChar unicodePoint) +{ + int const fontIndex = GetFontIndex(unicodePoint); + if (fontIndex == kInvalidFont) + return GetInvalidGlyph(); + + unique_ptr const & f = m_impl->m_fonts[fontIndex]; + Glyph glyph = f->GetGlyph(unicodePoint, m_impl->m_baseGlyphHeight); + glyph.m_fontIndex = fontIndex; + return glyph; } GlyphManager::Glyph GlyphManager::GenerateGlyph(Glyph const & glyph) const { ASSERT_NOT_EQUAL(glyph.m_fontIndex, -1, ()); ASSERT_LESS(glyph.m_fontIndex, m_impl->m_fonts.size(), ()); - Font const & f = m_impl->m_fonts[glyph.m_fontIndex]; - return f.GenerateGlyph(glyph); + unique_ptr const & f = m_impl->m_fonts[glyph.m_fontIndex]; + return f->GenerateGlyph(glyph); } void GlyphManager::ForEachUnicodeBlock(GlyphManager::TUniBlockCallback const & fn) const @@ -521,17 +569,43 @@ void GlyphManager::ForEachUnicodeBlock(GlyphManager::TUniBlockCallback const & f fn(uni.m_start, uni.m_end); } +void GlyphManager::MarkGlyphReady(Glyph const & glyph) +{ + ASSERT_GREATER_OR_EQUAL(glyph.m_fontIndex, 0, ()); + ASSERT_LESS(glyph.m_fontIndex, m_impl->m_fonts.size(), ()); + m_impl->m_fonts[glyph.m_fontIndex]->MarkGlyphReady(glyph.m_code); +} + +bool GlyphManager::AreGlyphsReady(strings::UniString const & str) const +{ + for (strings::UniChar const & code : str) + { + int const fontIndex = GetFontIndexImmutable(code); + if (fontIndex == kInvalidFont) + continue; + + if (!m_impl->m_fonts[fontIndex]->IsGlyphReady(code)) + return false; + } + + return true; +} + GlyphManager::Glyph GlyphManager::GetInvalidGlyph() const { + strings::UniChar const kInvalidGlyphCode = 0x9; + int const kFontId = 0; + static bool s_inited = false; static Glyph s_glyph; if (!s_inited) { ASSERT(!m_impl->m_fonts.empty(), ()); - s_glyph = m_impl->m_fonts[0].GetGlyph(0x9, m_impl->m_baseGlyphHeight); + s_glyph = m_impl->m_fonts[kFontId]->GetGlyph(kInvalidGlyphCode, m_impl->m_baseGlyphHeight); s_glyph.m_metrics.m_isValid = false; - s_glyph.m_fontIndex = 0; + s_glyph.m_fontIndex = kFontId; + s_glyph.m_code = kInvalidGlyphCode; s_inited = true; } diff --git a/drape/glyph_manager.hpp b/drape/glyph_manager.hpp index 4b1d64218d..52d6fe90e5 100644 --- a/drape/glyph_manager.hpp +++ b/drape/glyph_manager.hpp @@ -12,6 +12,8 @@ namespace dp { +struct UnicodeBlock; + class GlyphManager { public: @@ -66,6 +68,7 @@ public: GlyphMetrics m_metrics; GlyphImage m_image; int m_fontIndex; + strings::UniChar m_code; }; GlyphManager(Params const & params); @@ -74,12 +77,19 @@ public: Glyph GetGlyph(strings::UniChar unicodePoints); Glyph GenerateGlyph(Glyph const & glyph) const; + void MarkGlyphReady(Glyph const & glyph); + bool AreGlyphsReady(strings::UniString const & str) const; + typedef function TUniBlockCallback; void ForEachUnicodeBlock(TUniBlockCallback const & fn) const; -private: Glyph GetInvalidGlyph() const; +private: + int GetFontIndex(strings::UniChar unicodePoint); + int GetFontIndexImmutable(strings::UniChar unicodePoint) const; + int FindFontIndexInBlock(UnicodeBlock const & block, strings::UniChar unicodePoint) const; + private: struct Impl; Impl * m_impl; diff --git a/drape/texture_manager.cpp b/drape/texture_manager.cpp index a9e890cf6b..32a6e53de5 100644 --- a/drape/texture_manager.cpp +++ b/drape/texture_manager.cpp @@ -21,7 +21,7 @@ namespace dp { -uint32_t const kMaxTextureSize = 512; +uint32_t const kMaxTextureSize = 1024; uint32_t const kStippleTextureWidth = 512; uint32_t const kMinStippleTextureHeight = 64; uint32_t const kMinColorTextureSize = 32; @@ -33,6 +33,9 @@ size_t const kDuplicatedGlyphsCount = 128; size_t const kReservedPatterns = 10; size_t const kReservedColors = 20; +float const kGlyphAreaMultiplier = 1.2; +float const kGlyphAreaCoverage = 0.9; + namespace { @@ -410,11 +413,11 @@ void TextureManager::Init(Params const & params) m_glyphManager = make_unique_dp(params.m_glyphMngParams); uint32_t const textureSquare = m_maxTextureSize * m_maxTextureSize; - uint32_t const baseGlyphHeight = params.m_glyphMngParams.m_baseGlyphHeight; + uint32_t const baseGlyphHeight = params.m_glyphMngParams.m_baseGlyphHeight * kGlyphAreaMultiplier; uint32_t const avarageGlyphSquare = baseGlyphHeight * baseGlyphHeight; m_glyphGroups.push_back(GlyphGroup()); - m_maxGlypsCount = ceil(0.9 * textureSquare / avarageGlyphSquare); + m_maxGlypsCount = ceil(kGlyphAreaCoverage * textureSquare / avarageGlyphSquare); m_glyphManager->ForEachUnicodeBlock([this](strings::UniChar const & start, strings::UniChar const & end) { if (m_glyphGroups.empty()) @@ -465,6 +468,11 @@ void TextureManager::GetGlyphRegions(strings::UniString const & text, TGlyphsBuf CalcGlyphRegions(text, regions); } +bool TextureManager::AreGlyphsReady(strings::UniString const & str) const +{ + return m_glyphManager->AreGlyphsReady(str); +} + constexpr size_t TextureManager::GetInvalidGlyphGroup() { return kInvalidGlyphGroup; diff --git a/drape/texture_manager.hpp b/drape/texture_manager.hpp index fae9e77f52..68404b20d1 100644 --- a/drape/texture_manager.hpp +++ b/drape/texture_manager.hpp @@ -98,6 +98,9 @@ public: /// If you implement some kind of dynamic texture, you must synchronyze UploadData and index creation operations bool UpdateDynamicTextures(); + /// This method must be called only on Frontend renderer's thread. + bool AreGlyphsReady(strings::UniString const & str) const; + private: struct GlyphGroup { diff --git a/drape_frontend/gui/button.cpp b/drape_frontend/gui/button.cpp index ced96fb880..26c8c194e0 100644 --- a/drape_frontend/gui/button.cpp +++ b/drape_frontend/gui/button.cpp @@ -175,7 +175,7 @@ void Button::Draw(Params const & params, ShapeControl & control, ref_ptr; using THandleCreator = function; + using TLabelHandleCreator = function; struct Params { @@ -59,7 +61,7 @@ public: float m_facet = 0.0f; THandleCreator m_bodyHandleCreator; - THandleCreator m_labelHandleCreator; + TLabelHandleCreator m_labelHandleCreator; }; static void Draw(Params const & params, ShapeControl & control, ref_ptr texMgr); diff --git a/drape_frontend/gui/copyright_label.cpp b/drape_frontend/gui/copyright_label.cpp index 49b2a8bfe9..81d405c706 100644 --- a/drape_frontend/gui/copyright_label.cpp +++ b/drape_frontend/gui/copyright_label.cpp @@ -15,15 +15,18 @@ namespace gui namespace { - double const COPYRIGHT_VISIBLE_TIME = 3.0f; - double const COPYRIGHT_HIDE_DURATION = 0.25f; + double const kCopyrightVisibleTime = 2.0f; + double const kCopyrightHideTime = 0.25f; - class CopyrightHandle : public Handle + class CopyrightHandle : public StaticLabelHandle { - using TBase = Handle; + using TBase = StaticLabelHandle; + public: - CopyrightHandle(dp::Anchor anchor, m2::PointF const & pivot, m2::PointF const & size) - : TBase(anchor, pivot, size) + CopyrightHandle(ref_ptr textureManager, + dp::Anchor anchor, m2::PointF const & pivot, + m2::PointF const & size, TAlphabet const & alphabet) + : TBase(textureManager, anchor, pivot, size, alphabet) { SetIsVisible(true); } @@ -33,10 +36,11 @@ namespace if (!IsVisible()) return false; - TBase::Update(screen); + if (!TBase::Update(screen)) + return false; if (m_animation == nullptr) - m_animation.reset(new df::OpacityAnimation(COPYRIGHT_HIDE_DURATION, COPYRIGHT_VISIBLE_TIME, 1.0f, 0.0f)); + m_animation.reset(new df::OpacityAnimation(kCopyrightHideTime, kCopyrightVisibleTime, 1.0f, 0.0f)); else if (m_animation->IsFinished()) { DrapeGui::Instance().DeactivateCopyright(); @@ -73,7 +77,9 @@ drape_ptr CopyrightLabel::Draw(m2::PointF & size, ref_ptr handle = make_unique_dp(m_position.m_anchor, m_position.m_pixelPivot, size); + drape_ptr handle = make_unique_dp(tex, m_position.m_anchor, + m_position.m_pixelPivot, size, + result.m_alphabet); drape_ptr renderer = make_unique_dp(); dp::Batcher batcher(indexCount, vertexCount); diff --git a/drape_frontend/gui/country_status.cpp b/drape_frontend/gui/country_status.cpp index a3a0fe3ee5..2636d43b69 100644 --- a/drape_frontend/gui/country_status.cpp +++ b/drape_frontend/gui/country_status.cpp @@ -47,14 +47,16 @@ private: Shape::TTapHandler m_tapHandler; }; -class CountryStatusLabelHandle : public Handle +class CountryStatusLabelHandle : public StaticLabelHandle { - using TBase = Handle; + using TBase = StaticLabelHandle; public: CountryStatusLabelHandle(CountryStatusHelper::ECountryState const state, - dp::Anchor anchor, m2::PointF const & size) - : TBase(anchor, m2::PointF::Zero(), size) + ref_ptr textureManager, + dp::Anchor anchor, m2::PointF const & size, + TAlphabet const & alphabet) + : TBase(textureManager, anchor, m2::PointF::Zero(), size, alphabet) , m_state(state) {} @@ -73,8 +75,9 @@ class CountryProgressHandle : public MutableLabelHandle using TBase = MutableLabelHandle; public: - CountryProgressHandle(dp::Anchor anchor, CountryStatusHelper::ECountryState const state) - : TBase(anchor, m2::PointF::Zero()), m_state(state) + CountryProgressHandle(dp::Anchor anchor, CountryStatusHelper::ECountryState const state, + ref_ptr textures) + : TBase(anchor, m2::PointF::Zero(), textures), m_state(state) {} bool Update(ScreenBase const & screen) override @@ -100,10 +103,11 @@ drape_ptr CreateButtonHandle(CountryStatusHelper::ECountrySta } drape_ptr CreateLabelHandle(CountryStatusHelper::ECountryState const state, - dp::Anchor anchor, - m2::PointF const & size) + ref_ptr textureManager, + dp::Anchor anchor, m2::PointF const & size, + TAlphabet const & alphabet) { - return make_unique_dp(state, anchor, size); + return make_unique_dp(state, textureManager, anchor, size, alphabet); } void DrawLabelControl(string const & text, dp::Anchor anchor, dp::Batcher::TFlushFn const & flushFn, @@ -123,7 +127,7 @@ void DrawLabelControl(string const & text, dp::Anchor anchor, dp::Batcher::TFlus dp::Batcher batcher(indexCount, vertexCount); dp::SessionGuard guard(batcher, flushFn); m2::PointF size(result.m_boundRect.SizeX(), result.m_boundRect.SizeY()); - drape_ptr handle = make_unique_dp(state, anchor, size); + drape_ptr handle = make_unique_dp(state, mng, anchor, size, result.m_alphabet); batcher.InsertListOfStrip(result.m_state, make_ref(&provider), move(handle), dp::Batcher::VertexPerQuad); } @@ -138,9 +142,9 @@ void DrawProgressControl(dp::Anchor anchor, dp::Batcher::TFlushFn const & flushF params.m_anchor = anchor; params.m_pivot = m2::PointF::Zero(); params.m_font = dp::FontDecl(dp::Color::Black(), 18); - params.m_handleCreator = [state](dp::Anchor anchor, m2::PointF const & /*pivot*/) + params.m_handleCreator = [state, mng](dp::Anchor anchor, m2::PointF const & /*pivot*/) { - return make_unique_dp(anchor, state); + return make_unique_dp(anchor, state, mng); }; MutableLabelDrawer::Draw(params, mng, flushFn); @@ -191,7 +195,7 @@ drape_ptr CountryStatus::Draw(ref_ptr tex, auto const buttonHandlerIt = buttonHandlers.find(control.m_buttonType); Shape::TTapHandler buttonHandler = (buttonHandlerIt != buttonHandlers.end() ? buttonHandlerIt->second : nullptr); params.m_bodyHandleCreator = bind(&CreateButtonHandle, state, buttonHandler, color, pressedColor, _1, _2); - params.m_labelHandleCreator = bind(&CreateLabelHandle, state, _1, _2); + params.m_labelHandleCreator = bind(&CreateLabelHandle, state, tex, _1, _2, _3); Button::Draw(params, shapeControl, tex); renderer->AddShapeControl(move(shapeControl)); diff --git a/drape_frontend/gui/gui_text.cpp b/drape_frontend/gui/gui_text.cpp index 07a3130a3a..cff0f5b8bc 100644 --- a/drape_frontend/gui/gui_text.cpp +++ b/drape_frontend/gui/gui_text.cpp @@ -125,6 +125,10 @@ void StaticLabel::CacheStaticText(string const & text, char const * delim, ASSERT(!textParts.empty(), ()); + for (strings::UniString const & str : textParts) + for (strings::UniChar const & c : str) + result.m_alphabet.insert(c); + dp::TextureManager::TMultilineGlyphsBuffer buffers; mng->GetGlyphRegions(textParts, buffers); @@ -437,10 +441,20 @@ m2::PointF MutableLabel::GetAvarageSize() const } MutableLabelHandle::MutableLabelHandle(dp::Anchor anchor, m2::PointF const & pivot) - : TBase(anchor, pivot, m2::PointF::Zero()) - , m_textView(make_unique_dp(anchor)) -{ -} + : TBase(anchor, pivot, m2::PointF::Zero()) + , m_textView(make_unique_dp(anchor)) + , m_isContentDirty(true) + , m_glyphsReady(false) +{} + +MutableLabelHandle::MutableLabelHandle(dp::Anchor anchor, m2::PointF const & pivot, + ref_ptr textures) + : TBase(anchor, pivot, m2::PointF::Zero()) + , m_textView(make_unique_dp(anchor)) + , m_isContentDirty(true) + , m_textureManager(textures) + , m_glyphsReady(false) +{} void MutableLabelHandle::GetAttributeMutation(ref_ptr mutator, ScreenBase const & screen) const @@ -470,6 +484,28 @@ void MutableLabelHandle::GetAttributeMutation(ref_ptrAddMutation(offsetNode.first, mutateNode); } +bool MutableLabelHandle::Update(ScreenBase const & screen) +{ + if (!m_glyphsReady) + { + strings::UniString alphabetStr; + for (auto const & node : m_textView->GetAlphabet()) + alphabetStr.push_back(node.first); + + m_glyphsReady = m_textureManager->AreGlyphsReady(alphabetStr); + } + + if (!m_glyphsReady) + return false; + + return TBase::Update(screen); +} + +void MutableLabelHandle::SetTextureManager(ref_ptr textures) +{ + m_textureManager = textures; +} + ref_ptr MutableLabelHandle::GetTextView() { return make_ref(m_textView); @@ -535,4 +571,27 @@ m2::PointF MutableLabelDrawer::Draw(Params const & params, ref_ptr textureManager, + dp::Anchor anchor, m2::PointF const & pivot, + m2::PointF const & size, + TAlphabet const & alphabet) + : TBase(anchor, pivot, size) + , m_textureManager(textureManager) + , m_glyphsReady(false) +{ + for (strings::UniChar const & c : alphabet) + m_alphabet.push_back(c); +} + +bool StaticLabelHandle::Update(ScreenBase const & screen) +{ + if (!m_glyphsReady) + m_glyphsReady = m_textureManager->AreGlyphsReady(m_alphabet); + + if (!m_glyphsReady) + return false; + + return TBase::Update(screen); +} + } diff --git a/drape_frontend/gui/gui_text.hpp b/drape_frontend/gui/gui_text.hpp index dd9523a6e9..55e1d94973 100644 --- a/drape_frontend/gui/gui_text.hpp +++ b/drape_frontend/gui/gui_text.hpp @@ -9,11 +9,14 @@ #include "drape/texture_manager.hpp" #include "std/cstdint.hpp" +#include "std/unordered_set.hpp" #include "std/utility.hpp" namespace gui { +using TAlphabet = unordered_set; + class StaticLabel { public: @@ -47,16 +50,14 @@ public: dp::GLState m_state; buffer_vector m_buffer; m2::RectF m_boundRect; + TAlphabet m_alphabet; }; - /// return pixelSize of text static void CacheStaticText(string const & text, char const * delim, - dp::Anchor anchor, dp::FontDecl const & font, - ref_ptr mng, LabelResult & result); + dp::Anchor anchor, dp::FontDecl const & font, + ref_ptr mng, LabelResult & result); }; -//////////////////////////////////////////////////////////////////////////////////////////////// - class MutableLabel { public: @@ -122,6 +123,11 @@ public: void SetText(LabelResult & result, string text) const; m2::PointF GetAvarageSize() const; + using TAlphabetNode = pair; + using TAlphabet = vector; + + TAlphabet const & GetAlphabet() const { return m_alphabet; } + private: void SetMaxLength(uint16_t maxLength); ref_ptr SetAlphabet(string const & alphabet, ref_ptr mng); @@ -131,32 +137,38 @@ private: uint16_t m_maxLength = 0; float m_textRatio = 0.0f; - typedef pair TAlphabetNode; - typedef vector TAlphabet; TAlphabet m_alphabet; }; class MutableLabelHandle : public Handle { - typedef Handle TBase; + using TBase = Handle; public: MutableLabelHandle(dp::Anchor anchor, m2::PointF const & pivot); + MutableLabelHandle(dp::Anchor anchor, m2::PointF const & pivot, + ref_ptr textures); + void GetAttributeMutation(ref_ptr mutator, ScreenBase const & screen) const override; + bool Update(ScreenBase const & screen) override; + ref_ptr GetTextView(); void UpdateSize(m2::PointF const & size); protected: void SetContent(string && content); void SetContent(string const & content); + void SetTextureManager(ref_ptr textures); private: drape_ptr m_textView; mutable bool m_isContentDirty; string m_content; + ref_ptr m_textureManager; + bool m_glyphsReady; }; class MutableLabelDrawer @@ -179,4 +191,23 @@ public: static m2::PointF Draw(Params const & params, ref_ptr mng, dp::Batcher::TFlushFn const & flushFn); }; + +class StaticLabelHandle : public Handle +{ + using TBase = Handle; + +public: + StaticLabelHandle(ref_ptr textureManager, + dp::Anchor anchor, m2::PointF const & pivot, + m2::PointF const & size, + TAlphabet const & alphabet); + + bool Update(ScreenBase const & screen) override; + +private: + strings::UniString m_alphabet; + ref_ptr m_textureManager; + bool m_glyphsReady; +}; + } diff --git a/drape_frontend/gui/layer_render.cpp b/drape_frontend/gui/layer_render.cpp index d5725b4851..c75f1675fa 100644 --- a/drape_frontend/gui/layer_render.cpp +++ b/drape_frontend/gui/layer_render.cpp @@ -112,8 +112,6 @@ void LayerRenderer::OnTouchCancel(m2::RectD const & touchArea) } } -//////////////////////////////////////////////////////////////////////////////////// - namespace { @@ -121,8 +119,8 @@ class ScaleLabelHandle : public MutableLabelHandle { using TBase = MutableLabelHandle; public: - ScaleLabelHandle() - : TBase(dp::LeftBottom, m2::PointF::Zero()) + ScaleLabelHandle(ref_ptr textures) + : TBase(dp::LeftBottom, m2::PointF::Zero(), textures) , m_scale(0) { SetIsVisible(true); @@ -236,9 +234,9 @@ m2::PointF LayerCacher::CacheScaleLabel(Position const & position, ref_ptr(); + return make_unique_dp(textures); }; drape_ptr scaleRenderer = make_unique_dp(); diff --git a/drape_frontend/gui/ruler.cpp b/drape_frontend/gui/ruler.cpp index 1767d4a7c3..bd16d3fefd 100644 --- a/drape_frontend/gui/ruler.cpp +++ b/drape_frontend/gui/ruler.cpp @@ -84,13 +84,13 @@ public: } } - TBase::Update(screen); + bool const result = TBase::Update(screen); UpdateImpl(screen, helper); if (m_animation.IsFinished()) TBase::SetIsVisible(m_isVisibleAtEnd); - return true; + return result; } protected: @@ -108,11 +108,11 @@ private: class RulerHandle : public BaseRulerHandle { using TBase = BaseRulerHandle; + public: RulerHandle(dp::Anchor anchor, m2::PointF const & pivot, bool appearing) - : BaseRulerHandle(anchor, pivot, appearing) - { - } + : TBase(anchor, pivot, appearing) + {} private: void UpdateImpl(ScreenBase const & screen, RulerHelper const & helper) override @@ -133,10 +133,12 @@ class RulerTextHandle : public BaseRulerHandle using TBase = BaseRulerHandle; public: - RulerTextHandle(dp::Anchor anchor, m2::PointF const & pivot, bool isAppearing) + RulerTextHandle(dp::Anchor anchor, m2::PointF const & pivot, bool isAppearing, + ref_ptr textures) : TBase(anchor, pivot, isAppearing) , m_firstUpdate(true) { + SetTextureManager(textures); } bool Update(ScreenBase const & screen) override @@ -240,9 +242,9 @@ void Ruler::DrawText(m2::PointF & size, ShapeControl & control, ref_ptr(anchor, pivot, isAppearing); + return make_unique_dp(anchor, pivot, isAppearing, tex); }; m2::PointF textSize = MutableLabelDrawer::Draw(params, tex, bind(&ShapeControl::AddShape, &control, _1, _2)); diff --git a/drape_frontend/gui/shape.cpp b/drape_frontend/gui/shape.cpp index cda00ef9f4..3fb652564a 100644 --- a/drape_frontend/gui/shape.cpp +++ b/drape_frontend/gui/shape.cpp @@ -98,7 +98,9 @@ void ShapeRenderer::Render(ScreenBase const & screen, ref_ptrUpdate(screen); + if (!info.m_handle->Update(screen)) + return; + if (!info.m_handle->IsVisible()) return; diff --git a/drape_frontend/path_text_shape.cpp b/drape_frontend/path_text_shape.cpp index 06c8fb8204..e5ce930ae3 100644 --- a/drape_frontend/path_text_shape.cpp +++ b/drape_frontend/path_text_shape.cpp @@ -31,9 +31,9 @@ class PathTextHandle : public df::TextHandle public: PathTextHandle(m2::SharedSpline const & spl, df::SharedTextLayout const & layout, - float const mercatorOffset, - float const depth) - : TextHandle(FeatureID(), dp::Center, depth) + float const mercatorOffset, float const depth, + ref_ptr textureManager) + : TextHandle(FeatureID(), layout->GetText(), dp::Center, depth, textureManager) , m_spline(spl) , m_layout(layout) { @@ -44,6 +44,9 @@ public: bool Update(ScreenBase const & screen) override { + if (!df::TextHandle::Update(screen)) + return false; + return m_layout->CacheDynamicGeometry(m_centerPointIter, screen, m_normals); } @@ -190,7 +193,8 @@ void PathTextShape::Draw(ref_ptr batcher, ref_ptr handle = make_unique_dp(m_spline, layoutPtr, offset, m_params.m_depth); + drape_ptr handle = make_unique_dp(m_spline, layoutPtr, offset, + m_params.m_depth, textures); batcher->InsertListOfStrip(state, make_ref(&provider), move(handle), 4); } } diff --git a/drape_frontend/text_handle.cpp b/drape_frontend/text_handle.cpp index 6e4583fe55..95dcdecb65 100644 --- a/drape_frontend/text_handle.cpp +++ b/drape_frontend/text_handle.cpp @@ -1,20 +1,32 @@ #include "drape_frontend/text_handle.hpp" +#include "drape/texture_manager.hpp" + namespace df { -TextHandle::TextHandle(FeatureID const & id, dp::Anchor anchor, double priority) +TextHandle::TextHandle(FeatureID const & id, strings::UniString const & text, + dp::Anchor anchor, double priority, + ref_ptr textureManager) : OverlayHandle(id, anchor, priority) , m_forceUpdateNormals(false) , m_isLastVisible(false) + , m_text(text) + , m_textureManager(textureManager) + , m_glyphsReady(false) {} -TextHandle::TextHandle(FeatureID const & id, dp::Anchor anchor, double priority, - gpu::TTextDynamicVertexBuffer && normals) +TextHandle::TextHandle(FeatureID const & id, strings::UniString const & text, + dp::Anchor anchor, double priority, + ref_ptr textureManager, + gpu::TTextDynamicVertexBuffer && normals) : OverlayHandle(id, anchor, priority) , m_normals(move(normals)) , m_forceUpdateNormals(false) , m_isLastVisible(false) + , m_text(text) + , m_textureManager(textureManager) + , m_glyphsReady(false) {} void TextHandle::GetAttributeMutation(ref_ptr mutator, @@ -45,6 +57,15 @@ void TextHandle::GetAttributeMutation(ref_ptr mutato m_isLastVisible = isVisible; } +bool TextHandle::Update(ScreenBase const & screen) +{ + if (m_glyphsReady) + return true; + + m_glyphsReady = m_textureManager->AreGlyphsReady(m_text); + return m_glyphsReady; +} + bool TextHandle::IndexesRequired() const { return false; diff --git a/drape_frontend/text_handle.hpp b/drape_frontend/text_handle.hpp index 55d3e8a8d5..4ad61c8292 100644 --- a/drape_frontend/text_handle.hpp +++ b/drape_frontend/text_handle.hpp @@ -1,19 +1,33 @@ #pragma once #include "drape/overlay_handle.hpp" +#include "drape/pointers.hpp" #include "drape/utils/vertex_decl.hpp" +#include "base/string_utils.hpp" + +namespace dp +{ + class TextureManager; +} + namespace df { class TextHandle : public dp::OverlayHandle { public: - TextHandle(FeatureID const & id, dp::Anchor anchor, double priority); + TextHandle(FeatureID const & id, strings::UniString const & text, + dp::Anchor anchor, double priority, + ref_ptr textureManager); - TextHandle(FeatureID const & id, dp::Anchor anchor, double priority, + TextHandle(FeatureID const & id, strings::UniString const & text, + dp::Anchor anchor, double priority, + ref_ptr textureManager, gpu::TTextDynamicVertexBuffer && normals); + bool Update(ScreenBase const & screen) override; + void GetAttributeMutation(ref_ptr mutator, ScreenBase const & screen) const override; @@ -27,6 +41,10 @@ protected: private: mutable bool m_isLastVisible; + + strings::UniString m_text; + ref_ptr m_textureManager; + bool m_glyphsReady; }; diff --git a/drape_frontend/text_layout.cpp b/drape_frontend/text_layout.cpp index 97fe3250be..cad0358e4d 100644 --- a/drape_frontend/text_layout.cpp +++ b/drape_frontend/text_layout.cpp @@ -269,6 +269,7 @@ void CalculateOffsets(dp::Anchor anchor, void TextLayout::Init(strings::UniString const & text, float fontSize, ref_ptr textures) { + m_text = text; m_textSizeRatio = fontSize / BASE_HEIGHT; textures->GetGlyphRegions(text, m_metrics); } @@ -305,6 +306,11 @@ float TextLayout::GetPixelHeight() const return m_textSizeRatio * BASE_HEIGHT; } +strings::UniString const & TextLayout::GetText() const +{ + return m_text; +} + StraightTextLayout::StraightTextLayout(strings::UniString const & text, float fontSize, ref_ptr textures, dp::Anchor anchor) { diff --git a/drape_frontend/text_layout.hpp b/drape_frontend/text_layout.hpp index ccc9ea4ee2..fe3133bc6a 100644 --- a/drape_frontend/text_layout.hpp +++ b/drape_frontend/text_layout.hpp @@ -38,6 +38,8 @@ public: float GetPixelLength() const; float GetPixelHeight() const; + strings::UniString const & GetText() const; + protected: void Init(strings::UniString const & text, float fontSize, @@ -47,6 +49,7 @@ protected: typedef dp::TextureManager::GlyphRegion GlyphRegion; dp::TextureManager::TGlyphsBuffer m_metrics; + strings::UniString m_text; float m_textSizeRatio = 0.0; }; diff --git a/drape_frontend/text_shape.cpp b/drape_frontend/text_shape.cpp index 19471cf990..285f6c901f 100644 --- a/drape_frontend/text_shape.cpp +++ b/drape_frontend/text_shape.cpp @@ -22,10 +22,12 @@ namespace class StraightTextHandle : public TextHandle { public: - StraightTextHandle(FeatureID const & id, dp::Anchor anchor, glsl::vec2 const & pivot, + StraightTextHandle(FeatureID const & id, strings::UniString const & text, + dp::Anchor anchor, glsl::vec2 const & pivot, glsl::vec2 const & pxSize, glsl::vec2 const & offset, - double priority, gpu::TTextDynamicVertexBuffer && normals) - : TextHandle(id, anchor, priority, move(normals)) + double priority, ref_ptr textureManager, + gpu::TTextDynamicVertexBuffer && normals) + : TextHandle(id, text, anchor, priority, textureManager, move(normals)) , m_pivot(glsl::ToPoint(pivot)) , m_offset(glsl::ToPoint(offset)) , m_size(glsl::ToPoint(pxSize)) @@ -141,10 +143,12 @@ void TextShape::DrawSubString(StraightTextLayout const & layout, m2::PointU const & pixelSize = layout.GetPixelSize(); drape_ptr handle = make_unique_dp(m_params.m_featureID, + layout.GetText(), m_params.m_anchor, glsl::ToVec2(m_basePoint), glsl::vec2(pixelSize.x, pixelSize.y), baseOffset, m_params.m_depth, + textures, move(dynamicBuffer)); dp::AttributeProvider provider(2, staticBuffer.size());