diff --git a/drape/drape_common.pri b/drape/drape_common.pri index 827abd80a2..3c96a890e2 100644 --- a/drape/drape_common.pri +++ b/drape/drape_common.pri @@ -39,6 +39,7 @@ SOURCES += \ $$DRAPE_DIR/texture_of_colors.cpp \ $$DRAPE_DIR/uniform_value.cpp \ $$DRAPE_DIR/uniform_values_storage.cpp \ + $$DRAPE_DIR/utils/glyph_usage_tracker.cpp \ $$DRAPE_DIR/utils/gpu_mem_tracker.cpp \ $$DRAPE_DIR/utils/projection.cpp \ $$DRAPE_DIR/utils/vertex_decl.cpp \ @@ -91,6 +92,7 @@ HEADERS += \ $$DRAPE_DIR/texture_of_colors.hpp \ $$DRAPE_DIR/uniform_value.hpp \ $$DRAPE_DIR/uniform_values_storage.hpp \ + $$DRAPE_DIR/utils/glyph_usage_tracker.hpp \ $$DRAPE_DIR/utils/gpu_mem_tracker.hpp \ $$DRAPE_DIR/utils/projection.hpp \ $$DRAPE_DIR/utils/vertex_decl.hpp \ diff --git a/drape/texture_manager.cpp b/drape/texture_manager.cpp index 8f2447c79c..81d2279a2c 100644 --- a/drape/texture_manager.cpp +++ b/drape/texture_manager.cpp @@ -3,8 +3,8 @@ #include "drape/font_texture.hpp" #include "drape/stipple_pen_resource.hpp" #include "drape/texture_of_colors.hpp" - #include "drape/glfunctions.hpp" +#include "drape/utils/glyph_usage_tracker.hpp" #include "platform/platform.hpp" @@ -140,7 +140,9 @@ size_t TextureManager::FindCharGroup(strings::UniChar const & c) { return g.m_endChar < c; }); - ASSERT(iter != m_glyphGroups.end(), ()); + if (iter == m_glyphGroups.end()) + return INVALID_GLYPH_GROUP; + return distance(m_glyphGroups.begin(), iter); } @@ -162,10 +164,22 @@ void TextureManager::FillResultBuffer(strings::UniString const & text, GlyphGrou bool TextureManager::CheckCharGroup(strings::UniChar const & c, size_t & groupIndex) { size_t currentIndex = FindCharGroup(c); + if (currentIndex == INVALID_GLYPH_GROUP) + { +#if defined(TRACK_GLYPH_USAGE) + GlyphUsageTracker::Instance().AddInvalidGlyph(c); +#endif + groupIndex = INVALID_GLYPH_GROUP; + return false; + } + if (groupIndex == INVALID_GLYPH_GROUP) groupIndex = currentIndex; else if (groupIndex != currentIndex) { +#if defined(TRACK_GLYPH_USAGE) + GlyphUsageTracker::Instance().AddUnexpectedGlyph(c, currentIndex, groupIndex); +#endif groupIndex = INVALID_GLYPH_GROUP; return false; } diff --git a/drape/utils/glyph_usage_tracker.cpp b/drape/utils/glyph_usage_tracker.cpp new file mode 100644 index 0000000000..71ef19452f --- /dev/null +++ b/drape/utils/glyph_usage_tracker.cpp @@ -0,0 +1,77 @@ +#include "glyph_usage_tracker.hpp" + +#include "../../base/assert.hpp" +#include "../../std/sstream.hpp" +#include "../../platform/preferred_languages.hpp" + +namespace dp +{ + +GlyphUsageTracker & GlyphUsageTracker::Instance() +{ + static GlyphUsageTracker s_inst; + return s_inst; +} + +string GlyphUsageTracker::Report() +{ + lock_guard lock(m_mutex); + + ostringstream ss; + ss << "\n ===== Glyphs Usage Report ===== \n"; + ss << " Current language = " << languages::GetCurrentOrig() << "\n"; + ss << " Invalid glyphs count = " << m_invalidGlyphs.size() << "\n"; + ss << " Invalid glyphs: { "; + for (auto const & it : m_invalidGlyphs) + ss << it.first << "(" << it.second << ") "; + ss << "}\n"; + + ss << " Unexpected glyphs count = " << m_unexpectedGlyphs.size() << "\n"; + ss << " Unexpected glyphs: {\n"; + for (auto const & it : m_unexpectedGlyphs) + { + ss << " glyph = " << it.first << ", usages = " << it.second.counter << ", group = " << it.second.group << ", expected groups = { "; + for (auto const & gr : it.second.expectedGroups) + ss << gr << " "; + ss << "}\n"; + } + ss << " }\n"; + ss << " ===== Glyphs Usage Report ===== \n"; + + return ss.str(); +} + +void GlyphUsageTracker::AddInvalidGlyph(strings::UniChar const & c) +{ + lock_guard lock(m_mutex); + + auto it = m_invalidGlyphs.find(c); + if (it != m_invalidGlyphs.end()) + it->second++; + else + m_invalidGlyphs.insert(make_pair(c, 1)); +} + +void GlyphUsageTracker::AddUnexpectedGlyph(strings::UniChar const & c, size_t const group, size_t const expectedGroup) +{ + lock_guard lock(m_mutex); + + auto it = m_unexpectedGlyphs.find(c); + if (it != m_unexpectedGlyphs.end()) + { + ASSERT(it->second.group == group, ("")); + it->second.counter++; + if (it->second.expectedGroups.find(expectedGroup) == it->second.expectedGroups.end()) + it->second.expectedGroups.emplace(expectedGroup); + } + else + { + UnexpectedGlyphData data; + data.group = group; + data.expectedGroups.emplace(expectedGroup); + data.counter = 1; + m_unexpectedGlyphs.insert(make_pair(c, data)); + } +} + +} // namespace dp diff --git a/drape/utils/glyph_usage_tracker.hpp b/drape/utils/glyph_usage_tracker.hpp new file mode 100644 index 0000000000..5514857f27 --- /dev/null +++ b/drape/utils/glyph_usage_tracker.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include "../../base/string_utils.hpp" +#include "../../std/map.hpp" +#include "../../std/set.hpp" +#include "../../std/list.hpp" +#include "../../std/mutex.hpp" + +#define TRACK_GLYPH_USAGE + +namespace dp +{ + +class GlyphUsageTracker +{ +public: + static GlyphUsageTracker & Instance(); + + void AddInvalidGlyph(strings::UniChar const & c); + void AddUnexpectedGlyph(strings::UniChar const & c, size_t const group, size_t const expectedGroup); + + string Report(); + + +private: + GlyphUsageTracker() = default; + GlyphUsageTracker(GlyphUsageTracker const & rhs) = delete; + GlyphUsageTracker(GlyphUsageTracker && rhs) = delete; + +private: + using InvalidGlyphs = map; + InvalidGlyphs m_invalidGlyphs; + + struct UnexpectedGlyphData + { + size_t counter; + size_t group; + set expectedGroups; + }; + using UnexpectedGlyphs = map; + UnexpectedGlyphs m_unexpectedGlyphs; + + mutex m_mutex; +}; + +} // namespace dp diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index b7648274b1..0d88af821c 100644 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -3,6 +3,7 @@ #include "drape_frontend/visual_params.hpp" #include "drape_frontend/user_mark_shapes.hpp" +#include "drape/utils/glyph_usage_tracker.hpp" #include "drape/utils/gpu_mem_tracker.hpp" #include "drape/utils/projection.hpp" @@ -84,6 +85,10 @@ void FrontendRenderer::AfterDrawFrame() #if defined(TRACK_GPU_MEM) string report = dp::GPUMemTracker::Inst().Report(); LOG(LINFO, (report)); +#endif +#if defined(TRACK_GLYPH_USAGE) + string glyphReport = dp::GlyphUsageTracker::Instance().Report(); + LOG(LINFO, (glyphReport)); #endif } } diff --git a/platform/preferred_languages.cpp b/platform/preferred_languages.cpp index c931a98cc9..780bee41ed 100644 --- a/platform/preferred_languages.cpp +++ b/platform/preferred_languages.cpp @@ -49,7 +49,7 @@ void GetSystemPreferred(vector & languages) { #if defined(OMIM_OS_MAC) || defined(OMIM_OS_IPHONE) // Mac and iOS implementation - CFArrayRef langs = CFLocaleCopyPreferredLanguages(); + /*CFArrayRef langs = CFLocaleCopyPreferredLanguages(); char buf[30]; for (CFIndex i = 0; i < CFArrayGetCount(langs); ++i) { @@ -57,7 +57,8 @@ void GetSystemPreferred(vector & languages) CFStringGetCString(strRef, buf, 30, kCFStringEncodingUTF8); languages.push_back(buf); } - CFRelease(langs); + CFRelease(langs);*/ + languages.emplace_back("zh"); #elif defined(OMIM_OS_WINDOWS) // if we're on Vista or above, take list of preferred languages