WIP: Working on custom bookmark icons. #2795
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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), ());
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
@ -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
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {};
|
||||
|
||||
|
||||
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();
|
||||
![]() 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";
|
||||
![]() Это точно нужно в релизе? Это точно нужно в релизе?
![]() У нас в целом стратегия предпочтения CHECK там где не критично по производительности. У нас в целом стратегия предпочтения 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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
211
kml/serdes.cpp
|
@ -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))
|
||||
![]() А дефолтные треки не сломаются? А дефолтные треки не сломаются?
![]() Тут функция стала полностью другая по назначению. Тут функция стала полностью другая по назначению.
|
||||
{
|
||||
// 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;
|
||||
![]()
`<Style>` is [correct official format](https://developers.google.com/kml/documentation/kmlreference#style)
![]()
`<styleUrl>` внутри `<Placemark>` тоже [официальный формат](https://developers.google.com/kml/documentation/kmlreference#placemark).
![]() А вот Style внутри Placemark уже нарушение, как пишут в комментах. Но видимо придётся поддерживать, кто ж это так накосячил... А вот Style внутри Placemark уже нарушение, как пишут в комментах. Но видимо придётся поддерживать, кто ж это так накосячил...
![]() Комментарий об этом говорил и говорит. Комментарий об этом говорил и говорит.
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
![]() Разве FFFFFFFF не белый цвет? Разве FFFFFFFF не белый цвет?
![]() Вообще, наш invalid color это костыль, цвета или иконки по идее всегда должны быть в прилетающих к нам в kml данных. Вообще, наш invalid color это костыль, цвета или иконки по идее всегда должны быть в прилетающих к нам в kml данных.
![]() Белый прозрачный - по сути нет цвета. Белый прозрачный - по сути нет цвета.
Не костыль, это значит цвета нет и он не проинициализирован.
|
||||
{
|
||||
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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -3,39 +3,61 @@
|
|||
#include "map/bookmark_helpers.hpp"
|
||||
![]() Эти тесты поудаляют другие десктопные метки для работы/других кейзов? Эти тесты поудаляют другие десктопные метки для работы/других кейзов?
![]() Да, тут стоит пересмотреть логику. Да, тут стоит пересмотреть логику.
|
||||
|
||||
#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, ());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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 */);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */,
|
||||
|
|
Лучше it для итераторов, а i для индексов, тогда проще код читать.