WIP: Working on custom bookmark icons. #2795

Draft
vng wants to merge 3 commits from vng-bookmarks into master
37 changed files with 729 additions and 456 deletions

View file

@ -15,7 +15,7 @@ namespace
{
void CreateAndTestZip(std::string const & filePath, std::string const & zipPath)
{
TEST(CreateZipFromPathDeflatedAndDefaultCompression(filePath, zipPath), ());
TEST(CreateZipFromFiles({filePath}, zipPath, CompressionLevel::DefaultCompression), ());
ZipFileReader::FileList files;
ZipFileReader::FilesList(zipPath, files);

View file

@ -67,61 +67,11 @@ int GetCompressionLevel(CompressionLevel compression)
}
} // namespace
bool CreateZipFromPathDeflatedAndDefaultCompression(std::string const & filePath,
std::string const & zipFilePath)
{
// Open zip file for writing.
SCOPE_GUARD(outFileGuard, [&zipFilePath]() { base::DeleteFileX(zipFilePath); });
ZipHandle zip(zipFilePath);
if (!zip.Handle())
return false;
zip::FileInfo zipInfo = {};
CreateTMZip(zipInfo.tmz_date);
std::string fileName = base::FileNameFromFullPath(filePath);
if (!strings::IsASCIIString(fileName))
fileName = "OrganicMaps.kml";
if (zip::Code::Ok != zip::OpenNewFileInZip(zip.Handle(), fileName, zipInfo, "ZIP from OMaps",
Z_DEFLATED, Z_DEFAULT_COMPRESSION))
{
return false;
}
// Write source file into zip file.
try
{
base::FileData file(filePath, base::FileData::OP_READ);
uint64_t const fileSize = file.Size();
uint64_t currSize = 0;
std::array<char, zip::kFileBufferSize> buffer;
while (currSize < fileSize)
{
auto const toRead = std::min(buffer.size(), static_cast<size_t>(fileSize - currSize));
file.Read(currSize, buffer.data(), toRead);
if (zip::Code::Ok != zip::WriteInFileInZip(zip.Handle(), buffer, toRead))
return false;
currSize += toRead;
}
}
catch (Reader::Exception const & ex)
{
LOG(LERROR, ("Error reading file:", filePath, ex.Msg()));
return false;
}
outFileGuard.release();
return true;
}
bool CreateZipFromFiles(std::vector<std::string> const & files, std::string const & zipFilePath,
CompressionLevel compression)
bool CreateZipFromFiles(std::vector<std::string> const & filePaths, std::string const & zipFilePath,
CompressionLevel compression /* = CompressionLevel::DefaultCompression */,
std::vector<std::string> const * fileNames /* = nullptr */)
{
ASSERT(!fileNames || filePaths.size() == fileNames->size(), ());
SCOPE_GUARD(outFileGuard, [&zipFilePath]() { base::DeleteFileX(zipFilePath); });
ZipHandle zip(zipFilePath);
@ -129,19 +79,21 @@ bool CreateZipFromFiles(std::vector<std::string> const & files, std::string cons
return false;
auto const compressionLevel = GetCompressionLevel(compression);
zip::FileInfo const fileInfo = {};
zip::FileInfo zipInfo = {};
CreateTMZip(zipInfo.tmz_date);
try
{
for (auto const & filePath : files)
for (size_t i = 0; i < filePaths.size(); ++i)
{
if (zip::Code::Ok != zip::OpenNewFileInZip(zip.Handle(), filePath, fileInfo, "",
Z_DEFLATED, compressionLevel))
if (zip::Code::Ok != zip::OpenNewFileInZip(zip.Handle(), fileNames ? fileNames->at(i) : filePaths[i],
zipInfo, "ZIP from Organic Maps", Z_DEFLATED, compressionLevel))
{
return false;
}
base::FileData file(filePath, base::FileData::OP_READ);
base::FileData file(filePaths[i], base::FileData::OP_READ);
uint64_t const fileSize = file.Size();
uint64_t writtenSize = 0;
zip::Buffer buffer;

View file

@ -12,8 +12,8 @@ enum class CompressionLevel
Count
};
bool CreateZipFromPathDeflatedAndDefaultCompression(std::string const & filePath,
std::string const & zipFilePath);
bool CreateZipFromFiles(std::vector<std::string> const & files, std::string const & zipFilePath,
CompressionLevel compression = CompressionLevel::DefaultCompression);
/// @param[in] filePaths Full paths on disk to archive.
/// @param[in] fileNames Correspondent (for filePaths) file names in archive.
bool CreateZipFromFiles(std::vector<std::string> const & filePaths, std::string const & zipFilePath,
CompressionLevel compression = CompressionLevel::DefaultCompression,
std::vector<std::string> const * fileNames = nullptr);

View file

@ -72,6 +72,8 @@ set(SRC
overlay_tree.hpp
pointers.cpp
pointers.hpp
rect_packer.cpp
rect_packer.hpp
render_bucket.cpp
render_bucket.hpp
render_state.cpp

View file

@ -1,26 +1,27 @@
#include "testing/testing.hpp"
#include "drape/font_texture.hpp"
#include "drape/rect_packer.hpp"
UNIT_TEST(SimplePackTest)
{
dp::GlyphPacker packer(m2::PointU(32, 32));
dp::RectPacker packer(m2::PointU(32, 32));
m2::RectU r;
TEST(packer.PackGlyph(10, 13, r), ());
TEST(packer.Pack(10, 13, r), ());
TEST_EQUAL(r, m2::RectU(0, 0, 10, 13), ());
TEST(packer.PackGlyph(18, 8, r), ());
TEST(packer.Pack(18, 8, r), ());
TEST_EQUAL(r, m2::RectU(10, 0, 28, 8), ());
TEST(packer.PackGlyph(4, 15, r), ());
TEST(packer.Pack(4, 15, r), ());
TEST_EQUAL(r, m2::RectU(28, 0, 32, 15), ());
TEST(packer.PackGlyph(7, 10, r), ());
TEST(packer.Pack(7, 10, r), ());
TEST(!packer.IsFull(), ());
TEST_EQUAL(r, m2::RectU(0, 15, 7, 25), ());
TEST(!packer.PackGlyph(12, 18, r),());
TEST(!packer.Pack(12, 18, r),());
TEST(packer.IsFull(), ());
TEST_EQUAL(r, m2::RectU(0, 15, 7, 25), ());
}

View file

@ -15,75 +15,6 @@
namespace dp
{
GlyphPacker::GlyphPacker(const m2::PointU & size)
: m_size(size)
{}
bool GlyphPacker::PackGlyph(uint32_t width, uint32_t height, m2::RectU & rect)
{
ASSERT_LESS(width, m_size.x, ());
ASSERT_LESS(height, m_size.y, ());
if (m_cursor.x + width > m_size.x)
{
m_cursor.x = 0;
m_cursor.y += m_yStep;
m_yStep = 0;
}
if (m_cursor.y + height > m_size.y)
{
m_isFull = true;
return false;
}
rect = m2::RectU(m_cursor.x, m_cursor.y,
m_cursor.x + width, m_cursor.y + height);
m_cursor.x += width;
m_yStep = std::max(height, m_yStep);
return true;
}
bool GlyphPacker::CanBePacked(uint32_t glyphsCount, uint32_t width, uint32_t height) const
{
uint32_t x = m_cursor.x;
uint32_t y = m_cursor.y;
uint32_t step = m_yStep;
for (uint32_t i = 0; i < glyphsCount; i++)
{
if (x + width > m_size.x)
{
x = 0;
y += step;
}
if (y + height > m_size.y)
return false;
x += width;
step = std::max(height, step);
}
return true;
}
m2::RectF GlyphPacker::MapTextureCoords(const m2::RectU & pixelRect) const
{
auto const width = static_cast<float>(m_size.x);
auto const height = static_cast<float>(m_size.y);
// Half-pixel offset to eliminate artefacts on fetching from texture.
float offset = 0.0f;
if (pixelRect.SizeX() != 0 && pixelRect.SizeY() != 0)
offset = 0.5f;
return {(pixelRect.minX() + offset) / width,
(pixelRect.minY() + offset) / height,
(pixelRect.maxX() - offset) / width,
(pixelRect.maxY() - offset) / height};
}
bool GlyphPacker::IsFull() const { return m_isFull; }
GlyphIndex::GlyphIndex(m2::PointU const & size, ref_ptr<GlyphManager> mng,
ref_ptr<GlyphGenerator> generator)
@ -164,7 +95,7 @@ ref_ptr<Texture::ResourceInfo> GlyphIndex::MapResource(GlyphKey const & key, boo
GlyphManager::Glyph glyph = m_mng->GetGlyph(key.GetUnicodePoint(), key.GetFixedSize());
m2::RectU r;
if (!m_packer.PackGlyph(glyph.m_image.m_width, glyph.m_image.m_height, r))
if (!m_packer.Pack(glyph.m_image.m_width, glyph.m_image.m_height, r))
{
glyph.m_image.Destroy();
if (glyph.m_metrics.m_isValid)
@ -241,10 +172,8 @@ void GlyphIndex::UploadResources(ref_ptr<dp::GraphicsContext> context, ref_ptr<T
if (pendingNodes.empty())
return;
for (size_t i = 0; i < pendingNodes.size(); ++i)
for (auto & [rect, glyph] : pendingNodes)
{
GlyphManager::Glyph & glyph = pendingNodes[i].second;
m2::RectU const rect = pendingNodes[i].first;
m2::PointU const zeroPoint = rect.LeftBottom();
if (glyph.m_image.m_width == 0 || glyph.m_image.m_height == 0 || rect.SizeX() == 0 || rect.SizeY() == 0)
{

View file

@ -4,6 +4,7 @@
#include "drape/glyph_generator.hpp"
#include "drape/glyph_manager.hpp"
#include "drape/pointers.hpp"
#include "drape/rect_packer.hpp"
#include <atomic>
#include <map>
@ -13,23 +14,7 @@
namespace dp
{
class GlyphPacker
{
public:
explicit 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;
m2::PointU const & GetSize() const { return m_size; }
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;
};
using GlyphPacker = RectPacker;
class GlyphKey : public Texture::Key
{

70
drape/rect_packer.cpp Normal file
View file

@ -0,0 +1,70 @@
#include "rect_packer.hpp"
namespace dp
{
bool RectPacker::Pack(uint32_t width, uint32_t height, m2::RectU & rect)
{
ASSERT_LESS(width, m_size.x, ());
ASSERT_LESS(height, m_size.y, ());
if (m_cursor.x + width > m_size.x)
{
m_cursor.x = 0;
m_cursor.y += m_yStep;
m_yStep = 0;
}
if (m_cursor.y + height > m_size.y)
{
m_isFull = true;
return false;
}
rect = m2::RectU(m_cursor.x, m_cursor.y,
m_cursor.x + width, m_cursor.y + height);
m_cursor.x += width;
m_yStep = std::max(height, m_yStep);
return true;
}
bool RectPacker::CanBePacked(uint32_t glyphsCount, uint32_t width, uint32_t height) const
{
uint32_t x = m_cursor.x;
uint32_t y = m_cursor.y;
uint32_t step = m_yStep;
for (uint32_t i = 0; i < glyphsCount; i++)
{
if (x + width > m_size.x)
{
x = 0;
y += step;
}
if (y + height > m_size.y)
return false;
x += width;
step = std::max(height, step);
}
return true;
}
m2::RectF RectPacker::MapTextureCoords(const m2::RectU & pixelRect) const
{
auto const width = static_cast<float>(m_size.x);
auto const height = static_cast<float>(m_size.y);
// Half-pixel offset to eliminate artifacts on fetching from texture.
float offset = 0.0f;
if (pixelRect.SizeX() != 0 && pixelRect.SizeY() != 0)
offset = 0.5f;
return {(pixelRect.minX() + offset) / width,
(pixelRect.minY() + offset) / height,
(pixelRect.maxX() - offset) / width,
(pixelRect.maxY() - offset) / height};
}
} // namespace dp

26
drape/rect_packer.hpp Normal file
View file

@ -0,0 +1,26 @@
#pragma once
#include "geometry/rect2d.hpp"
namespace dp
{
class RectPacker
{
public:
explicit RectPacker(m2::PointU const & size) : m_size(size) {}
bool Pack(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 { return m_isFull; }
m2::PointU const & GetSize() const { return m_size; }
private:
m2::PointU m_size;
m2::PointU m_cursor{0, 0};
uint32_t m_yStep = 0;
bool m_isFull = false;
};
} // namespace dp

View file

@ -4,9 +4,10 @@
#include "platform/platform.hpp"
#include "coding/reader.hpp"
#include "coding/file_reader.hpp"
#include "coding/parse_xml.hpp"
#include "base/shared_buffer_manager.hpp"
#include "base/string_utils.hpp"
#include "3party/stb_image/stb_image.h"
@ -131,9 +132,8 @@ void LoadSymbols(std::string const & skinPathName, std::string const & textureNa
DefinitionLoader loader(definitionInserter, convertToUV);
{
ReaderPtr<Reader> reader =
GetStyleReader().GetResourceReader(textureName + ".sdf", skinPathName);
ReaderSource<ReaderPtr<Reader>> source(reader);
auto reader = GetStyleReader().GetResourceReader(textureName + ".sdf", skinPathName);
ReaderSource source(reader);
if (!ParseXML(source, loader))
{
failureHandler("Error parsing skin");
@ -145,11 +145,10 @@ void LoadSymbols(std::string const & skinPathName, std::string const & textureNa
}
{
ReaderPtr<Reader> reader =
GetStyleReader().GetResourceReader(textureName + ".png", skinPathName);
auto reader = GetStyleReader().GetResourceReader(textureName + ".png", skinPathName);
size_t const size = static_cast<size_t>(reader.Size());
rawData.resize(size);
reader.Read(0, &rawData[0], size);
reader.Read(0, rawData.data(), size);
}
}
catch (RootException & e)
@ -159,8 +158,7 @@ void LoadSymbols(std::string const & skinPathName, std::string const & textureNa
}
int w, h, bpp;
unsigned char * data =
stbi_load_from_memory(&rawData[0], static_cast<int>(rawData.size()), &w, &h, &bpp, 0);
unsigned char * data = stbi_load_from_memory(rawData.data(), static_cast<int>(rawData.size()), &w, &h, &bpp, 0);
ASSERT_EQUAL(bpp, 4, ("Incorrect symbols texture format"));
ASSERT(glm::isPowerOfTwo(w), (w));
ASSERT(glm::isPowerOfTwo(h), (h));
@ -178,29 +176,6 @@ void LoadSymbols(std::string const & skinPathName, std::string const & textureNa
}
} // namespace
SymbolsTexture::SymbolKey::SymbolKey(std::string const & symbolName)
: m_symbolName(symbolName)
{}
Texture::ResourceType SymbolsTexture::SymbolKey::GetType() const
{
return Texture::ResourceType::Symbol;
}
std::string const & SymbolsTexture::SymbolKey::GetSymbolName() const
{
return m_symbolName;
}
SymbolsTexture::SymbolInfo::SymbolInfo(const m2::RectF & texRect)
: ResourceInfo(texRect)
{}
Texture::ResourceType SymbolsTexture::SymbolInfo::GetType() const
{
return Texture::ResourceType::Symbol;
}
SymbolsTexture::SymbolsTexture(ref_ptr<dp::GraphicsContext> context, std::string const & skinPathName,
std::string const & textureName, ref_ptr<HWTextureAllocator> allocator)
: m_name(textureName)
@ -213,7 +188,7 @@ void SymbolsTexture::Load(ref_ptr<dp::GraphicsContext> context, std::string cons
{
auto definitionInserter = [this](std::string const & name, m2::RectF const & rect)
{
m_definition.insert(std::make_pair(name, SymbolsTexture::SymbolInfo(rect)));
m_definition.emplace(name, SymbolInfo(rect));
};
auto completionHandler = [this, &allocator, context](unsigned char * data, uint32_t width, uint32_t height)
@ -256,15 +231,13 @@ void SymbolsTexture::Invalidate(ref_ptr<dp::GraphicsContext> context, std::strin
ref_ptr<Texture::ResourceInfo> SymbolsTexture::FindResource(Texture::Key const & key, bool & newResource)
{
newResource = false;
if (key.GetType() != Texture::ResourceType::Symbol)
return nullptr;
ASSERT(key.GetType() == Texture::ResourceType::Symbol, ());
newResource = false;
std::string const & symbolName = static_cast<SymbolKey const &>(key).GetSymbolName();
auto it = m_definition.find(symbolName);
ASSERT(it != m_definition.end(), (symbolName));
return make_ref(&it->second);
return (it != m_definition.end() ? make_ref(&it->second) : nullptr);
}
void SymbolsTexture::Fail(ref_ptr<dp::GraphicsContext> context)
@ -280,11 +253,6 @@ void SymbolsTexture::Fail(ref_ptr<dp::GraphicsContext> context)
Create(context, p, make_ref(&alphaTexture));
}
bool SymbolsTexture::IsSymbolContained(std::string const & symbolName) const
{
return m_definition.find(symbolName) != m_definition.end();
}
bool SymbolsTexture::DecodeToMemory(std::string const & skinPathName, std::string const & textureName,
std::vector<uint8_t> & symbolsSkin,
std::map<std::string, m2::RectU> & symbolsIndex,
@ -317,4 +285,86 @@ bool SymbolsTexture::DecodeToMemory(std::string const & skinPathName, std::strin
definitionInserter, completionHandler, failureHandler);
return result;
}
bool LoadedSymbol::FromPngFile(std::string const & filePath)
{
std::vector<uint8_t> buffer;
try
{
FileReader reader(filePath);
size_t const size = static_cast<size_t>(reader.Size());
buffer.resize(size);
reader.Read(0, buffer.data(), size);
}
catch (RootException & e)
{
return false;
}
int bpp;
m_data = stbi_load_from_memory(buffer.data(), static_cast<int>(buffer.size()), &m_width, &m_height, &bpp, 0);
if (m_data && bpp == 4) // only this fits TextureFormat::RGBA8
return true;
LOG(LWARNING, ("Error loading PNG for path:", filePath, "Result:", bool(m_data != nullptr), bpp));
return false;
}
void LoadedSymbol::Free()
{
if (m_data)
{
stbi_image_free(m_data);
m_data = nullptr;
}
}
ref_ptr<Texture::ResourceInfo> SymbolsIndex::MapResource(SymbolKey const & key, bool & newResource)
{
auto const & symbolName = key.GetSymbolName();
std::lock_guard guard(m_mapping);
auto it = m_index.find(symbolName);
if (it != m_index.end())
{
newResource = false;
return make_ref(&it->second);
}
LoadedSymbol symbol;
if (!symbol.FromPngFile(symbolName))
return {};
newResource = true;
m2::RectU pixelRect;
m_packer.Pack(symbol.m_width, symbol.m_height, pixelRect);
{
std::lock_guard<std::mutex> guard(m_upload);
m_pendingNodes.emplace_back(pixelRect, std::move(symbol));
}
auto res = m_index.emplace(symbolName, SymbolInfo(m_packer.MapTextureCoords(pixelRect)));
ASSERT(res.second, ());
return make_ref(&res.first->second);
}
void SymbolsIndex::UploadResources(ref_ptr<dp::GraphicsContext> context, ref_ptr<Texture> texture)
{
TPendingNodes pendingNodes;
{
std::lock_guard<std::mutex> upload(m_upload);
if (m_pendingNodes.empty())
return;
m_pendingNodes.swap(pendingNodes);
}
for (auto const & [rect, symbol] : pendingNodes)
{
m2::PointU const zeroPoint = rect.LeftBottom();
texture->UploadData(context, zeroPoint.x, zeroPoint.y, rect.SizeX(), rect.SizeY(), make_ref(symbol.m_data));
}
}
} // namespace dp

View file

@ -1,34 +1,36 @@
#pragma once
#include "drape/texture.hpp"
#include "drape/dynamic_texture.hpp"
#include "drape/rect_packer.hpp"
#include <map>
#include <mutex>
#include <string>
#include <vector>
namespace dp
{
class SymbolKey : public Texture::Key
{
public:
explicit SymbolKey(std::string const & symbolName) : m_symbolName(symbolName) {}
Texture::ResourceType GetType() const override { return Texture::ResourceType::Symbol; }
std::string const & GetSymbolName() const { return m_symbolName; }
private:
std::string m_symbolName;
};
class SymbolInfo : public Texture::ResourceInfo
{
public:
explicit SymbolInfo(m2::RectF const & texRect) : Texture::ResourceInfo(texRect) {}
Texture::ResourceType GetType() const override { return Texture::ResourceType::Symbol; }
};
class SymbolsTexture : public Texture
{
public:
class SymbolKey : public Key
{
public:
explicit SymbolKey(std::string const & symbolName);
ResourceType GetType() const override;
std::string const & GetSymbolName() const;
private:
std::string m_symbolName;
};
class SymbolInfo : public ResourceInfo
{
public:
explicit SymbolInfo(m2::RectF const & texRect);
ResourceType GetType() const override;
};
SymbolsTexture(ref_ptr<dp::GraphicsContext> context, std::string const & skinPathName,
std::string const & textureName, ref_ptr<HWTextureAllocator> allocator);
@ -40,8 +42,6 @@ public:
ref_ptr<HWTextureAllocator> allocator,
std::vector<drape_ptr<HWTexture>> & internalTextures);
bool IsSymbolContained(std::string const & symbolName) const;
static bool DecodeToMemory(std::string const & skinPathName, std::string const & textureName,
std::vector<uint8_t> & symbolsSkin,
std::map<std::string, m2::RectU> & symbolsIndex,
@ -51,8 +51,70 @@ private:
void Load(ref_ptr<dp::GraphicsContext> context, std::string const & skinPathName,
ref_ptr<HWTextureAllocator> allocator);
using TSymDefinition = std::map<std::string, SymbolInfo>;
std::string m_name;
mutable TSymDefinition m_definition;
std::map<std::string, SymbolInfo> m_definition;
};
class LoadedSymbol
{
DISALLOW_COPY(LoadedSymbol);
public:
LoadedSymbol() = default;
LoadedSymbol(LoadedSymbol && rhs)
: m_data(rhs.m_data), m_width(rhs.m_width), m_height(rhs.m_height)
{
rhs.m_data = nullptr;
}
LoadedSymbol & operator=(LoadedSymbol &&) = delete;
~LoadedSymbol()
{
Free();
}
bool FromPngFile(std::string const & filePath);
void Free();
uint8_t * m_data = nullptr;
int m_width, m_height;
};
class SymbolsIndex
{
public:
explicit SymbolsIndex(m2::PointU const & size) : m_packer(size) {}
ref_ptr<Texture::ResourceInfo> MapResource(SymbolKey const & key, bool & newResource);
void UploadResources(ref_ptr<dp::GraphicsContext> context, ref_ptr<Texture> texture);
private:
RectPacker m_packer;
std::map<std::string, SymbolInfo> m_index;
using TPendingNodes = std::vector<std::pair<m2::RectU, LoadedSymbol>>;
TPendingNodes m_pendingNodes;
std::mutex m_upload, m_mapping;
};
class DynamicSymbolsTexture : public DynamicTexture<SymbolsIndex, SymbolKey, Texture::ResourceType::Symbol>
{
using TBase = DynamicTexture<SymbolsIndex, SymbolKey, Texture::ResourceType::Symbol>;
public:
DynamicSymbolsTexture(m2::PointU const & size, ref_ptr<HWTextureAllocator> allocator)
: m_index(size)
{
TBase::DynamicTextureParams params{size, TextureFormat::RGBA8, TextureFilter::Nearest, false /* m_usePixelBuffer */};
TBase::Init(allocator, make_ref(&m_index), params);
}
~DynamicSymbolsTexture() override { TBase::Reset(); }
private:
SymbolsIndex m_index;
};
} // namespace dp

View file

@ -26,6 +26,7 @@ namespace dp
namespace
{
uint32_t constexpr kMaxTextureSize = 1024;
uint32_t constexpr kUserSymbolsTextureSize = 512;
uint32_t constexpr kStippleTextureWidth = 512; /// @todo Should be equal with kMaxStipplePenLength?
uint32_t constexpr kMinStippleTextureHeight = 64;
uint32_t constexpr kMinColorTextureSize = 32;
@ -67,6 +68,12 @@ void ParseColorsList(std::string const & colorsFile, ToDo toDo)
}
}
m2::PointU UserSymbolsTextureSize(uint32_t maxTextureSize)
{
uint32_t const sz = std::min(kUserSymbolsTextureSize, maxTextureSize);
return {sz, sz};
}
m2::PointU StipplePenTextureSize(size_t patternsCount, uint32_t maxTextureSize)
{
uint32_t const sz = base::NextPowOf2(static_cast<uint32_t>(patternsCount) + kReservedPatterns);
@ -206,6 +213,7 @@ void TextureManager::Release()
m_hybridGlyphGroups.clear();
m_symbolTextures.clear();
m_userSymbolTexture.reset();
m_stipplePenTexture.reset();
m_colorTexture.reset();
@ -254,6 +262,9 @@ bool TextureManager::UpdateDynamicTextures(ref_ptr<dp::GraphicsContext> context)
CHECK(m_stipplePenTexture != nullptr, ());
m_stipplePenTexture->UpdateState(context);
CHECK(m_userSymbolTexture != nullptr, ());
m_userSymbolTexture->UpdateState(context);
UpdateGlyphTextures(context);
CHECK(m_textureAllocator != nullptr, ());
@ -285,15 +296,23 @@ ref_ptr<Texture> TextureManager::AllocateGlyphTexture()
return make_ref(m_glyphTextures.back());
}
void TextureManager::GetRegionBase(ref_ptr<Texture> tex, TextureManager::BaseRegion & region,
Texture::Key const & key)
bool TextureManager::GetRegionSafe(ref_ptr<Texture> tex, TextureManager::BaseRegion & region, Texture::Key const & key)
{
bool isNew = false;
region.SetResourceInfo(tex != nullptr ? tex->FindResource(key, isNew) : nullptr);
bool isNew;
auto const info = tex->FindResource(key, isNew);
if (!info)
return false;
region.SetResourceInfo(info);
region.SetTexture(tex);
ASSERT(region.IsValid(), ());
if (isNew)
m_nothingToUpload.clear();
return true;
}
void TextureManager::GetRegionBase(ref_ptr<Texture> tex, TextureManager::BaseRegion & region, Texture::Key const & key)
{
VERIFY(GetRegionSafe(tex, region, key), ());
}
void TextureManager::GetGlyphsRegions(ref_ptr<FontTexture> tex, strings::UniString const & text,
@ -410,6 +429,10 @@ void TextureManager::Init(ref_ptr<dp::GraphicsContext> context, Params const & p
make_ref(m_textureAllocator)));
}
m_userSymbolTexture = make_unique_dp<DynamicSymbolsTexture>(UserSymbolsTextureSize(m_maxTextureSize),
make_ref(m_textureAllocator));
LOG(LDEBUG, ("User symbols texture size =", m_userSymbolTexture->GetWidth(), m_userSymbolTexture->GetHeight()));
// Initialize static textures.
m_trafficArrowTexture =
make_unique_dp<StaticTexture>(context, "traffic-arrow.png", m_resPostfix,
@ -542,20 +565,33 @@ void TextureManager::GetTexturesToCleanup(std::vector<drape_ptr<HWTexture>> & te
bool TextureManager::GetSymbolRegionSafe(std::string const & symbolName, SymbolRegion & region)
{
CHECK(m_isInitialized, ());
for (size_t i = 0; i < m_symbolTextures.size(); ++i)
ASSERT(!symbolName.empty(), ());
SymbolKey const key(symbolName);
for (uint32_t i = 0; i < m_symbolTextures.size(); ++i)
{
ref_ptr<SymbolsTexture> symbolsTexture = make_ref(m_symbolTextures[i]);
ASSERT(symbolsTexture != nullptr, ());
if (symbolsTexture->IsSymbolContained(symbolName))
if (GetRegionSafe(make_ref(m_symbolTextures[i]), region, key))
{
GetRegionBase(symbolsTexture, region, SymbolsTexture::SymbolKey(symbolName));
region.SetTextureIndex(static_cast<uint32_t>(i));
region.SetTextureIndex(i);
return true;
}
}
return false;
}
bool TextureManager::GetUserSymbolRegion(std::string const & symbolName, SymbolRegion & region)
{
CHECK(m_isInitialized, ());
ASSERT(!symbolName.empty(), ());
if (GetRegionSafe(make_ref(m_userSymbolTexture), region, SymbolKey(symbolName)))
{
region.SetTextureIndex(m_symbolTextures.size());
return true;
}
return false;
}
void TextureManager::GetSymbolRegion(std::string const & symbolName, SymbolRegion & region)
{
if (!GetSymbolRegionSafe(symbolName, region))

View file

@ -92,6 +92,7 @@ public:
bool GetSymbolRegionSafe(std::string const & symbolName, SymbolRegion & region);
void GetSymbolRegion(std::string const & symbolName, SymbolRegion & region);
bool GetUserSymbolRegion(std::string const & symbolName, SymbolRegion & region);
void GetStippleRegion(PenPatternT const & pen, StippleRegion & region);
void GetColorRegion(Color const & color, ColorRegion & region);
@ -155,6 +156,7 @@ private:
uint32_t m_maxGlypsCount;
ref_ptr<Texture> AllocateGlyphTexture();
bool GetRegionSafe(ref_ptr<Texture> tex, TextureManager::BaseRegion & region, Texture::Key const & key);
void GetRegionBase(ref_ptr<Texture> tex, TextureManager::BaseRegion & region, Texture::Key const & key);
void GetGlyphsRegions(ref_ptr<FontTexture> tex, strings::UniString const & text,
@ -225,7 +227,9 @@ private:
bool m_isInitialized = false;
ref_ptr<GlyphGenerator> m_glyphGenerator;
std::string m_resPostfix;
std::vector<drape_ptr<Texture>> m_symbolTextures;
drape_ptr<Texture> m_userSymbolTexture;
drape_ptr<Texture> m_stipplePenTexture;
drape_ptr<Texture> m_colorTexture;
std::list<drape_ptr<Texture>> m_glyphTextures;

View file

@ -21,6 +21,8 @@
#include "geometry/clipping.hpp"
#include "geometry/mercator.hpp"
#include "base/file_name_utils.hpp"
#include <array>
#include <cmath>
#include <vector>
@ -118,10 +120,11 @@ std::string GetSymbolNameForZoomLevel(ref_ptr<UserPointMark::SymbolNameZoomInfo>
if (!symbolNames)
return {};
biodranik commented 2022-06-25 05:43:12 +00:00 (Migrated from github.com)
Review

Лучше it для итераторов, а i для индексов, тогда проще код читать.

Лучше it для итераторов, а i для индексов, тогда проще код читать.
for (auto itName = symbolNames->crbegin(); itName != symbolNames->crend(); ++itName)
auto const & v = symbolNames->m_zoomInfo;
for (auto it = v.crbegin(); it != v.crend(); ++it)
{
if (itName->first <= tileKey.m_zoomLevel)
return itName->second;
if (it->first <= tileKey.m_zoomLevel)
return it->second;
}
return {};
}
@ -397,24 +400,34 @@ void CacheUserMarks(ref_ptr<dp::GraphicsContext> context, TileKey const & tileKe
m2::PointD const tileCenter = tileKey.GetGlobalRect().Center();
biodranik commented 2022-06-25 05:43:41 +00:00 (Migrated from github.com)
Review

to the default

to the default
// Calculate symbol's region params.
m2::PointF symbolSize(0.0f, 0.0f);
dp::TextureManager::SymbolRegion symbolRegion;
auto const symbolName = GetSymbolNameForZoomLevel(make_ref(renderInfo.m_symbolNames), tileKey);
auto symbolName = GetSymbolNameForZoomLevel(make_ref(renderInfo.m_symbolNames), tileKey);
if (!symbolName.empty())
{
textures->GetSymbolRegion(symbolName, symbolRegion);
if (!textures->GetSymbolRegionSafe(symbolName, symbolRegion))
{
if (renderInfo.m_symbolNames->m_pathPrefix.empty() ||
!textures->GetUserSymbolRegion(base::JoinPath(renderInfo.m_symbolNames->m_pathPrefix, symbolName), symbolRegion))
{
LOG(LWARNING, ("Can't load symbol:", symbolName));
// Fallback to the default bookmark's icon if user icon's file was not loaded.
symbolName = "bookmark-default-m";
biodranik commented 2022-06-23 22:24:16 +00:00 (Migrated from github.com)
Review

Это точно нужно в релизе?

Это точно нужно в релизе?
vng commented 2022-06-28 06:43:08 +00:00 (Migrated from github.com)
Review

У нас в целом стратегия предпочтения CHECK там где не критично по производительности.
В drape это имеет смысл, потому что много зависит от зоопарка девайсов.

У нас в целом стратегия предпочтения CHECK там где не критично по производительности. В drape это имеет смысл, потому что много зависит от зоопарка девайсов.
VERIFY(textures->GetSymbolRegionSafe(symbolName, symbolRegion), ());
}
}
symbolSize = symbolRegion.GetPixelSize();
}
m2::PointF symbolOffset = m2::PointF::Zero();
m2::PointF symbolOffset(0, 0);
if (renderInfo.m_symbolIsPOI)
symbolOffset = GetSymbolOffsetForZoomLevel(make_ref(renderInfo.m_symbolOffsets), tileKey);
if (renderInfo.m_coloredSymbols != nullptr)
{
GenerateColoredSymbolShapes(context, textures, renderInfo, tileKey, tileCenter, symbolOffset, symbolSize,
batcher);
}
GenerateColoredSymbolShapes(context, textures, renderInfo, tileKey, tileCenter, symbolOffset, symbolSize, batcher);
if (!symbolName.empty())
{
@ -437,8 +450,7 @@ void CacheUserMarks(ref_ptr<dp::GraphicsContext> context, TileKey const & tileKe
m2::RectF const & bgTexRect = backgroundRegion.GetTexRect();
m2::PointF const pxSize = symbolRegion.GetPixelSize();
dp::Anchor const anchor = renderInfo.m_anchor;
m2::PointD const pt = MapShape::ConvertToLocal(renderInfo.m_pivot, tileCenter,
kShapeCoordScalar);
m2::PointD const pt = MapShape::ConvertToLocal(renderInfo.m_pivot, tileCenter, kShapeCoordScalar);
glsl::vec3 const pos = glsl::vec3(glsl::ToVec2(pt), renderInfo.m_depth);
bool const runAnim = renderInfo.m_hasCreationAnimation && renderInfo.m_justCreated;
@ -449,12 +461,12 @@ void CacheUserMarks(ref_ptr<dp::GraphicsContext> context, TileKey const & tileKe
m2::PointD const pixelOffset = renderInfo.m_pixelOffset;
glsl::vec2 const offset(pixelOffset.x, pixelOffset.y);
/// @todo Here we always have maskColor, which may conflict with custom user symbols.
dp::Color color = dp::Color::White();
if (!renderInfo.m_color.empty())
color = df::GetColorConstant(renderInfo.m_color);
glsl::vec4 maskColor(color.GetRedF(), color.GetGreenF(), color.GetBlueF(),
renderInfo.m_symbolOpacity);
glsl::vec4 const maskColor(color.GetRedF(), color.GetGreenF(), color.GetBlueF(), renderInfo.m_symbolOpacity);
float animateOrZ = 0.0f;
if (!renderInfo.m_customDepth)
animateOrZ = runAnim ? 1.0f : -1.0f;

View file

@ -38,10 +38,20 @@ struct IDCollections
class UserPointMark
{
public:
using SymbolNameZoomInfo = std::map<int, std::string>;
struct SymbolNameZoomInfo
{
std::map<int, std::string> m_zoomInfo;
// Check symbol from file if not empty.
std::string m_pathPrefix;
bool IsEmpty() const { return m_zoomInfo.empty(); }
void Emplace(int zoom, std::string name) { m_zoomInfo.emplace(zoom, std::move(name)); }
};
using TitlesInfo = std::vector<dp::TitleDecl>;
using SymbolSizes = std::vector<m2::PointF>;
using SymbolOffsets = std::vector<m2::PointF>;
struct ColoredSymbolZoomInfo
{
std::map<int, df::ColoredSymbolViewParams> m_zoomInfo;

View file

@ -73,7 +73,9 @@ fileprivate func uiColorForBookmarkColor(_ color: BookmarkColor) -> UIColor {
case .gray: return rgbColor(115, 115, 115);
case .blueGray: return rgbColor(89, 115, 128);
case .none, .count:
fatalError()
// Clear color (transparent) for custom symbols.
/// @todo Rewrite and show custom images in Bookmarls view.
return UIColor.clear
@unknown default:
fatalError()
}

View file

@ -100,8 +100,7 @@ PredefinedColor ExtractPlacemarkPredefinedColor(std::string const & s)
if (s == "#placemark-bluegray")
return PredefinedColor::BlueGray;
// Default color.
return PredefinedColor::Red;
return PredefinedColor::None;
}
std::string GetStyleForPredefinedColor(PredefinedColor color)
@ -174,8 +173,7 @@ void SaveStringWithCDATA(KmlWriter::WriterWrapper & writer, std::string s)
writer << s;
}
void SaveStyle(KmlWriter::WriterWrapper & writer, std::string const & style,
std::string_view const & indent)
void SaveStyle(KmlWriter::WriterWrapper & writer, std::string const & style, std::string_view const & indent)
{
if (style.empty())
return;
@ -183,7 +181,7 @@ void SaveStyle(KmlWriter::WriterWrapper & writer, std::string const & style,
writer << indent << kIndent2 << "<Style id=\"" << style << "\">\n"
<< indent << kIndent4 << "<IconStyle>\n"
<< indent << kIndent6 << "<Icon>\n"
<< indent << kIndent8 << "<href>https://omaps.app/placemarks/" << style << ".png</href>\n"
<< indent << kIndent8 << "<href>" << style << "</href>\n"
<< indent << kIndent6 << "</Icon>\n"
<< indent << kIndent4 << "</IconStyle>\n"
<< indent << kIndent2 << "</Style>\n";
@ -262,10 +260,6 @@ void SaveStringsMap(KmlWriter::WriterWrapper & writer,
writer << indent << "</mwm:" << tagName << ">\n";
}
void SaveCategoryData(KmlWriter::WriterWrapper & writer, CategoryData const & categoryData,
std::string const & extendedServerId,
std::vector<CategoryData> const * compilationData);
void SaveCategoryExtendedData(KmlWriter::WriterWrapper & writer, CategoryData const & categoryData,
std::string const & extendedServerId,
std::vector<CategoryData> const * compilationData)
@ -344,9 +338,8 @@ void SaveCategoryExtendedData(KmlWriter::WriterWrapper & writer, CategoryData co
if (compilationData)
{
for (auto const & compilationDatum : *compilationData)
SaveCategoryData(writer, compilationDatum, {} /* extendedServerId */,
nullptr /* compilationData */);
for (auto const & cd : *compilationData)
SaveCategoryExtendedData(writer, cd, {} /* extendedServerId */, nullptr /* compilationData */);
}
if (compilationData)
@ -357,29 +350,23 @@ void SaveCategoryExtendedData(KmlWriter::WriterWrapper & writer, CategoryData co
void SaveCategoryData(KmlWriter::WriterWrapper & writer, CategoryData const & categoryData,
std::string const & extendedServerId,
std::vector<CategoryData> const * compilationData)
std::vector<CategoryData> const & compilationData)
{
if (compilationData)
// Use CDATA if we have special symbols in the name.
writer << kIndent2 << "<name>";
SaveStringWithCDATA(writer, GetLocalizableString(categoryData.m_name, kDefaultLang));
writer << "</name>\n";
if (!categoryData.m_description.empty())
{
for (uint8_t i = 0; i < base::Underlying(PredefinedColor::Count); ++i)
SaveStyle(writer, GetStyleForPredefinedColor(static_cast<PredefinedColor>(i)), kIndent0);
// Use CDATA if we have special symbols in the name.
writer << kIndent2 << "<name>";
SaveStringWithCDATA(writer, GetLocalizableString(categoryData.m_name, kDefaultLang));
writer << "</name>\n";
if (!categoryData.m_description.empty())
{
writer << kIndent2 << "<description>";
SaveStringWithCDATA(writer, GetLocalizableString(categoryData.m_description, kDefaultLang));
writer << "</description>\n";
}
writer << kIndent2 << "<visibility>" << (categoryData.m_visible ? "1" : "0") << "</visibility>\n";
writer << kIndent2 << "<description>";
SaveStringWithCDATA(writer, GetLocalizableString(categoryData.m_description, kDefaultLang));
writer << "</description>\n";
}
SaveCategoryExtendedData(writer, categoryData, extendedServerId, compilationData);
writer << kIndent2 << "<visibility>" << (categoryData.m_visible ? "1" : "0") << "</visibility>\n";
SaveCategoryExtendedData(writer, categoryData, extendedServerId, &compilationData);
}
void SaveBookmarkExtendedData(KmlWriter::WriterWrapper & writer, BookmarkData const & bookmarkData)
@ -475,7 +462,9 @@ void SaveBookmarkData(KmlWriter::WriterWrapper & writer, BookmarkData const & bo
<< "</when></TimeStamp>\n";
}
auto const style = GetStyleForPredefinedColor(bookmarkData.m_color.m_predefinedColor);
auto style = bookmarkData.m_iconPath;
if (style.empty())
style = GetStyleForPredefinedColor(bookmarkData.m_color.m_predefinedColor);
writer << kIndent4 << "<styleUrl>#" << style << "</styleUrl>\n"
<< kIndent4 << "<Point><coordinates>" << PointToString(bookmarkData.m_point)
<< "</coordinates></Point>\n";
@ -649,9 +638,23 @@ void KmlWriter::Write(FileData const & fileData)
{
m_writer << kKmlHeader;
// Save predefined styles.
for (uint8_t i = 0; i < base::Underlying(PredefinedColor::Count); ++i)
{
auto const style = GetStyleForPredefinedColor(static_cast<PredefinedColor>(i));
if (!style.empty())
SaveStyle(m_writer, "https://omaps.app/placemarks/" + style + ".png", kIndent0);
}
// Save user styles.
for (auto const & bd : fileData.m_bookmarksData)
{
if (!bd.m_iconPath.empty())
SaveStyle(m_writer, bd.m_iconPath, kIndent0);
}
// Save category.
SaveCategoryData(m_writer, fileData.m_categoryData, fileData.m_serverId,
&fileData.m_compilationsData);
SaveCategoryData(m_writer, fileData.m_categoryData, fileData.m_serverId, fileData.m_compilationsData);
// Save bookmarks.
for (auto const & bookmarkData : fileData.m_bookmarksData)
@ -677,15 +680,18 @@ void KmlParser::ResetPoint()
m_name.clear();
m_description.clear();
m_org = {};
m_predefinedColor = PredefinedColor::None;
m_viewportScale = 0;
m_timestamp = {};
m_color = 0;
m_currStyle.Invalidate();
m_styleId.clear();
m_mapStyleId.clear();
m_styleUrlKey.clear();
m_predefinedColor = PredefinedColor::None;
m_icon = BookmarkIcon::None;
m_iconPath.clear();
m_featureTypes.clear();
m_customName.clear();
m_boundTracks.clear();
@ -695,8 +701,6 @@ void KmlParser::ResetPoint()
m_properties.clear();
m_localId = 0;
m_trackLayers.clear();
m_trackWidth = kDefaultTrackWidth;
m_icon = BookmarkIcon::None;
m_geometry.Clear();
m_geometryType = GEOMETRY_TYPE_UNKNOWN;
@ -751,13 +755,19 @@ bool KmlParser::MakeValid()
if (m_name.empty() && m_featureTypes.empty())
m_name[kDefaultLang] = PointToString(m_org);
// Set default pin.
if (m_predefinedColor == PredefinedColor::None)
if (m_predefinedColor != PredefinedColor::None)
{
// We use fixed predefined colors instead of their path like "https://omaps.app/placemarks/placemark-red.png".
m_iconPath.clear();
}
else if (m_iconPath.empty())
{
// Set default color if there is no icon path.
m_predefinedColor = PredefinedColor::Red;
}
return true;
}
return false;
}
else if (GEOMETRY_TYPE_LINE == m_geometryType)
{
@ -774,35 +784,32 @@ void KmlParser::ParseColor(std::string const & value)
return;
// Color positions in HEX aabbggrr.
m_color = ToRGBA(fromHex[3], fromHex[2], fromHex[1], fromHex[0]);
m_currStyle.color = ToRGBA(fromHex[3], fromHex[2], fromHex[1], fromHex[0]);
}
bool KmlParser::GetColorForStyle(std::string const & styleUrl, uint32_t & color) const
KmlParser::StyleParams const * KmlParser::GetStyle(std::string styleUrl) const
{
if (styleUrl.empty())
return false;
return nullptr;
// Remove leading '#' symbol
auto const it = m_styleUrl2Color.find(styleUrl.substr(1));
if (it != m_styleUrl2Color.cend())
while (true)
{
color = it->second;
return true;
// Remove leading '#' symbol
ASSERT(styleUrl[0] == '#', (styleUrl));
styleUrl = styleUrl.substr(1);
auto const it = m_styleParams.find(styleUrl);
if (it != m_styleParams.cend())
return &it->second;
auto st = m_mapStyle2Style.find(styleUrl);
if (st != m_mapStyle2Style.end())
styleUrl = st->second;
else
break;
}
return false;
}
double KmlParser::GetTrackWidthForStyle(std::string const & styleUrl) const
{
if (styleUrl.empty())
return kDefaultTrackWidth;
// Remove leading '#' symbol
auto const it = m_styleUrl2Width.find(styleUrl.substr(1));
if (it != m_styleUrl2Width.cend())
return it->second;
return kDefaultTrackWidth;
return nullptr;
}
bool KmlParser::Push(std::string movedTag)
@ -897,9 +904,13 @@ void KmlParser::Pop(std::string_view tag)
BookmarkData data;
data.m_name = std::move(m_name);
data.m_description = std::move(m_description);
data.m_color.m_predefinedColor = m_predefinedColor;
data.m_color.m_rgba = m_color;
// Standalone color is not defined for point placemark, but return style color with default black (as before).
data.m_color.m_rgba = m_currStyle.GetColor(0 /* defaultColor */);
data.m_icon = m_icon;
data.m_iconPath = std::move(m_iconPath);
data.m_viewportScale = m_viewportScale;
data.m_timestamp = m_timestamp;
data.m_point = m_org;
@ -961,10 +972,8 @@ void KmlParser::Pop(std::string_view tag)
{
if (!m_styleId.empty())
{
m_styleUrl2Color[m_styleId] = m_color;
m_styleUrl2Width[m_styleId] = m_trackWidth;
m_color = 0;
m_trackWidth = kDefaultTrackWidth;
m_styleParams[m_styleId] = m_currStyle;
m_currStyle.Invalidate();
}
}
}
@ -972,20 +981,22 @@ void KmlParser::Pop(std::string_view tag)
(tag == "mwm:additionalLineStyle" && m_tags.size() > 3 && GetTagFromEnd(3) == kPlacemark))
biodranik commented 2022-06-27 22:41:07 +00:00 (Migrated from github.com)
Review

А дефолтные треки не сломаются?

А дефолтные треки не сломаются?
vng commented 2022-06-28 07:04:53 +00:00 (Migrated from github.com)
Review

Тут функция стала полностью другая по назначению.

Тут функция стала полностью другая по назначению.
{
// This code assumes that <Style> is stored inside <Placemark>.
// It is a violation of KML format, but it must be here to support
// loading of KML files which were stored by older versions of OMaps.
// It is a violation of KML format, but it must be here to support loading of KML files which are stored by OMaps.
/// @todo By VNG: Now app writes <Style><LineStyle> into Placemark, should rewrite on <styleUrl>?
TrackLayer layer;
layer.m_lineWidth = m_trackWidth;
layer.m_lineWidth = m_currStyle.width;
layer.m_color.m_predefinedColor = PredefinedColor::None;
uint32_t color = m_currStyle.GetColor(kDefaultTrackColor);
// Fix wrongly parsed transparent color, see https://github.com/organicmaps/organicmaps/issues/5800
// TODO: Remove this fix in 2024 when all users will have their imported GPX files fixed.
if (m_color == 0 || (m_color & 0xFF) < 10)
layer.m_color.m_rgba = kDefaultTrackColor;
else
layer.m_color.m_rgba = m_color;
m_trackLayers.push_back(layer);
if (color == 0 || (color & 0xFF) < 10)
color = kDefaultTrackColor;
layer.m_color.m_rgba = color;
m_trackWidth = kDefaultTrackWidth;
m_color = 0;
m_trackLayers.push_back(std::move(layer));
m_currStyle.Invalidate();
}
else if (tag == kCompilation)
{
@ -1011,12 +1022,12 @@ void KmlParser::CharData(std::string & value)
size_t const count = m_tags.size();
if (count > 1 && !value.empty())
{
using namespace std;
string const & currTag = m_tags[count - 1];
string const & prevTag = m_tags[count - 2];
string_view const ppTag = count > 2 ? m_tags[count - 3] : string_view{};
string_view const pppTag = count > 3 ? m_tags[count - 4] : string_view{};
string_view const ppppTag = count > 4 ? m_tags[count - 5] : string_view{};
/// @todo Current parse state checking logic, based on [*p]Tag strings comparison is not a good approach.
std::string const & currTag = m_tags[count - 1];
std::string const & prevTag = m_tags[count - 2];
std::string_view const ppTag = count > 2 ? m_tags[count - 3] : std::string_view();
std::string_view const pppTag = count > 3 ? m_tags[count - 4] : std::string_view();
std::string_view const ppppTag = count > 4 ? m_tags[count - 5] : std::string_view();
auto const TrackTag = [this, &prevTag, &currTag, &value]()
{
@ -1160,18 +1171,17 @@ void KmlParser::CharData(std::string & value)
}
// Track draw style.
if (!GetColorForStyle(value, m_color))
StyleParams const * style = GetStyle(value);
if (style)
{
// Remove leading '#' symbol.
std::string const styleId = m_mapStyle2Style[value.substr(1)];
if (!styleId.empty())
GetColorForStyle(styleId, m_color);
m_iconPath = style->iconPath;
TrackLayer layer;
layer.m_lineWidth = style->width;
layer.m_color.m_predefinedColor = PredefinedColor::None;
biodranik commented 2022-06-27 22:46:28 +00:00 (Migrated from github.com)
Review
`<Style>` is [correct official format](https://developers.google.com/kml/documentation/kmlreference#style)
biodranik commented 2022-06-27 22:48:52 +00:00 (Migrated from github.com)
Review

<styleUrl> внутри <Placemark> тоже официальный формат.

`<styleUrl>` внутри `<Placemark>` тоже [официальный формат](https://developers.google.com/kml/documentation/kmlreference#placemark).
biodranik commented 2022-06-27 22:49:46 +00:00 (Migrated from github.com)
Review

А вот Style внутри Placemark уже нарушение, как пишут в комментах. Но видимо придётся поддерживать, кто ж это так накосячил...

А вот Style внутри Placemark уже нарушение, как пишут в комментах. Но видимо придётся поддерживать, кто ж это так накосячил...
vng commented 2022-06-28 07:08:55 +00:00 (Migrated from github.com)
Review

Комментарий об этом говорил и говорит.

Комментарий об этом говорил и говорит.
layer.m_color.m_rgba = style->GetColor(kDefaultTrackColor);
m_trackLayers.push_back(std::move(layer));
}
TrackLayer layer;
layer.m_lineWidth = GetTrackWidthForStyle(value);
layer.m_color.m_predefinedColor = PredefinedColor::None;
layer.m_color.m_rgba = (m_color != 0 ? m_color : kDefaultTrackColor);
m_trackLayers.push_back(std::move(layer));
}
else if (currTag == "description")
{
@ -1188,11 +1198,14 @@ void KmlParser::CharData(std::string & value)
{
double val;
if (strings::to_double(value, val))
m_trackWidth = val;
m_currStyle.width = val;
}
}
else if (ppTag == kStyleMap && prevTag == kPair && currTag == kStyleUrl &&
m_styleUrlKey == "normal")
else if (pppTag == kStyle && ppTag == "IconStyle" && prevTag == "Icon" && currTag == "href")
{
m_currStyle.iconPath = value;
}
else if (ppTag == kStyleMap && prevTag == kPair && currTag == kStyleUrl && m_styleUrlKey == "normal")
{
if (!m_mapStyleId.empty())
m_mapStyle2Style[m_mapStyleId] = value;
@ -1276,10 +1289,6 @@ void KmlParser::CharData(std::string & value)
m_timestamp = TimestampClock::from_time_t(ts);
}
}
else if (currTag == kStyleUrl)
{
GetColorForStyle(value, m_color);
}
}
else if (ppTag == "MultiGeometry")
{
@ -1354,7 +1363,7 @@ void KmlParser::CharData(std::string & value)
kml::TrackLayer KmlParser::GetDefaultTrackLayer()
{
kml::TrackLayer layer;
layer.m_lineWidth = kDefaultTrackWidth;
layer.m_lineWidth = StyleParams::kDefaultWidth;
layer.m_color.m_rgba = kDefaultTrackColor;
return layer;
}

View file

@ -97,9 +97,7 @@ private:
void ParseLineString(std::string const & s);
bool MakeValid();
void ParseColor(std::string const &value);
bool GetColorForStyle(std::string const & styleUrl, uint32_t & color) const;
double GetTrackWidthForStyle(std::string const & styleUrl) const;
void ParseColor(std::string const & value);
FileData & m_data;
CategoryData m_compilationData;
@ -108,13 +106,33 @@ private:
std::vector<std::string> m_tags;
GeometryType m_geometryType;
MultiGeometry m_geometry;
uint32_t m_color;
std::string m_styleId;
std::string m_mapStyleId;
std::string m_styleUrlKey;
std::map<std::string, uint32_t> m_styleUrl2Color;
std::map<std::string, double> m_styleUrl2Width;
struct StyleParams
{
static uint32_t constexpr kInvalidColor = uint32_t(-1);
static double constexpr kDefaultWidth = 5.0;
uint32_t color = kInvalidColor;
double width = kDefaultWidth;
std::string iconPath;
void Invalidate()
biodranik commented 2022-06-27 22:52:39 +00:00 (Migrated from github.com)
Review

Разве FFFFFFFF не белый цвет?

Разве FFFFFFFF не белый цвет?
biodranik commented 2022-06-27 22:53:26 +00:00 (Migrated from github.com)
Review

Вообще, наш invalid color это костыль, цвета или иконки по идее всегда должны быть в прилетающих к нам в kml данных.

Вообще, наш invalid color это костыль, цвета или иконки по идее всегда должны быть в прилетающих к нам в kml данных.
vng commented 2022-06-28 07:10:38 +00:00 (Migrated from github.com)
Review

Белый прозрачный - по сути нет цвета.
Не костыль, это значит цвета нет и он не проинициализирован.

Белый прозрачный - по сути нет цвета. Не костыль, это значит цвета нет и он не проинициализирован.
{
color = kInvalidColor;
width = kDefaultWidth;
iconPath.clear();
}
uint32_t GetColor(uint32_t defColor) const { return color == kInvalidColor ? defColor : color; }
};
StyleParams const * GetStyle(std::string styleUrl) const;
StyleParams m_currStyle;
std::map<std::string, StyleParams> m_styleParams;
std::map<std::string, std::string> m_mapStyle2Style;
int8_t m_attrCode;
@ -123,7 +141,11 @@ private:
LocalizableString m_name;
LocalizableString m_description;
PredefinedColor m_predefinedColor;
BookmarkIcon m_icon;
std::string m_iconPath;
Timestamp m_timestamp;
m2::PointD m_org;
uint8_t m_viewportScale;
@ -131,7 +153,6 @@ private:
LocalizableString m_customName;
std::vector<LocalId> m_boundTracks;
LocalId m_localId;
BookmarkIcon m_icon;
std::vector<TrackLayer> m_trackLayers;
bool m_visible;
std::string m_nearestToponym;
@ -139,7 +160,6 @@ private:
int m_minZoom = 1;
kml::Properties m_properties;
std::vector<CompilationId> m_compilations;
double m_trackWidth;
};
class DeserializerKml

View file

@ -262,10 +262,14 @@ struct BookmarkData
std::vector<uint32_t> m_featureTypes;
// Custom bookmark's name.
LocalizableString m_customName;
// Bookmark's color.
ColorData m_color;
// Bookmark's icon.
BookmarkIcon m_icon = BookmarkIcon::None;
// Bookmark's custom icon from file (e.g. images/icon.png).
std::string m_iconPath;
// Viewport scale. 0 is a default value (no scale set).
uint8_t m_viewportScale = 0;
// Creation timestamp.

View file

@ -50,7 +50,7 @@ drape_ptr<df::UserPointMark::SymbolNameZoomInfo> ApiMarkPoint::GetSymbolNames()
{
//TODO: use its own icon.
auto symbol = make_unique_dp<SymbolNameZoomInfo>();
symbol->insert(std::make_pair(1 /* zoomLevel */, "coloredmark-default-s"));
symbol->Emplace(1, "coloredmark-default-s");
return symbol;
}

View file

@ -103,16 +103,29 @@ dp::Anchor Bookmark::GetAnchor() const
drape_ptr<df::UserPointMark::SymbolNameZoomInfo> Bookmark::GetSymbolNames() const
{
// Order:
// - CustomImage from 'mwm:properties' (can be file icon from images)
// - File icon from images
// - bookmark-default icon as mask with further GetColorConstant()
auto symbolNames = GetCustomSymbolNames();
if (symbolNames != nullptr)
return symbolNames;
symbolNames = make_unique_dp<SymbolNameZoomInfo>();
symbolNames->insert(std::make_pair(1 /* zoomLevel */, "bookmark-default-xs"));
symbolNames->insert(std::make_pair(8 /* zoomLevel */, "bookmark-default-s"));
auto const iconType = GetBookmarkIconType(m_data.m_icon);
symbolNames->insert(std::make_pair(14 /* zoomLevel */, "bookmark-" + iconType + "-m"));
if (!m_data.m_iconPath.empty())
{
symbolNames->m_pathPrefix = GetBookmarksDirectory();
symbolNames->Emplace(1, m_data.m_iconPath);
}
else
{
symbolNames->Emplace(1, "bookmark-default-xs");
symbolNames->Emplace(8, "bookmark-default-s");
symbolNames->Emplace(14, "bookmark-" + GetBookmarkIconType(m_data.m_icon) + "-m");
}
return symbolNames;
}
@ -123,6 +136,8 @@ drape_ptr<df::UserPointMark::SymbolNameZoomInfo> Bookmark::GetCustomSymbolNames(
return nullptr;
auto symbolNames = make_unique_dp<SymbolNameZoomInfo>();
symbolNames->m_pathPrefix = GetBookmarksDirectory();
strings::Tokenize(it->second, ";", [&](std::string_view token)
{
uint8_t zoomLevel = 1;
@ -130,10 +145,10 @@ drape_ptr<df::UserPointMark::SymbolNameZoomInfo> Bookmark::GetCustomSymbolNames(
if (pos != std::string::npos && strings::to_uint(token.substr(0, pos), zoomLevel))
token = token.substr(pos + 1);
if (!token.empty() && zoomLevel >= 1 && zoomLevel <= scales::GetUpperStyleScale())
symbolNames->emplace(zoomLevel, std::string(token));
symbolNames->Emplace(zoomLevel, std::string(token));
});
if (symbolNames->empty())
if (symbolNames->IsEmpty())
return nullptr;
return symbolNames;
@ -175,6 +190,10 @@ df::ColorConstant Bookmark::GetColorConstant() const
return "BookmarkGray";
case kml::PredefinedColor::BlueGray:
return "BookmarkBlueGray";
// Default red color.
/// @todo By VNG: What will happen if user symbol will have 'mask' pixels (like bookmark-default-m.png)?
/// Looks like they will be filled with this default red color, see CacheUserMarks.
case kml::PredefinedColor::None:
case kml::PredefinedColor::Count:
return "BookmarkRed";
@ -203,7 +222,7 @@ std::string Bookmark::GetPreferredName() const
return GetPreferredBookmarkName(m_data);
}
kml::LocalizableString Bookmark::GetName() const
kml::LocalizableString const & Bookmark::GetName() const
{
return m_data.m_name;
}
@ -220,10 +239,10 @@ void Bookmark::SetName(std::string const & name, int8_t langCode)
m_data.m_name[langCode] = name;
}
std::string Bookmark::GetCustomName() const
{
return GetPreferredBookmarkStr(m_data.m_customName);
}
//std::string Bookmark::GetCustomName() const
//{
// return GetPreferredBookmarkStr(m_data.m_customName);
//}
void Bookmark::SetCustomName(std::string const & customName)
{
@ -277,9 +296,8 @@ kml::MarkGroupId Bookmark::GetGroupId() const
bool Bookmark::CanFillPlacePageMetadata() const
{
auto const & p = m_data.m_properties;
if (auto const hours = p.find("hours"); hours != p.end() && !hours->second.empty())
return true;
return false;
auto const hours = p.find("hours");
return (hours != p.end() && !hours->second.empty());
}
void Bookmark::Attach(kml::MarkGroupId groupId)

View file

@ -31,11 +31,11 @@ public:
std::string GetPreferredName() const;
kml::LocalizableString GetName() const;
kml::LocalizableString const & GetName() const;
void SetName(kml::LocalizableString const & name);
void SetName(std::string const & name, int8_t langCode);
std::string GetCustomName() const;
//std::string GetCustomName() const;
void SetCustomName(std::string const & customName);
kml::PredefinedColor GetColor() const;
@ -55,6 +55,7 @@ public:
dp::Anchor GetAnchor() const override;
drape_ptr<SymbolNameZoomInfo> GetSymbolNames() const override;
/// @return Bookmark color constant from style.mapcss.
df::ColorConstant GetColorConstant() const override;
kml::MarkGroupId GetGroupId() const override;

View file

@ -381,22 +381,33 @@ std::string GetKMLorGPXPath(std::string const & filePath)
{
ZipFileReader::FileList files;
ZipFileReader::FilesList(filePath, files);
std::string kmlFileName;
std::string ext;
for (size_t i = 0; i < files.size(); ++i)
for (auto const & [file, _] : files)
{
ext = GetLowercaseFileExt(files[i].first);
if (ext == kKmlExtension)
std::string const ext = GetLowercaseFileExt(file);
if (ext == kKmlExtension && fileSavePath.empty())
{
kmlFileName = files[i].first;
break;
fileSavePath = GenerateValidAndUniqueFilePathForKML(file);
ZipFileReader::UnzipFile(filePath, file, fileSavePath);
}
else if (ext == ".png")
{
std::string dir = base::GetDirectory(file);
if (dir != ".")
{
dir = base::JoinPath(GetBookmarksDirectory(), dir);
if (!Platform::MkDirRecursively(dir))
{
LOG(LERROR, ("Can't create folder:", dir));
continue;
}
}
else
dir = GetBookmarksDirectory();
ZipFileReader::UnzipFile(filePath, file, base::JoinPath(dir, base::FileNameFromFullPath(file)));
}
}
if (kmlFileName.empty())
return {};
fileSavePath = GenerateValidAndUniqueFilePathForKML(kmlFileName);
ZipFileReader::UnzipFile(filePath, kmlFileName, fileSavePath);
}
catch (RootException const & e)
{
@ -409,6 +420,7 @@ std::string GetKMLorGPXPath(std::string const & filePath)
LOG(LWARNING, ("Unknown file type", filePath));
return {};
}
return fileSavePath;
}

View file

@ -81,19 +81,41 @@ BookmarkManager::SharingResult GetFileForSharing(BookmarkManager::KMLDataCollect
if (fileName.empty())
fileName = base::GetNameFromFullPathWithoutExt(kmlToShare.first);
auto const filePath = base::JoinPath(GetPlatform().TmpDir(), fileName + std::string{kKmlExtension});
SCOPE_GUARD(fileGuard, std::bind(&base::DeleteFileX, filePath));
/// @todo Really needed for zip?
if (!strings::IsASCIIString(fileName))
fileName = kDefaultBookmarksFileName;
fileName.append(kKmlExtension);
auto const & tmpDir = GetPlatform().TmpDir();
std::vector<std::string> filePaths, fileNames;
fileNames.push_back(fileName);
filePaths.push_back(base::JoinPath(tmpDir, fileNames.back()));
SCOPE_GUARD(fileGuard, std::bind(&base::DeleteFileX, filePaths.back()));
auto const categoryId = kmlToShare.second->m_categoryData.m_id;
if (!SaveKmlFileSafe(*kmlToShare.second, filePath, KmlFileType::Text))
if (!SaveKmlFileSafe(*kmlToShare.second, filePaths.back(), KmlFileType::Text))
return {categoryId, BookmarkManager::SharingResult::Code::FileError, "Bookmarks file does not exist."};
auto const tmpFilePath = base::JoinPath(GetPlatform().TmpDir(), fileName + std::string{kKmzExtension});
if (!CreateZipFromPathDeflatedAndDefaultCompression(filePath, tmpFilePath))
auto const bookmarksDir = GetBookmarksDirectory();
for (auto const & bmData : kmlToShare.second->m_bookmarksData)
{
if (!bmData.m_iconPath.empty())
{
auto const path = base::JoinPath(bookmarksDir, bmData.m_iconPath);
if (Platform::IsFileExistsByFullPath(path))
{
fileNames.push_back(bmData.m_iconPath);
filePaths.push_back(std::move(path));
}
}
}
auto const kmzFilePath = base::JoinPath(tmpDir, fileName);
if (!CreateZipFromFiles(filePaths, kmzFilePath, CompressionLevel::DefaultCompression, &fileNames))
return {categoryId, BookmarkManager::SharingResult::Code::ArchiveError, "Could not create archive."};
return {categoryId, tmpFilePath};
return {categoryId, kmzFilePath};
}
std::string ToString(BookmarkManager::SortingType type)
@ -187,6 +209,20 @@ void BookmarkManager::DeleteUserMark(kml::MarkId markId)
Bookmark * BookmarkManager::CreateBookmark(kml::BookmarkData && bmData)
{
CHECK_THREAD_CHECKER(m_threadChecker, ());
if (!bmData.m_iconPath.empty())
{
// Check that user icon file is actually present.
if (!GetPlatform().IsFileExistsByFullPath(base::JoinPath(GetBookmarksDirectory(), bmData.m_iconPath)))
{
LOG(LWARNING, ("Bookmark's icon file is not exist:", bmData.m_iconPath));
bmData.m_iconPath.clear();
if (bmData.m_color.m_predefinedColor == kml::PredefinedColor::None)
bmData.m_color.m_predefinedColor = kml::PredefinedColor::Red;
}
}
return AddBookmark(std::make_unique<Bookmark>(std::move(bmData)));
}
@ -2182,7 +2218,7 @@ kml::MarkGroupId BookmarkManager::CreateBookmarkCategory(kml::CategoryData && da
return groupId;
}
kml::MarkGroupId BookmarkManager::CreateBookmarkCategory(std::string const & name, bool autoSave)
kml::MarkGroupId BookmarkManager::CreateBookmarkCategory(std::string const & name, bool autoSave /* = true */)
{
CHECK_THREAD_CHECKER(m_threadChecker, ());
auto const groupId = UserMarkIdStorage::Instance().GetNextCategoryId();
@ -2543,6 +2579,7 @@ std::unique_ptr<kml::FileData> BookmarkManager::CollectBmGroupKMLData(BookmarkCa
return kmlData;
}
/*
bool BookmarkManager::SaveBookmarkCategory(kml::MarkGroupId groupId)
{
CHECK_THREAD_CHECKER(m_threadChecker, ());
@ -2562,6 +2599,7 @@ bool BookmarkManager::SaveBookmarkCategory(kml::MarkGroupId groupId, Writer & wr
auto kmlData = CollectBmGroupKMLData(group);
return SaveKmlData(*kmlData, writer, fileType);
}
*/
BookmarkManager::KMLDataCollectionPtr BookmarkManager::PrepareToSaveBookmarks(
kml::GroupIdCollection const & groupIdCollection)

View file

@ -360,9 +360,11 @@ public:
void FilterInvalidBookmarks(kml::MarkIdCollection & bookmarks) const;
void FilterInvalidTracks(kml::TrackIdCollection & tracks) const;
/// @todo Avoid dualism with sync/async tasks. Leave async only.
void EnableTestMode(bool enable);
bool SaveBookmarkCategory(kml::MarkGroupId groupId);
bool SaveBookmarkCategory(kml::MarkGroupId groupId, Writer & writer, KmlFileType fileType) const;
// bool SaveBookmarkCategory(kml::MarkGroupId groupId);
// bool SaveBookmarkCategory(kml::MarkGroupId groupId, Writer & writer, KmlFileType fileType) const;
static void UpdateLastModifiedTime(KMLDataCollection & collection);
// Used for LoadBookmarks() and unit tests only. Does *not* update last modified time.

View file

@ -23,6 +23,7 @@ omim_add_test(${PROJECT_NAME} ${SRC} REQUIRE_QT REQUIRE_SERVER)
target_link_libraries(${PROJECT_NAME}
search_tests_support
platform_tests_support
generator_tests_support
map
)

View file

@ -211,6 +211,7 @@ UNIT_CLASS_TEST(Runner, Bookmarks_ImportKML)
TEST_EQUAL(bmManager.IsVisible(groupId), false, ());
}
/*
UNIT_CLASS_TEST(Runner, Bookmarks_ExportKML)
{
string const dir = GetBookmarksDirectory();
@ -268,7 +269,7 @@ UNIT_CLASS_TEST(Runner, Bookmarks_ExportKML)
kmlDataCollection3.emplace_back(fileName, LoadKmlFile(fileName, GetActiveKmlFileType()));
TEST(kmlDataCollection3.back().second, ());
bmManager.CreateCategories(std::move(kmlDataCollection3), true /* autoSave */);
bmManager.CreateCategories(std::move(kmlDataCollection3), true);
TEST_EQUAL(bmManager.GetBmGroupsIdList().size(), 1, ());
auto const groupId3 = bmManager.GetBmGroupsIdList().front();
@ -279,6 +280,7 @@ UNIT_CLASS_TEST(Runner, Bookmarks_ExportKML)
uint64_t dummy;
TEST(base::GetFileSize(fileName, dummy), ());
}
*/
namespace
{
@ -967,12 +969,13 @@ UNIT_CLASS_TEST(Runner, Bookmarks_InnerFolder)
TEST_EQUAL(bmManager.GetUserMarkIds(groupIds.front()).size(), 1, ());
}
/*
UNIT_CLASS_TEST(Runner, BookmarkCategory_EmptyName)
{
BookmarkManager bmManager(BM_CALLBACKS);
bmManager.EnableTestMode(true);
auto const catId = bmManager.CreateBookmarkCategory("", false /* autoSave */);
auto const catId = bmManager.CreateBookmarkCategory("", false);
kml::BookmarkData bm;
bm.m_point = m2::PointD(0, 0);
bmManager.GetEditSession().CreateBookmark(std::move(bm), catId);
@ -986,6 +989,7 @@ UNIT_CLASS_TEST(Runner, BookmarkCategory_EmptyName)
vector<string> const arrFiles = {"Bookmarks", "xxx"};
DeleteCategoryFiles(arrFiles);
}
*/
namespace
{
@ -1046,6 +1050,7 @@ UNIT_CLASS_TEST(Runner, Bookmarks_SpecialXMLNames)
expectedName = "test";
bmManager.GetEditSession().SetCategoryName(catId, expectedName);
/*
TEST(bmManager.SaveBookmarkCategory(catId), ());
auto const fileName = bmManager.GetCategoryFileName(catId);
@ -1055,12 +1060,11 @@ UNIT_CLASS_TEST(Runner, Bookmarks_SpecialXMLNames)
bmManager.GetEditSession().DeleteBmCategory(catId);
BookmarkManager::KMLDataCollection kmlDataCollection2;
kmlDataCollection2.emplace_back("" /* filePath */, LoadKmlFile(fileNameTmp, GetActiveKmlFileType()));
kmlDataCollection2.emplace_back("", LoadKmlFile(fileNameTmp, GetActiveKmlFileType()));
bmManager.CreateCategories(std::move(kmlDataCollection2));
BookmarkManager::KMLDataCollection kmlDataCollection3;
kmlDataCollection3.emplace_back("" /* filePath */,
LoadKmlData(MemReader(kmlString3, strlen(kmlString3)), KmlFileType::Text));
kmlDataCollection3.emplace_back("", LoadKmlData(MemReader(kmlString3, strlen(kmlString3)), KmlFileType::Text));
bmManager.UpdateLastModifiedTime(kmlDataCollection3);
bmManager.CreateCategories(std::move(kmlDataCollection3));
@ -1081,6 +1085,7 @@ UNIT_CLASS_TEST(Runner, Bookmarks_SpecialXMLNames)
TEST_EQUAL(kml::GetDefaultStr(bm1->GetName()), "![X1]{X2}(X3)", ());
TEST(base::DeleteFileX(fileNameTmp), ());
*/
}
UNIT_CLASS_TEST(Runner, TrackParsingTest_1)

View file

@ -3,39 +3,61 @@
#include "map/bookmark_helpers.hpp"
biodranik commented 2022-06-27 23:01:40 +00:00 (Migrated from github.com)
Review

Эти тесты поудаляют другие десктопные метки для работы/других кейзов?

Эти тесты поудаляют другие десктопные метки для работы/других кейзов?
vng commented 2022-06-28 07:21:02 +00:00 (Migrated from github.com)
Review

Да, тут стоит пересмотреть логику.

Да, тут стоит пересмотреть логику.
#include "platform/platform.hpp"
#include "platform/platform_tests_support/writable_dir_changer.hpp"
#include "base/scope_guard.hpp"
#include "base/file_name_utils.hpp"
UNIT_TEST(KMZ_UnzipTest)
{
std::string const kmzFile = GetPlatform().TestsDataPathForFile("kml_test_data/test.kmz");
// Temporary path for GetBookmarksDirectory.
WritableDirChanger dirGuard("kmz_test", true /* setSettingsDir */);
std::string const filePath = GetKMLorGPXPath(kmzFile);
TEST(!filePath.empty(), ());
SCOPE_GUARD(fileGuard, std::bind(&base::DeleteFileX, filePath));
TEST(strings::EndsWith(filePath, "doc.kml"), (filePath));
{
Platform::FilesList filesList;
Platform::GetFilesRecursively(base::JoinPath(GetBookmarksDirectory(), "files"), filesList);
TEST_EQUAL(filesList.size(), 4, ());
}
auto const kmlData = LoadKmlFile(filePath, KmlFileType::Text);
TEST(kmlData != nullptr, ());
TEST_EQUAL(kmlData->m_bookmarksData.size(), 6, ("Category wrong number of bookmarks"));
auto const checkUserSymbol = [](Bookmark const & bm, std::string const & symbolPath)
{
TEST_EQUAL(bm.GetColor(), kml::PredefinedColor::None, ());
auto const symbolNames = bm.GetSymbolNames();
TEST(!symbolNames->m_pathPrefix.empty(), ());
TEST(!symbolNames->m_zoomInfo.empty(), ());
TEST_EQUAL(symbolNames->m_zoomInfo.begin()->second, symbolPath, ());
};
{
Bookmark const bm(std::move(kmlData->m_bookmarksData[0]));
TEST_EQUAL(kml::GetDefaultStr(bm.GetName()), ("Lahaina Breakwall"), ("KML wrong name!"));
TEST_EQUAL(bm.GetColor(), kml::PredefinedColor::Red, ("KML wrong type!"));
TEST_ALMOST_EQUAL_ULPS(bm.GetPivot().x, -156.6777046791284, ("KML wrong org x!"));
TEST_ALMOST_EQUAL_ULPS(bm.GetPivot().y, 21.34256685860084, ("KML wrong org y!"));
TEST_EQUAL(bm.GetScale(), 0, ("KML wrong scale!"));
TEST_EQUAL(kml::GetDefaultStr(bm.GetName()), ("Lahaina Breakwall"), ());
checkUserSymbol(bm, "files/icon_surfing.png");
TEST_ALMOST_EQUAL_ULPS(bm.GetPivot().x, -156.6777046791284, ());
TEST_ALMOST_EQUAL_ULPS(bm.GetPivot().y, 21.34256685860084, ());
TEST_EQUAL(bm.GetScale(), 0, ());
}
{
Bookmark const bm(std::move(kmlData->m_bookmarksData[1]));
TEST_EQUAL(kml::GetDefaultStr(bm.GetName()), ("Seven Sacred Pools, Kipahulu"), ("KML wrong name!"));
TEST_EQUAL(bm.GetColor(), kml::PredefinedColor::Red, ("KML wrong type!"));
TEST_ALMOST_EQUAL_ULPS(bm.GetPivot().x, -156.0405130750025, ("KML wrong org x!"));
TEST_ALMOST_EQUAL_ULPS(bm.GetPivot().y, 21.12480639056074, ("KML wrong org y!"));
TEST_EQUAL(bm.GetScale(), 0, ("KML wrong scale!"));
TEST_EQUAL(kml::GetDefaultStr(bm.GetName()), ("Seven Sacred Pools, Kipahulu"), ());
checkUserSymbol(bm, "files/icon_surfing.png");
TEST_ALMOST_EQUAL_ULPS(bm.GetPivot().x, -156.0405130750025, ());
TEST_ALMOST_EQUAL_ULPS(bm.GetPivot().y, 21.12480639056074, ());
TEST_EQUAL(bm.GetScale(), 0, ());
}
}

View file

@ -195,7 +195,7 @@ drape_ptr<df::UserPointMark::SymbolNameZoomInfo> RouteMarkPoint::GetSymbolNames(
}
}
auto symbol = make_unique_dp<SymbolNameZoomInfo>();
symbol->insert(std::make_pair(1 /* zoomLevel */, name));
symbol->Emplace(1, std::move(name));
return symbol;
}
@ -470,7 +470,7 @@ drape_ptr<df::UserPointMark::TitlesInfo> TransitMark::GetTitleDecl() const
return titles;
}
void TransitMark::SetSymbolNames(std::map<int, std::string> const & symbolNames)
void TransitMark::SetSymbolNames(df::UserPointMark::SymbolNameZoomInfo const & symbolNames)
{
SetDirty();
m_symbolNames = symbolNames;
@ -525,7 +525,7 @@ dp::Anchor TransitMark::GetAnchor() const
drape_ptr<df::UserPointMark::SymbolNameZoomInfo> TransitMark::GetSymbolNames() const
{
if (m_symbolNames.empty())
if (m_symbolNames.IsEmpty())
return nullptr;
return make_unique_dp<SymbolNameZoomInfo>(m_symbolNames);
}
@ -552,7 +552,7 @@ SpeedCameraMark::SpeedCameraMark(m2::PointD const & ptOrg)
m_titleDecl.m_primaryOffset.x = kSpeedCameraOutlineWidth + kSpeedCameraMarkTextMargin;
m_titleDecl.m_anchor = dp::Left;
m_symbolNames.insert(std::make_pair(kMinSpeedCameraZoom, "speedcam-alert-l"));
m_symbolNames.Emplace(kMinSpeedCameraZoom, "speedcam-alert-l");
df::ColoredSymbolViewParams params;
params.m_color = df::GetColorConstant(kSpeedCameraMarkBg);
@ -674,7 +674,7 @@ drape_ptr<df::UserPointMark::SymbolNameZoomInfo> RoadWarningMark::GetSymbolNames
case RoadWarningMarkType::Count: CHECK(false, ()); break;
}
auto symbol = make_unique_dp<SymbolNameZoomInfo>();
symbol->insert(std::make_pair(1 /* zoomLevel */, symbolName));
symbol->Emplace(1, std::move(symbolName));
return symbol;
}

View file

@ -212,7 +212,7 @@ drape_ptr<df::UserPointMark::SymbolNameZoomInfo> SearchMarkPoint::GetSymbolNames
return nullptr;
auto symbolZoomInfo = make_unique_dp<SymbolNameZoomInfo>();
symbolZoomInfo->emplace(1 /*kWorldZoomLevel*/, *symbolName);
symbolZoomInfo->Emplace(1, *symbolName);
return symbolZoomInfo;
}

View file

@ -40,7 +40,7 @@ void TrackInfoMark::SetTrackId(kml::TrackId trackId)
drape_ptr<df::UserPointMark::SymbolNameZoomInfo> TrackInfoMark::GetSymbolNames() const
{
auto symbol = make_unique_dp<SymbolNameZoomInfo>();
symbol->insert(std::make_pair(kMinInfoVisibleZoom, kInfoSignSymbolName));
symbol->Emplace(kMinInfoVisibleZoom, kInfoSignSymbolName);
return symbol;
}
@ -91,7 +91,7 @@ void TrackSelectionMark::SetMyPositionDistance(double distance)
drape_ptr<df::UserPointMark::SymbolNameZoomInfo> TrackSelectionMark::GetSymbolNames() const
{
auto symbol = make_unique_dp<SymbolNameZoomInfo>();
symbol->insert(std::make_pair(m_minVisibleZoom, kTrackDeselectedSymbolName));
symbol->Emplace(m_minVisibleZoom, kTrackDeselectedSymbolName);
return symbol;
}

View file

@ -836,8 +836,8 @@ void TransitRouteDisplay::CreateTransitMarks()
return name != kZeroIcon ? name + suffix : name;
};
df::UserPointMark::SymbolNameZoomInfo symbolNames;
symbolNames[kSmallIconZoom] = GetSymbolName(mark.m_symbolName, "-s");
symbolNames[kMediumIconZoom] = GetSymbolName(mark.m_symbolName, "-m");
symbolNames.Emplace(kSmallIconZoom, GetSymbolName(mark.m_symbolName, "-s"));
symbolNames.Emplace(kMediumIconZoom, GetSymbolName(mark.m_symbolName, "-m"));
transitMark->SetSymbolNames(symbolNames);
transitMark->SetPriority(UserMark::Priority::TransitGate);
@ -864,7 +864,7 @@ void TransitRouteDisplay::CreateTransitMarks()
titleTransitMark->AddTitle(titleDecl);
titleTransitMark->SetAnchor(dp::Top);
titleTransitMark->SetSymbolNames({{1 /* minZoom */, "transfer_arrow"}});
titleTransitMark->SetSymbolNames({{{1 /* minZoom */, "transfer_arrow"}}, {}});
titleTransitMark->SetSymbolOffsets(transferArrowOffsets);
titleTransitMark->SetPriority(UserMark::Priority::TransitTransfer);
}
@ -900,19 +900,19 @@ void TransitRouteDisplay::CreateTransitMarks()
if (mark.m_type == TransitMarkInfo::Type::KeyStop)
{
df::UserPointMark::SymbolNameZoomInfo symbolNames;
symbolNames[kSmallIconZoom] = mark.m_symbolName + "-s";
symbolNames[kMediumIconZoom] = mark.m_symbolName + "-m";
symbolNames.Emplace(kSmallIconZoom, mark.m_symbolName + "-s");
symbolNames.Emplace(kMediumIconZoom, mark.m_symbolName + "-m");
transitMark->SetSymbolNames(symbolNames);
df::UserPointMark::ColoredSymbolZoomInfo coloredSymbol;
df::ColoredSymbolViewParams params;
params.m_color = df::GetColorConstant(mark.m_color);
auto sz = m_symbolSizes.at(symbolNames[kSmallIconZoom]);
auto sz = m_symbolSizes.at(symbolNames.m_zoomInfo.at(kSmallIconZoom));
params.m_radiusInPixels = max(sz.x, sz.y) * kGateBgScale * 0.5f;
coloredSymbol.m_zoomInfo[kSmallIconZoom] = params;
sz = m_symbolSizes.at(symbolNames[kMediumIconZoom]);
sz = m_symbolSizes.at(symbolNames.m_zoomInfo.at(kMediumIconZoom));
params.m_radiusInPixels = max(sz.x, sz.y) * kGateBgScale * 0.5f;
coloredSymbol.m_zoomInfo[kMediumIconZoom] = params;

View file

@ -56,7 +56,7 @@ DebugMarkPoint::DebugMarkPoint(const m2::PointD & ptOrg)
drape_ptr<df::UserPointMark::SymbolNameZoomInfo> DebugMarkPoint::GetSymbolNames() const
{
auto symbol = make_unique_dp<SymbolNameZoomInfo>();
symbol->insert(std::make_pair(1 /* zoomLevel */, "non-found-search-result"));
symbol->Emplace(1, "non-found-search-result");
return symbol;
}

View file

@ -5,22 +5,22 @@
#include "platform/platform.hpp"
#include "platform/settings.hpp"
#include "coding/internal/file_data.hpp"
#include "base/file_name_utils.hpp"
WritableDirChanger::WritableDirChanger(std::string const & testDir, SettingsDirPolicy settingsDirPolicy)
WritableDirChanger::WritableDirChanger(std::string const & testDir, bool m_settingsDir /* = false */)
: m_writableDirBeforeTest(GetPlatform().WritableDir())
, m_testDirFullPath(m_writableDirBeforeTest + testDir)
, m_settingsDirPolicy(settingsDirPolicy)
, m_settingsDir(m_settingsDir)
{
Platform & platform = GetPlatform();
platform.RmDirRecursively(m_testDirFullPath);
TEST(!platform.IsFileExistsByFullPath(m_testDirFullPath), ());
TEST_EQUAL(Platform::ERR_OK, platform.MkDir(m_testDirFullPath), ());
platform.SetWritableDirForTests(m_testDirFullPath);
if (m_settingsDirPolicy == SettingsDirPolicy::UseWritableDir)
if (m_settingsDir)
{
platform.SetSettingsDir(m_testDirFullPath);
/// @todo Make a copy of settings.ini file here?
}
settings::Clear();
}
@ -30,7 +30,7 @@ WritableDirChanger::~WritableDirChanger()
Platform & platform = GetPlatform();
std::string const writableDirForTest = platform.WritableDir();
platform.SetWritableDirForTests(m_writableDirBeforeTest);
if (m_settingsDirPolicy == SettingsDirPolicy::UseWritableDir)
if (m_settingsDir)
platform.SetSettingsDir(m_writableDirBeforeTest);
platform.RmDirRecursively(writableDirForTest);
}

View file

@ -5,17 +5,11 @@
class WritableDirChanger
{
public:
enum class SettingsDirPolicy
{
UseDefault, UseWritableDir
};
WritableDirChanger(std::string const & testDir,
SettingsDirPolicy settingsDirPolicy = SettingsDirPolicy::UseDefault);
explicit WritableDirChanger(std::string const & testDir, bool setSettingsDir = false);
~WritableDirChanger();
private:
std::string const m_writableDirBeforeTest;
std::string const m_testDirFullPath;
SettingsDirPolicy m_settingsDirPolicy;
bool m_settingsDir;
};

View file

@ -134,10 +134,8 @@ void BookmarkDialog::OnImportClick()
for (auto const & name : files)
{
auto const file = name.toStdString();
if (file.empty())
continue;
m_framework.GetBookmarkManager().LoadBookmark(file, false /* isTemporaryFile */);
if (!file.empty())
m_framework.AddBookmarksFile(file, false /* isTemporaryFile */);
}
}

View file

@ -139,6 +139,8 @@
6743D3451C3533AE0095054B /* support_manager.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 6743D3431C3533AE0095054B /* support_manager.hpp */; };
675D21991BFB876E00717E4F /* projection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 675D21971BFB876E00717E4F /* projection.cpp */; };
675D219A1BFB876E00717E4F /* projection.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 675D21981BFB876E00717E4F /* projection.hpp */; };
ACA9AB4D285F8BA4009FFFCD /* rect_packer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ACA9AB4B285F8BA4009FFFCD /* rect_packer.cpp */; };
ACA9AB4E285F8BA4009FFFCD /* rect_packer.hpp in Headers */ = {isa = PBXBuildFile; fileRef = ACA9AB4C285F8BA4009FFFCD /* rect_packer.hpp */; };
BB035F6C1E3A2A5C00519962 /* drape_diagnostics.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BB035F6B1E3A2A5C00519962 /* drape_diagnostics.hpp */; };
BBAD59F821258812005543FC /* debug_renderer.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BBAD59F721258812005543FC /* debug_renderer.hpp */; };
BBB72E902110AF0F00249D4F /* oglcontext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BBB72E8F2110AF0F00249D4F /* oglcontext.cpp */; };
@ -287,6 +289,8 @@
6743D3431C3533AE0095054B /* support_manager.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = support_manager.hpp; sourceTree = "<group>"; };
675D21971BFB876E00717E4F /* projection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = projection.cpp; sourceTree = "<group>"; };
675D21981BFB876E00717E4F /* projection.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = projection.hpp; sourceTree = "<group>"; };
ACA9AB4B285F8BA4009FFFCD /* rect_packer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rect_packer.cpp; sourceTree = "<group>"; };
ACA9AB4C285F8BA4009FFFCD /* rect_packer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = rect_packer.hpp; sourceTree = "<group>"; };
BB035F6B1E3A2A5C00519962 /* drape_diagnostics.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = drape_diagnostics.hpp; sourceTree = "<group>"; };
BBAD59F721258812005543FC /* debug_renderer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = debug_renderer.hpp; sourceTree = "<group>"; };
BBB72E8F2110AF0F00249D4F /* oglcontext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = oglcontext.cpp; sourceTree = "<group>"; };
@ -456,6 +460,8 @@
6729A5331A69213A007D5872 /* overlay_tree.hpp */,
6729A5341A69213A007D5872 /* pointers.cpp */,
6729A5351A69213A007D5872 /* pointers.hpp */,
ACA9AB4B285F8BA4009FFFCD /* rect_packer.cpp */,
ACA9AB4C285F8BA4009FFFCD /* rect_packer.hpp */,
6729A5361A69213A007D5872 /* render_bucket.cpp */,
6729A5371A69213A007D5872 /* render_bucket.hpp */,
45D7ADE12113535600160DE3 /* render_state.cpp */,
@ -551,6 +557,7 @@
4560F5A92142A17B00CC736C /* metal_gpu_buffer_impl.hpp in Headers */,
45789EDA2133E14F009955CC /* metal_base_context.hpp in Headers */,
6743D3451C3533AE0095054B /* support_manager.hpp in Headers */,
ACA9AB4E285F8BA4009FFFCD /* rect_packer.hpp in Headers */,
6729A5B31A69213A007D5872 /* vertex_decl.hpp in Headers */,
6729A5721A69213A007D5872 /* cpu_buffer.hpp in Headers */,
4525F88522154BE800CAC51A /* vulkan_pipeline.hpp in Headers */,
@ -678,6 +685,7 @@
457B536720358F7E00E4E752 /* glyph_generator.cpp in Sources */,
6729A5A21A69213A007D5872 /* stipple_pen_resource.cpp in Sources */,
6729A5691A69213A007D5872 /* batcher.cpp in Sources */,
ACA9AB4D285F8BA4009FFFCD /* rect_packer.cpp in Sources */,
670947251BDF9A4F005014C0 /* bidi.cpp in Sources */,
4577B25D21F2035D00864FAC /* vulkan_layers.cpp in Sources */,
6729A58C1A69213A007D5872 /* index_buffer_mutator.cpp in Sources */,