ENH: load more fonts
this feature is according to Prusa by Filip Sykala<filip.sykala@prusa3d.cz>, thanks to Filip Sykala jira: none Change-Id: I55e92f184f750c0b93b679d4382aaa5b164ec5c3 (cherry picked from commit d05522c4cc5d7ee4cac42de398b88d347a55f74b)
This commit is contained in:
parent
b34cffa437
commit
1bd02c6aa6
|
@ -500,11 +500,11 @@ int main(int arg, char **argv)
|
|||
#ifndef __STB_INCLUDE_STB_TRUETYPE_H__
|
||||
#define __STB_INCLUDE_STB_TRUETYPE_H__
|
||||
|
||||
#ifdef STBTT_STATIC
|
||||
#define STBTT_DEF static
|
||||
#else
|
||||
//#ifdef STBTT_STATIC
|
||||
//#define STBTT_DEF static
|
||||
//#else
|
||||
#define STBTT_DEF extern
|
||||
#endif
|
||||
//#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
@ -492,6 +492,10 @@ set(SLIC3R_GUI_SOURCES
|
|||
Utils/CalibUtils.cpp
|
||||
Utils/CalibUtils.hpp
|
||||
Utils/ProfileDescription.hpp
|
||||
Utils/FontConfigHelp.cpp
|
||||
Utils/FontConfigHelp.hpp
|
||||
Utils/FontUtils.cpp
|
||||
Utils/FontUtils.hpp
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "GUI_App.hpp"
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <wx/dcgraph.h>
|
||||
#include "FontUtils.hpp"
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
|
@ -551,6 +552,9 @@ bool GLTexture::generate_from_text(const std::string &text_str, wxFont &font, wx
|
|||
|
||||
bool GLTexture::generate_texture_from_text(const std::string& text_str, wxFont& font, int& ww, int& hh, int& hl, wxColor background, wxColor foreground)
|
||||
{
|
||||
if(!can_generate_text_shape(text_str))
|
||||
return false;
|
||||
|
||||
if (text_str.empty())
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":no text string, should not happen\n";
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "libslic3r/SVG.hpp"
|
||||
#include <codecvt>
|
||||
#include "wx/fontenum.h"
|
||||
#include "FontUtils.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
@ -36,68 +37,8 @@ static const wxColour FONT_TEXTURE_FG = *wxWHITE;
|
|||
static const int FONT_SIZE = 12;
|
||||
static const float SELECTABLE_INNER_OFFSET = 8.0f;
|
||||
|
||||
static std::vector<std::string> font_black_list = {
|
||||
#ifdef _WIN32
|
||||
"MT Extra",
|
||||
"Marlett",
|
||||
"Symbol",
|
||||
"Webdings",
|
||||
"Wingdings",
|
||||
"Wingdings 2",
|
||||
"Wingdings 3",
|
||||
#endif
|
||||
};
|
||||
|
||||
static const wxFontEncoding font_encoding = wxFontEncoding::wxFONTENCODING_SYSTEM;
|
||||
|
||||
#ifdef _WIN32
|
||||
static bool load_hfont(void *hfont, DWORD &dwTable, DWORD &dwOffset, size_t &size, HDC hdc = nullptr)
|
||||
{
|
||||
bool del_hdc = false;
|
||||
if (hdc == nullptr) {
|
||||
del_hdc = true;
|
||||
hdc = ::CreateCompatibleDC(NULL);
|
||||
if (hdc == NULL) return false;
|
||||
}
|
||||
|
||||
// To retrieve the data from the beginning of the file for TrueType
|
||||
// Collection files specify 'ttcf' (0x66637474).
|
||||
dwTable = 0x66637474;
|
||||
dwOffset = 0;
|
||||
|
||||
::SelectObject(hdc, hfont);
|
||||
size = ::GetFontData(hdc, dwTable, dwOffset, NULL, 0);
|
||||
if (size == GDI_ERROR) {
|
||||
// HFONT is NOT TTC(collection)
|
||||
dwTable = 0;
|
||||
size = ::GetFontData(hdc, dwTable, dwOffset, NULL, 0);
|
||||
}
|
||||
|
||||
if (size == 0 || size == GDI_ERROR) {
|
||||
if (del_hdc) ::DeleteDC(hdc);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
bool can_load(const wxFont &font)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DWORD dwTable = 0, dwOffset = 0;
|
||||
size_t size = 0;
|
||||
void* hfont = font.GetHFONT();
|
||||
if (!load_hfont(hfont, dwTable, dwOffset, size))
|
||||
return false;
|
||||
return hfont != nullptr;
|
||||
#elif defined(__APPLE__)
|
||||
return true;
|
||||
#elif defined(__linux__)
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> init_face_names()
|
||||
{
|
||||
std::vector<std::string> valid_font_names;
|
||||
|
@ -142,10 +83,6 @@ std::vector<std::string> init_face_names()
|
|||
}
|
||||
assert(std::is_sorted(bad_fonts.begin(), bad_fonts.end()));
|
||||
|
||||
for (auto iter = font_black_list.begin(); iter != font_black_list.end(); ++iter) {
|
||||
valid_font_names.erase(std::remove(valid_font_names.begin(), valid_font_names.end(), *iter), valid_font_names.end());
|
||||
}
|
||||
|
||||
return valid_font_names;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
///|/ Copyright (c) Prusa Research 2021 - 2022 Filip Sykala @Jony01
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#include "FontConfigHelp.hpp"
|
||||
|
||||
#ifdef EXIST_FONT_CONFIG_INCLUDE
|
||||
|
||||
#include <wx/filename.h>
|
||||
#include <fontconfig/fontconfig.h>
|
||||
#include "libslic3r/Utils.hpp"
|
||||
|
||||
using namespace Slic3r::GUI;
|
||||
|
||||
|
||||
// @Vojta suggest to make static variable global
|
||||
// Guard for finalize Font Config
|
||||
// Will be finalized on application exit
|
||||
// It seams that it NOT work
|
||||
static std::optional<Slic3r::ScopeGuard> finalize_guard;
|
||||
// cache for Loading of the default configuration file and building information about the available fonts.
|
||||
static FcConfig *fc = nullptr;
|
||||
|
||||
std::string Slic3r::GUI::get_font_path(const wxFont &font, bool reload_fonts)
|
||||
{
|
||||
if (!finalize_guard.has_value()) {
|
||||
FcInit();
|
||||
fc = FcInitLoadConfigAndFonts();
|
||||
finalize_guard.emplace([]() {
|
||||
// Some internal problem of Font config or other library use FC too(like wxWidget)
|
||||
// fccache.c:795: FcCacheFini: Assertion `fcCacheChains[i] == NULL' failed.
|
||||
//FcFini();
|
||||
FcConfigDestroy(fc);
|
||||
});
|
||||
} else if (reload_fonts) {
|
||||
FcConfigDestroy(fc);
|
||||
fc = FcInitLoadConfigAndFonts();
|
||||
}
|
||||
|
||||
if (fc == nullptr) return "";
|
||||
|
||||
wxString fontDesc = font.GetNativeFontInfoUserDesc();
|
||||
wxString faceName = font.GetFaceName();
|
||||
const wxScopedCharBuffer faceNameBuffer = faceName.ToUTF8();
|
||||
const char * fontFamily = faceNameBuffer;
|
||||
|
||||
// Check font slant
|
||||
int slant = FC_SLANT_ROMAN;
|
||||
if (fontDesc.Find(wxS("Oblique")) != wxNOT_FOUND)
|
||||
slant = FC_SLANT_OBLIQUE;
|
||||
else if (fontDesc.Find(wxS("Italic")) != wxNOT_FOUND)
|
||||
slant = FC_SLANT_ITALIC;
|
||||
|
||||
// Check font weight
|
||||
int weight = FC_WEIGHT_NORMAL;
|
||||
if (fontDesc.Find(wxS("Book")) != wxNOT_FOUND)
|
||||
weight = FC_WEIGHT_BOOK;
|
||||
else if (fontDesc.Find(wxS("Medium")) != wxNOT_FOUND)
|
||||
weight = FC_WEIGHT_MEDIUM;
|
||||
#ifdef FC_WEIGHT_ULTRALIGHT
|
||||
else if (fontDesc.Find(wxS("Ultra-Light")) != wxNOT_FOUND)
|
||||
weight = FC_WEIGHT_ULTRALIGHT;
|
||||
#endif
|
||||
else if (fontDesc.Find(wxS("Light")) != wxNOT_FOUND)
|
||||
weight = FC_WEIGHT_LIGHT;
|
||||
else if (fontDesc.Find(wxS("Semi-Bold")) != wxNOT_FOUND)
|
||||
weight = FC_WEIGHT_DEMIBOLD;
|
||||
#ifdef FC_WEIGHT_ULTRABOLD
|
||||
else if (fontDesc.Find(wxS("Ultra-Bold")) != wxNOT_FOUND)
|
||||
weight = FC_WEIGHT_ULTRABOLD;
|
||||
#endif
|
||||
else if (fontDesc.Find(wxS("Bold")) != wxNOT_FOUND)
|
||||
weight = FC_WEIGHT_BOLD;
|
||||
else if (fontDesc.Find(wxS("Heavy")) != wxNOT_FOUND)
|
||||
weight = FC_WEIGHT_BLACK;
|
||||
|
||||
// Check font width
|
||||
int width = FC_WIDTH_NORMAL;
|
||||
if (fontDesc.Find(wxS("Ultra-Condensed")) != wxNOT_FOUND)
|
||||
width = FC_WIDTH_ULTRACONDENSED;
|
||||
else if (fontDesc.Find(wxS("Extra-Condensed")) != wxNOT_FOUND)
|
||||
width = FC_WIDTH_EXTRACONDENSED;
|
||||
else if (fontDesc.Find(wxS("Semi-Condensed")) != wxNOT_FOUND)
|
||||
width = FC_WIDTH_SEMICONDENSED;
|
||||
else if (fontDesc.Find(wxS("Condensed")) != wxNOT_FOUND)
|
||||
width = FC_WIDTH_CONDENSED;
|
||||
else if (fontDesc.Find(wxS("Ultra-Expanded")) != wxNOT_FOUND)
|
||||
width = FC_WIDTH_ULTRAEXPANDED;
|
||||
else if (fontDesc.Find(wxS("Extra-Expanded")) != wxNOT_FOUND)
|
||||
width = FC_WIDTH_EXTRAEXPANDED;
|
||||
else if (fontDesc.Find(wxS("Semi-Expanded")) != wxNOT_FOUND)
|
||||
width = FC_WIDTH_SEMIEXPANDED;
|
||||
else if (fontDesc.Find(wxS("Expanded")) != wxNOT_FOUND)
|
||||
width = FC_WIDTH_EXPANDED;
|
||||
|
||||
FcResult res;
|
||||
FcPattern *matchPattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString,
|
||||
(FcChar8 *) fontFamily, NULL);
|
||||
ScopeGuard sg_mp([matchPattern]() { FcPatternDestroy(matchPattern); });
|
||||
|
||||
FcPatternAddInteger(matchPattern, FC_SLANT, slant);
|
||||
FcPatternAddInteger(matchPattern, FC_WEIGHT, weight);
|
||||
FcPatternAddInteger(matchPattern, FC_WIDTH, width);
|
||||
|
||||
FcConfigSubstitute(NULL, matchPattern, FcMatchPattern);
|
||||
FcDefaultSubstitute(matchPattern);
|
||||
|
||||
FcPattern *resultPattern = FcFontMatch(NULL, matchPattern, &res);
|
||||
if (resultPattern == nullptr) return "";
|
||||
ScopeGuard sg_rp([resultPattern]() { FcPatternDestroy(resultPattern); });
|
||||
|
||||
FcChar8 *fileName;
|
||||
if (FcPatternGetString(resultPattern, FC_FILE, 0, &fileName) !=
|
||||
FcResultMatch)
|
||||
return "";
|
||||
wxString fontFileName = wxString::FromUTF8((char *) fileName);
|
||||
|
||||
if (fontFileName.IsEmpty()) return "";
|
||||
|
||||
// find full file path
|
||||
wxFileName myFileName(fontFileName);
|
||||
if (!myFileName.IsOk()) return "";
|
||||
|
||||
if (myFileName.IsRelative()) {
|
||||
// Check whether the file is relative to the current working directory
|
||||
if (!(myFileName.MakeAbsolute() && myFileName.FileExists())) {
|
||||
return "";
|
||||
// File not found, search in given search paths
|
||||
// wxString foundFileName =
|
||||
// m_searchPaths.FindAbsoluteValidPath(fileName); if
|
||||
// (!foundFileName.IsEmpty()) {
|
||||
// myFileName.Assign(foundFileName);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
if (!myFileName.FileExists() || !myFileName.IsFileReadable()) return "";
|
||||
|
||||
// File exists and is accessible
|
||||
wxString fullFileName = myFileName.GetFullPath();
|
||||
return std::string(fullFileName.c_str());
|
||||
}
|
||||
|
||||
#endif // EXIST_FONT_CONFIG_INCLUDE
|
|
@ -0,0 +1,29 @@
|
|||
///|/ Copyright (c) Prusa Research 2021 - 2022 Filip Sykala @Jony01
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#ifndef slic3r_FontConfigHelp_hpp_
|
||||
#define slic3r_FontConfigHelp_hpp_
|
||||
|
||||
#ifdef __linux__
|
||||
#define EXIST_FONT_CONFIG_INCLUDE
|
||||
#endif
|
||||
|
||||
#ifdef EXIST_FONT_CONFIG_INCLUDE
|
||||
#include <wx/font.h>
|
||||
namespace Slic3r::GUI {
|
||||
|
||||
/// <summary>
|
||||
/// initialize font config
|
||||
/// Convert wx widget font to file path
|
||||
/// inspired by wxpdfdoc -
|
||||
/// https://github.com/utelle/wxpdfdoc/blob/5bdcdb9953327d06dc50ec312685ccd9bc8400e0/src/pdffontmanager.cpp
|
||||
/// </summary>
|
||||
/// <param name="font">Wx descriptor of font</param>
|
||||
/// <param name="reload_fonts">flag to reinitialize font list</param>
|
||||
/// <returns>Font FilePath by FontConfig</returns>
|
||||
std::string get_font_path(const wxFont &font, bool reload_fonts = false);
|
||||
|
||||
} // namespace Slic3r
|
||||
#endif // EXIST_FONT_CONFIG_INCLUDE
|
||||
#endif // slic3r_FontConfigHelp_hpp_
|
|
@ -0,0 +1,290 @@
|
|||
#include "FontUtils.hpp"
|
||||
#include "imgui/imstb_truetype.h"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <CoreText/CTFont.h>
|
||||
#include <wx/uri.h>
|
||||
#include <wx/fontutil.h> // wxNativeFontInfo
|
||||
#include <wx/osx/core/cfdictionary.h>
|
||||
#elif defined(__linux__)
|
||||
#include "FontConfigHelp.hpp"
|
||||
#endif
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
#ifdef __APPLE__
|
||||
bool is_valid_ttf(std::string_view file_path)
|
||||
{
|
||||
if (file_path.empty()) return false;
|
||||
auto const pos_point = file_path.find_last_of('.');
|
||||
if (pos_point == std::string_view::npos) return false;
|
||||
|
||||
// use point only after last directory delimiter
|
||||
auto const pos_directory_delimiter = file_path.find_last_of("/\\");
|
||||
if (pos_directory_delimiter != std::string_view::npos && pos_point < pos_directory_delimiter) return false; // point is before directory delimiter
|
||||
|
||||
// check count of extension chars
|
||||
size_t extension_size = file_path.size() - pos_point;
|
||||
if (extension_size >= 5) return false; // a lot of symbols for extension
|
||||
if (extension_size <= 1) return false; // few letters for extension
|
||||
|
||||
std::string_view extension = file_path.substr(pos_point + 1, extension_size);
|
||||
|
||||
// Because of MacOs - Courier, Geneva, Monaco
|
||||
if (extension == std::string_view("dfont")) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// get filepath from wxFont on Mac OsX
|
||||
std::string get_file_path(const wxFont &font)
|
||||
{
|
||||
const wxNativeFontInfo *info = font.GetNativeFontInfo();
|
||||
if (info == nullptr) return {};
|
||||
CTFontDescriptorRef descriptor = info->GetCTFontDescriptor();
|
||||
CFURLRef typeref = (CFURLRef) CTFontDescriptorCopyAttribute(descriptor, kCTFontURLAttribute);
|
||||
if (typeref == NULL) return {};
|
||||
ScopeGuard sg([&typeref]() { CFRelease(typeref); });
|
||||
CFStringRef url = CFURLGetString(typeref);
|
||||
if (url == NULL) return {};
|
||||
wxString file_uri(wxCFStringRef::AsString(url));
|
||||
wxURI uri(file_uri);
|
||||
const wxString &path = uri.GetPath();
|
||||
wxString path_unescaped = wxURI::Unescape(path);
|
||||
std::string path_str = path_unescaped.ToUTF8().data();
|
||||
BOOST_LOG_TRIVIAL(trace) << "input uri(" << file_uri.c_str() << ") convert to path(" << path.c_str() << ") string(" << path_str << ").";
|
||||
return path_str;
|
||||
}
|
||||
#endif // __APPLE__
|
||||
|
||||
using fontinfo_opt = std::optional<stbtt_fontinfo>;
|
||||
|
||||
std::string get_human_readable_name(const wxFont &font)
|
||||
{
|
||||
if (!font.IsOk()) return "Font is NOT ok.";
|
||||
// Face name is optional in wxFont
|
||||
if (!font.GetFaceName().empty()) {
|
||||
return std::string(font.GetFaceName().c_str());
|
||||
} else {
|
||||
return std::string((font.GetFamilyString() + " " + font.GetStyleString() + " " + font.GetWeightString()).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
fontinfo_opt load_font_info(const unsigned char *data, unsigned int index)
|
||||
{
|
||||
int font_offset = stbtt_GetFontOffsetForIndex(data, index);
|
||||
if (font_offset < 0) {
|
||||
assert(false);
|
||||
// "Font index(" << index << ") doesn't exist.";
|
||||
return {};
|
||||
}
|
||||
stbtt_fontinfo font_info;
|
||||
if (stbtt_InitFont(&font_info, data, font_offset) == 0) {
|
||||
// Can't initialize font.
|
||||
assert(false);
|
||||
return {};
|
||||
}
|
||||
return font_info;
|
||||
}
|
||||
|
||||
std::unique_ptr<FontFile> create_font_file(std::unique_ptr<std::vector<unsigned char>> data)
|
||||
{
|
||||
int collection_size = stbtt_GetNumberOfFonts(data->data());
|
||||
// at least one font must be inside collection
|
||||
if (collection_size < 1) {
|
||||
assert(false);
|
||||
// There is no font collection inside font data
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned int c_size = static_cast<unsigned int>(collection_size);
|
||||
std::vector<FontFile::Info> infos;
|
||||
infos.reserve(c_size);
|
||||
for (unsigned int i = 0; i < c_size; ++i) {
|
||||
auto font_info = load_font_info(data->data(), i);
|
||||
if (!font_info.has_value()) return nullptr;
|
||||
|
||||
const stbtt_fontinfo *info = &(*font_info);
|
||||
// load information about line gap
|
||||
int ascent, descent, linegap;
|
||||
stbtt_GetFontVMetrics(info, &ascent, &descent, &linegap);
|
||||
|
||||
float pixels = 1000.; // value is irelevant
|
||||
float em_pixels = stbtt_ScaleForMappingEmToPixels(info, pixels);
|
||||
int units_per_em = static_cast<int>(std::round(pixels / em_pixels));
|
||||
|
||||
infos.emplace_back(FontFile::Info{ascent, descent, linegap, units_per_em});
|
||||
}
|
||||
return std::make_unique<FontFile>(std::move(data), std::move(infos));
|
||||
}
|
||||
|
||||
std::unique_ptr<FontFile> create_font_file(const char *file_path)
|
||||
{
|
||||
FILE *file = std::fopen(file_path, "rb");
|
||||
if (file == nullptr) {
|
||||
assert(false);
|
||||
BOOST_LOG_TRIVIAL(error) << "Couldn't open " << file_path << " for reading.";
|
||||
return nullptr;
|
||||
}
|
||||
ScopeGuard sg([&file]() { std::fclose(file); });
|
||||
|
||||
// find size of file
|
||||
if (fseek(file, 0L, SEEK_END) != 0) {
|
||||
assert(false);
|
||||
BOOST_LOG_TRIVIAL(error) << "Couldn't fseek file " << file_path << " for size measure.";
|
||||
return nullptr;
|
||||
}
|
||||
size_t size = ftell(file);
|
||||
if (size == 0) {
|
||||
assert(false);
|
||||
BOOST_LOG_TRIVIAL(error) << "Size of font file is zero. Can't read.";
|
||||
return nullptr;
|
||||
}
|
||||
rewind(file);
|
||||
auto buffer = std::make_unique<std::vector<unsigned char>>(size);
|
||||
size_t count_loaded_bytes = fread((void *) &buffer->front(), 1, size, file);
|
||||
if (count_loaded_bytes != size) {
|
||||
assert(false);
|
||||
BOOST_LOG_TRIVIAL(error) << "Different loaded(from file) data size.";
|
||||
return nullptr;
|
||||
}
|
||||
return create_font_file(std::move(buffer));
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
bool load_hfont(void *hfont, DWORD &dwTable, DWORD &dwOffset, size_t &size, HDC hdc = nullptr)
|
||||
{
|
||||
bool del_hdc = false;
|
||||
if (hdc == nullptr) {
|
||||
del_hdc = true;
|
||||
hdc = ::CreateCompatibleDC(NULL);
|
||||
if (hdc == NULL) return false;
|
||||
}
|
||||
|
||||
// To retrieve the data from the beginning of the file for TrueType
|
||||
// Collection files specify 'ttcf' (0x66637474).
|
||||
dwTable = 0x66637474;
|
||||
dwOffset = 0;
|
||||
|
||||
::SelectObject(hdc, hfont);
|
||||
size = ::GetFontData(hdc, dwTable, dwOffset, NULL, 0);
|
||||
if (size == GDI_ERROR) {
|
||||
// HFONT is NOT TTC(collection)
|
||||
dwTable = 0;
|
||||
size = ::GetFontData(hdc, dwTable, dwOffset, NULL, 0);
|
||||
}
|
||||
|
||||
if (size == 0 || size == GDI_ERROR) {
|
||||
if (del_hdc) ::DeleteDC(hdc);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<FontFile> create_font_file(void *hfont)
|
||||
{
|
||||
HDC hdc = ::CreateCompatibleDC(NULL);
|
||||
if (hdc == NULL) {
|
||||
assert(false);
|
||||
BOOST_LOG_TRIVIAL(error) << "Can't create HDC by CreateCompatibleDC(NULL).";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DWORD dwTable = 0, dwOffset = 0;
|
||||
size_t size;
|
||||
if (!load_hfont(hfont, dwTable, dwOffset, size, hdc)) {
|
||||
::DeleteDC(hdc);
|
||||
return nullptr;
|
||||
}
|
||||
auto buffer = std::make_unique<std::vector<unsigned char>>(size);
|
||||
size_t loaded_size = ::GetFontData(hdc, dwTable, dwOffset, buffer->data(), size);
|
||||
::DeleteDC(hdc);
|
||||
if (size != loaded_size) {
|
||||
assert(false);
|
||||
BOOST_LOG_TRIVIAL(error) << "Different loaded(from HFONT) data size.";
|
||||
return nullptr;
|
||||
}
|
||||
return create_font_file(std::move(buffer));
|
||||
}
|
||||
#endif
|
||||
|
||||
std::unique_ptr<FontFile> create_font_file(const wxFont &font)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return create_font_file(font.GetHFONT());
|
||||
#elif defined(__APPLE__)
|
||||
std::string file_path = get_file_path(font);
|
||||
if (!is_valid_ttf(file_path)) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Can not process font('" << get_human_readable_name(font) << "'), "
|
||||
<< "file in path('" << file_path << "') is not valid TTF.";
|
||||
return nullptr;
|
||||
}
|
||||
return create_font_file(file_path.c_str());
|
||||
#elif defined(__linux__)
|
||||
std::string font_path = Slic3r::GUI::get_font_path(font);
|
||||
if (font_path.empty()) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Can not read font('" << get_human_readable_name(font) << "'), "
|
||||
<< "file path is empty.";
|
||||
return nullptr;
|
||||
}
|
||||
return create_font_file(font_path.c_str());
|
||||
#else
|
||||
// HERE is place to add implementation for another platform
|
||||
// to convert wxFont to font data as windows or font file path as linux
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool can_generate_text_shape_from_font(const stbtt_fontinfo &font_info)
|
||||
{
|
||||
const float flatness = 0.0125f; // [in mm]
|
||||
wchar_t letter = 'A';
|
||||
int unicode_letter = static_cast<int>(letter);
|
||||
|
||||
int glyph_index = stbtt_FindGlyphIndex(&font_info, unicode_letter);
|
||||
if (glyph_index == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int advance_width=0, left_side_bearing=0;
|
||||
stbtt_GetGlyphHMetrics(&font_info, glyph_index, &advance_width, &left_side_bearing);
|
||||
|
||||
stbtt_vertex *vertices;
|
||||
int num_verts = stbtt_GetGlyphShape(&font_info, glyph_index, &vertices);
|
||||
if (num_verts <= 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool can_generate_text_shape(const std::string& font_name) {
|
||||
wxFont wx_font(wxFontInfo().FaceName(font_name.c_str()).Encoding(wxFontEncoding::wxFONTENCODING_SYSTEM));
|
||||
std::unique_ptr<FontFile> font = create_font_file(wx_font);
|
||||
if (!font)
|
||||
return false;
|
||||
|
||||
fontinfo_opt font_info_opt = load_font_info(font->data->data(), 0);
|
||||
if (!font_info_opt.has_value())
|
||||
return false;
|
||||
|
||||
return can_generate_text_shape_from_font(*font_info_opt);
|
||||
}
|
||||
|
||||
bool can_load(const wxFont &font)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DWORD dwTable = 0, dwOffset = 0;
|
||||
size_t size = 0;
|
||||
void * hfont = font.GetHFONT();
|
||||
if (!load_hfont(hfont, dwTable, dwOffset, size)) return false;
|
||||
return hfont != nullptr;
|
||||
#elif defined(__APPLE__)
|
||||
return true;
|
||||
#elif defined(__linux__)
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
#ifndef __FONT_UTILS_HPP__
|
||||
#define __FONT_UTILS_HPP__
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <assert.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
/// <summary>
|
||||
/// keep information from file about font
|
||||
/// (store file data itself)
|
||||
/// + cache data readed from buffer
|
||||
/// </summary>
|
||||
struct FontFile
|
||||
{
|
||||
// loaded data from font file
|
||||
// must store data size for imgui rasterization
|
||||
// To not store data on heap and To prevent unneccesary copy
|
||||
// data are stored inside unique_ptr
|
||||
std::unique_ptr<std::vector<unsigned char>> data;
|
||||
|
||||
struct Info
|
||||
{
|
||||
// vertical position is "scale*(ascent - descent + lineGap)"
|
||||
int ascent, descent, linegap;
|
||||
|
||||
// for convert font units to pixel
|
||||
int unit_per_em;
|
||||
};
|
||||
// info for each font in data
|
||||
std::vector<Info> infos;
|
||||
|
||||
FontFile(std::unique_ptr<std::vector<unsigned char>> data, std::vector<Info> &&infos) : data(std::move(data)), infos(std::move(infos))
|
||||
{
|
||||
assert(this->data != nullptr);
|
||||
assert(!this->data->empty());
|
||||
}
|
||||
|
||||
bool operator==(const FontFile &other) const
|
||||
{
|
||||
if (data->size() != other.data->size()) return false;
|
||||
// if(*data != *other.data) return false;
|
||||
for (size_t i = 0; i < infos.size(); i++)
|
||||
if (infos[i].ascent != other.infos[i].ascent || infos[i].descent == other.infos[i].descent || infos[i].linegap == other.infos[i].linegap) return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
bool can_generate_text_shape(const std::string &font_name);
|
||||
|
||||
bool can_load(const wxFont &font);
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue