wip(refactor): Improve parsing and font glyph caching
This commit is contained in:
parent
9f9f438fae
commit
b2e8428550
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
Checks: '-*,performance-*,readability-*,modernize-use-*,modernize-*,-modernize-raw-string-literal,-modernize-use-bool-literals,-readability-implicit-bool-cast,-readability-else-after-return,-readability-named-parameter'
|
Checks: '-*,performance-*,readability-*,clang-analyzer-alpha.core*,clang-analyzer-alpha.security*,clang-analyzer-alpha.unix.cstring*,clang-analyzer-core.uninitialized*,clang-analyzer-cplusplus.*,clang-analyzer-nullability*,clang-analyzer-unix*,cppcoreguidelines*,modernize-use-*,modernize-*,-modernize-raw-string-literal,-modernize-use-bool-literals,-readability-implicit-bool-cast,-readability-else-after-return,-readability-named-parameter,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-pro-type-cstyle-cast,-cppcoreguidelines-pro-bounds-constant-array-index'
|
||||||
CheckOptions:
|
CheckOptions:
|
||||||
- key: modernize-loop-convert.NamingStyle
|
- key: modernize-loop-convert.NamingStyle
|
||||||
value: lower_case
|
value: lower_case
|
||||||
|
@ -27,10 +27,6 @@
|
|||||||
#define STDERR_FILENO 2
|
#define STDERR_FILENO 2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
#include "debug.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
namespace placeholders = std::placeholders;
|
namespace placeholders = std::placeholders;
|
||||||
|
@ -17,6 +17,11 @@ DEFINE_CHILD_ERROR(unclosed_actionblocks, parser_error);
|
|||||||
|
|
||||||
class parser {
|
class parser {
|
||||||
public:
|
public:
|
||||||
|
struct packet {
|
||||||
|
uint16_t data[128]{0U};
|
||||||
|
size_t length{0};
|
||||||
|
};
|
||||||
|
|
||||||
explicit parser(signal_emitter& emitter, const bar_settings& bar);
|
explicit parser(signal_emitter& emitter, const bar_settings& bar);
|
||||||
void operator()(string data);
|
void operator()(string data);
|
||||||
|
|
||||||
|
@ -32,6 +32,9 @@ class renderer
|
|||||||
unique_ptr<font_manager> font_manager, const bar_settings& bar, const vector<string>& fonts);
|
unique_ptr<font_manager> font_manager, const bar_settings& bar, const vector<string>& fonts);
|
||||||
~renderer();
|
~renderer();
|
||||||
|
|
||||||
|
renderer(const renderer& o) = delete;
|
||||||
|
renderer& operator=(const renderer& o) = delete;
|
||||||
|
|
||||||
xcb_window_t window() const;
|
xcb_window_t window() const;
|
||||||
|
|
||||||
void begin();
|
void begin();
|
||||||
@ -55,8 +58,7 @@ class renderer
|
|||||||
void fill_underline(int16_t x, uint16_t w);
|
void fill_underline(int16_t x, uint16_t w);
|
||||||
void fill_shift(const int16_t px);
|
void fill_shift(const int16_t px);
|
||||||
|
|
||||||
void draw_character(const uint16_t character);
|
void draw_textstring(const uint16_t* text, size_t len);
|
||||||
void draw_textstring(const char* text, const size_t len);
|
|
||||||
|
|
||||||
void begin_action(const mousebtn btn, const string& cmd);
|
void begin_action(const mousebtn btn, const string& cmd);
|
||||||
void end_action(const mousebtn btn);
|
void end_action(const mousebtn btn);
|
||||||
|
@ -1,21 +1,42 @@
|
|||||||
#ifdef DEBUG
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef DEBUG
|
||||||
|
#error "Not a debug build..."
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
template <class T>
|
#include "common.hpp"
|
||||||
void benchmark_execution_speed(const T& expr) noexcept {
|
|
||||||
auto start = std::chrono::high_resolution_clock::now();
|
POLYBAR_NS
|
||||||
expr();
|
|
||||||
auto finish = std::chrono::high_resolution_clock::now();
|
namespace debug_util {
|
||||||
std::cout << "execution speed: " << std::chrono::duration_cast<std::chrono::milliseconds>(finish - start).count()
|
template <class T>
|
||||||
<< "ms" << std::endl;
|
void loop(const T& expr, size_t iterations) noexcept {
|
||||||
|
while (iterations--) {
|
||||||
|
expr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void execution_speed(const T& expr) noexcept {
|
||||||
|
auto start = std::chrono::high_resolution_clock::now();
|
||||||
|
expr();
|
||||||
|
auto finish = std::chrono::high_resolution_clock::now();
|
||||||
|
std::cout << "execution speed: " << std::chrono::duration_cast<std::chrono::milliseconds>(finish - start).count()
|
||||||
|
<< "ms" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void execution_speed(const T& expr, size_t iterations) noexcept {
|
||||||
|
execution_speed([=] { loop(expr, iterations); });
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void memory_usage(const T& object) noexcept {
|
||||||
|
std::cout << "memory usage: " << sizeof(object) << "b" << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
POLYBAR_NS_END
|
||||||
void benchmark_memory_usage(const T& object) noexcept {
|
|
||||||
std::cout << "memory usage: " << sizeof(object) << "b" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "components/eventloop.hpp"
|
#include "components/eventloop.hpp"
|
||||||
#include "components/ipc.hpp"
|
#include "components/ipc.hpp"
|
||||||
|
#include "components/parser.hpp"
|
||||||
#include "components/types.hpp"
|
#include "components/types.hpp"
|
||||||
#include "utils/functional.hpp"
|
#include "utils/functional.hpp"
|
||||||
|
|
||||||
@ -114,6 +115,8 @@ namespace signals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace parser {
|
namespace parser {
|
||||||
|
using parser_t = polybar::parser;
|
||||||
|
|
||||||
DEFINE_VALUE_SIGNAL(70, change_background, uint32_t);
|
DEFINE_VALUE_SIGNAL(70, change_background, uint32_t);
|
||||||
DEFINE_VALUE_SIGNAL(71, change_foreground, uint32_t);
|
DEFINE_VALUE_SIGNAL(71, change_foreground, uint32_t);
|
||||||
DEFINE_VALUE_SIGNAL(72, change_underline, uint32_t);
|
DEFINE_VALUE_SIGNAL(72, change_underline, uint32_t);
|
||||||
@ -128,7 +131,7 @@ namespace signals {
|
|||||||
DEFINE_VALUE_SIGNAL(81, action_end, mousebtn);
|
DEFINE_VALUE_SIGNAL(81, action_end, mousebtn);
|
||||||
DEFINE_VALUE_SIGNAL(82, write_text_ascii, uint16_t);
|
DEFINE_VALUE_SIGNAL(82, write_text_ascii, uint16_t);
|
||||||
DEFINE_VALUE_SIGNAL(83, write_text_unicode, uint16_t);
|
DEFINE_VALUE_SIGNAL(83, write_text_unicode, uint16_t);
|
||||||
DEFINE_VALUE_SIGNAL(84, write_text_string, string);
|
DEFINE_VALUE_SIGNAL(84, write_text_string, parser_t::packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
#include FT_OUTLINE_H
|
||||||
|
#include FT_GLYPH_H
|
||||||
|
|
||||||
#include <X11/Xft/Xft.h>
|
#include <X11/Xft/Xft.h>
|
||||||
#include <xcb/xcbext.h>
|
#include <xcb/xcbext.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "x11/color.hpp"
|
#include "x11/color.hpp"
|
||||||
@ -9,12 +15,17 @@
|
|||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
|
using std::map;
|
||||||
|
using std::unordered_map;
|
||||||
|
|
||||||
// fwd
|
// fwd
|
||||||
class connection;
|
class connection;
|
||||||
class logger;
|
class logger;
|
||||||
|
|
||||||
struct fonttype {
|
struct font_ref {
|
||||||
explicit fonttype() = default;
|
explicit font_ref() = default;
|
||||||
|
font_ref(const font_ref& o) = delete;
|
||||||
|
font_ref& operator=(const font_ref& o) = delete;
|
||||||
XftFont* xft{nullptr};
|
XftFont* xft{nullptr};
|
||||||
xcb_font_t ptr{XCB_NONE};
|
xcb_font_t ptr{XCB_NONE};
|
||||||
int offset_y{0};
|
int offset_y{0};
|
||||||
@ -25,57 +36,61 @@ struct fonttype {
|
|||||||
uint16_t char_max{0};
|
uint16_t char_max{0};
|
||||||
uint16_t char_min{0};
|
uint16_t char_min{0};
|
||||||
vector<xcb_charinfo_t> width_lut{};
|
vector<xcb_charinfo_t> width_lut{};
|
||||||
};
|
unordered_map<uint16_t, wchar_t> glyph_widths{};
|
||||||
|
|
||||||
struct fonttype_deleter {
|
static struct _deleter {
|
||||||
void operator()(fonttype* f);
|
void operator()(font_ref* font);
|
||||||
|
} deleter;
|
||||||
};
|
};
|
||||||
|
|
||||||
using fonttype_pointer = unique_ptr<fonttype, fonttype_deleter>;
|
|
||||||
|
|
||||||
class font_manager {
|
class font_manager {
|
||||||
public:
|
public:
|
||||||
using make_type = unique_ptr<font_manager>;
|
using make_type = unique_ptr<font_manager>;
|
||||||
static make_type make();
|
static make_type make();
|
||||||
|
|
||||||
explicit font_manager(connection& conn, const logger& logger, shared_ptr<Display>&& dsp, shared_ptr<Visual>&& vis);
|
explicit font_manager(
|
||||||
|
connection& conn, const logger& logger, shared_ptr<Display>&& dsp, shared_ptr<Visual>&& vis, Colormap&& cm);
|
||||||
~font_manager();
|
~font_manager();
|
||||||
|
|
||||||
|
font_manager(const font_manager& o) = delete;
|
||||||
|
font_manager& operator=(const font_manager& o) = delete;
|
||||||
|
|
||||||
|
void cleanup();
|
||||||
bool load(const string& name, int8_t fontindex = DEFAULT_FONT_INDEX, int8_t offset_y = 0);
|
bool load(const string& name, int8_t fontindex = DEFAULT_FONT_INDEX, int8_t offset_y = 0);
|
||||||
|
|
||||||
void set_preferred_font(int8_t index);
|
void set_preferred_font(int8_t index);
|
||||||
|
shared_ptr<font_ref> match_char(const uint16_t chr);
|
||||||
fonttype_pointer& match_char(uint16_t chr);
|
uint8_t glyph_width(const shared_ptr<font_ref>& font, const uint16_t chr);
|
||||||
uint8_t char_width(fonttype_pointer& font, uint16_t chr);
|
void drawtext(const shared_ptr<font_ref>& font, xcb_pixmap_t pm, xcb_gcontext_t gc, int16_t x, int16_t y,
|
||||||
|
const uint16_t* chars, size_t num_chars);
|
||||||
XftColor* xftcolor();
|
|
||||||
XftDraw* xftdraw();
|
|
||||||
|
|
||||||
void create_xftdraw(xcb_pixmap_t pm);
|
|
||||||
void destroy_xftdraw();
|
|
||||||
|
|
||||||
void allocate_color(uint32_t color);
|
void allocate_color(uint32_t color);
|
||||||
void allocate_color(XRenderColor color);
|
void allocate_color(XRenderColor color);
|
||||||
|
|
||||||
void set_gcontext_font(xcb_gcontext_t gc, xcb_font_t font);
|
void set_gcontext_font(const shared_ptr<font_ref>& font, xcb_gcontext_t, xcb_font_t*);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool open_xcb_font(fonttype_pointer& fontptr, string fontname);
|
bool open_xcb_font(const shared_ptr<font_ref>& font, string fontname);
|
||||||
bool has_glyph(fonttype_pointer& font, uint16_t chr);
|
|
||||||
|
uint8_t glyph_width_xft(const shared_ptr<font_ref>& font, const uint16_t chr);
|
||||||
|
uint8_t glyph_width_xcb(const shared_ptr<font_ref>& font, const uint16_t chr);
|
||||||
|
|
||||||
|
bool has_glyph_xft(const shared_ptr<font_ref>& font, const uint16_t chr);
|
||||||
|
bool has_glyph_xcb(const shared_ptr<font_ref>& font, const uint16_t chr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
connection& m_connection;
|
connection& m_connection;
|
||||||
const logger& m_logger;
|
const logger& m_logger;
|
||||||
|
|
||||||
shared_ptr<Display> m_display{nullptr};
|
shared_ptr<Display> m_display;
|
||||||
shared_ptr<Visual> m_visual{nullptr};
|
shared_ptr<Visual> m_visual;
|
||||||
Colormap m_colormap{};
|
Colormap m_colormap;
|
||||||
|
|
||||||
std::map<uint8_t, fonttype_pointer> m_fonts;
|
map<uint8_t, shared_ptr<font_ref>> m_fonts{};
|
||||||
int8_t m_fontindex{DEFAULT_FONT_INDEX};
|
int8_t m_fontindex{DEFAULT_FONT_INDEX};
|
||||||
|
|
||||||
XftColor* m_xftcolor{nullptr};
|
|
||||||
XftDraw* m_xftdraw{nullptr};
|
XftDraw* m_xftdraw{nullptr};
|
||||||
|
XftColor m_xftcolor{};
|
||||||
|
bool m_xftcolor_allocated{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -140,6 +140,7 @@ make_executable(${PROJECT_NAME} SOURCES
|
|||||||
target_link_libraries(${PROJECT_NAME} Threads::Threads)
|
target_link_libraries(${PROJECT_NAME} Threads::Threads)
|
||||||
|
|
||||||
target_compile_definitions(${PROJECT_NAME} PUBLIC
|
target_compile_definitions(${PROJECT_NAME} PUBLIC
|
||||||
|
${X11_Xft_DEFINITIONS}
|
||||||
${X11_XCB_DEFINITIONS}
|
${X11_XCB_DEFINITIONS}
|
||||||
${XCB_DEFINITIONS})
|
${XCB_DEFINITIONS})
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "events/signal.hpp"
|
#include "events/signal.hpp"
|
||||||
#include "events/signal_emitter.hpp"
|
#include "events/signal_emitter.hpp"
|
||||||
#include "utils/math.hpp"
|
#include "utils/math.hpp"
|
||||||
|
#include "utils/memory.hpp"
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
@ -29,8 +30,7 @@ void parser::operator()(string data) {
|
|||||||
} else if ((pos = data.find("%{")) != string::npos) {
|
} else if ((pos = data.find("%{")) != string::npos) {
|
||||||
data.erase(0, text(data.substr(0, pos)));
|
data.erase(0, text(data.substr(0, pos)));
|
||||||
} else {
|
} else {
|
||||||
text(move(data));
|
data.erase(0, text(data.substr(0)));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,20 +155,32 @@ void parser::codeblock(string&& data) {
|
|||||||
* Process text contents
|
* Process text contents
|
||||||
*/
|
*/
|
||||||
size_t parser::text(string&& data) {
|
size_t parser::text(string&& data) {
|
||||||
uint8_t* utf = reinterpret_cast<uint8_t*>(const_cast<char*>(data.c_str()));
|
const uint8_t* utf{reinterpret_cast<const uint8_t*>(&data[0])};
|
||||||
|
|
||||||
if (utf[0] < 0x80) {
|
if (utf[0] < 0x80) {
|
||||||
// grab all consecutive ascii chars
|
size_t pos{0};
|
||||||
size_t next_tag = data.find("%{");
|
|
||||||
if (next_tag != string::npos) {
|
// grab consecutive ascii chars
|
||||||
data.erase(next_tag);
|
while (utf[pos] && utf[pos] < 0x80) {
|
||||||
|
packet pkt{};
|
||||||
|
size_t limit{memory_util::countof(pkt.data)};
|
||||||
|
size_t len{0};
|
||||||
|
|
||||||
|
while (len + 1 < limit && utf[pos] && utf[pos] < 0x80) {
|
||||||
|
pkt.data[len++] = utf[pos++];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!len) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt.length = len;
|
||||||
|
m_sig.emit(write_text_string{move(pkt)});
|
||||||
}
|
}
|
||||||
size_t n = 0;
|
|
||||||
while (utf[n] != '\0' && utf[++n] < 0x80) {
|
if (pos > 0) {
|
||||||
;
|
return pos;
|
||||||
}
|
}
|
||||||
m_sig.emit(write_text_string{data.substr(0, n)});
|
|
||||||
return n;
|
|
||||||
} else if ((utf[0] & 0xe0) == 0xc0) { // 2 byte utf-8 sequence
|
} else if ((utf[0] & 0xe0) == 0xc0) { // 2 byte utf-8 sequence
|
||||||
m_sig.emit(write_text_unicode{static_cast<uint16_t>((utf[0] & 0x1f) << 6 | (utf[1] & 0x3f))});
|
m_sig.emit(write_text_unicode{static_cast<uint16_t>((utf[0] & 0x1f) << 6 | (utf[1] & 0x3f))});
|
||||||
return 2;
|
return 2;
|
||||||
@ -185,10 +197,13 @@ size_t parser::text(string&& data) {
|
|||||||
} else if ((utf[0] & 0xfe) == 0xfc) { // 6 byte utf-8 sequence
|
} else if ((utf[0] & 0xfe) == 0xfc) { // 6 byte utf-8 sequence
|
||||||
m_sig.emit(write_text_unicode{static_cast<uint16_t>(0xfffd)});
|
m_sig.emit(write_text_unicode{static_cast<uint16_t>(0xfffd)});
|
||||||
return 6;
|
return 6;
|
||||||
} else { // invalid utf-8 sequence
|
|
||||||
m_sig.emit(write_text_ascii{utf[0]});
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (utf[0] < 0x80) {
|
||||||
|
m_sig.emit(write_text_ascii{utf[0]});
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,14 +47,17 @@ renderer::renderer(connection& conn, signal_emitter& emitter, const logger& logg
|
|||||||
|
|
||||||
if ((m_visual = m_connection.visual_type(m_connection.screen(), 32)) == nullptr) {
|
if ((m_visual = m_connection.visual_type(m_connection.screen(), 32)) == nullptr) {
|
||||||
m_log.err("No 32-bit TrueColor visual found...");
|
m_log.err("No 32-bit TrueColor visual found...");
|
||||||
|
|
||||||
|
if ((m_visual = m_connection.visual_type(m_connection.screen(), 24)) == nullptr) {
|
||||||
|
m_log.err("No 24-bit TrueColor visual found, aborting...");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_visual == nullptr) {
|
||||||
|
throw application_error("No matching TrueColor visual found...");
|
||||||
|
}
|
||||||
|
|
||||||
m_depth = 24;
|
m_depth = 24;
|
||||||
}
|
}
|
||||||
if ((m_visual = m_connection.visual_type(m_connection.screen(), 24)) == nullptr) {
|
|
||||||
m_log.err("No 24-bit TrueColor visual found, aborting...");
|
|
||||||
}
|
|
||||||
if (m_visual == nullptr) {
|
|
||||||
throw application_error("No matching TrueColor visual found...");
|
|
||||||
}
|
|
||||||
|
|
||||||
m_log.trace("renderer: Allocate colormap");
|
m_log.trace("renderer: Allocate colormap");
|
||||||
m_colormap = m_connection.generate_id();
|
m_colormap = m_connection.generate_id();
|
||||||
@ -66,7 +69,7 @@ renderer::renderer(connection& conn, signal_emitter& emitter, const logger& logg
|
|||||||
m_window = winspec(m_connection)
|
m_window = winspec(m_connection)
|
||||||
<< cw_size(m_bar.size)
|
<< cw_size(m_bar.size)
|
||||||
<< cw_pos(m_bar.pos)
|
<< cw_pos(m_bar.pos)
|
||||||
<< cw_depth(32)
|
<< cw_depth(m_depth)
|
||||||
<< cw_visual(m_visual->visual_id)
|
<< cw_visual(m_visual->visual_id)
|
||||||
<< cw_class(XCB_WINDOW_CLASS_INPUT_OUTPUT)
|
<< cw_class(XCB_WINDOW_CLASS_INPUT_OUTPUT)
|
||||||
<< cw_params_back_pixel(0)
|
<< cw_params_back_pixel(0)
|
||||||
@ -83,7 +86,7 @@ renderer::renderer(connection& conn, signal_emitter& emitter, const logger& logg
|
|||||||
|
|
||||||
m_log.trace("renderer: Allocate window pixmap");
|
m_log.trace("renderer: Allocate window pixmap");
|
||||||
m_pixmap = m_connection.generate_id();
|
m_pixmap = m_connection.generate_id();
|
||||||
m_connection.create_pixmap(32, m_pixmap, m_window, m_rect.width, m_rect.height);
|
m_connection.create_pixmap(m_depth, m_pixmap, m_window, m_rect.width, m_rect.height);
|
||||||
|
|
||||||
m_log.trace("renderer: Allocate graphic contexts");
|
m_log.trace("renderer: Allocate graphic contexts");
|
||||||
{
|
{
|
||||||
@ -180,8 +183,6 @@ void renderer::begin() {
|
|||||||
m_currentx = 0;
|
m_currentx = 0;
|
||||||
m_attributes = 0;
|
m_attributes = 0;
|
||||||
m_actions.clear();
|
m_actions.clear();
|
||||||
|
|
||||||
m_fontmanager->create_xftdraw(m_pixmap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -190,7 +191,7 @@ void renderer::begin() {
|
|||||||
void renderer::end() {
|
void renderer::end() {
|
||||||
m_log.trace_x("renderer: end");
|
m_log.trace_x("renderer: end");
|
||||||
|
|
||||||
m_fontmanager->destroy_xftdraw();
|
m_fontmanager->cleanup();
|
||||||
|
|
||||||
#ifdef DEBUG_HINTS
|
#ifdef DEBUG_HINTS
|
||||||
debug_hints();
|
debug_hints();
|
||||||
@ -356,79 +357,39 @@ void renderer::fill_shift(const int16_t px) {
|
|||||||
shift_content(px);
|
shift_content(px);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw character glyph
|
|
||||||
*/
|
|
||||||
void renderer::draw_character(uint16_t character) {
|
|
||||||
m_log.trace_x("renderer: draw_character");
|
|
||||||
|
|
||||||
auto& font = m_fontmanager->match_char(character);
|
|
||||||
|
|
||||||
if (!font) {
|
|
||||||
return m_log.warn("No suitable font found (character=%i)", character);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (font->ptr && font->ptr != m_gcfont) {
|
|
||||||
m_gcfont = font->ptr;
|
|
||||||
m_fontmanager->set_gcontext_font(m_gcontexts.at(gc::FG), m_gcfont);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto width = m_fontmanager->char_width(font, character);
|
|
||||||
auto x = shift_content(width);
|
|
||||||
auto y = m_rect.height / 2 + font->height / 2 - font->descent + font->offset_y;
|
|
||||||
|
|
||||||
if (font->xft != nullptr) {
|
|
||||||
XftDrawString16(m_fontmanager->xftdraw(), m_fontmanager->xftcolor(), font->xft, x, y, &character, 1);
|
|
||||||
} else {
|
|
||||||
uint16_t ucs = ((character >> 8) | (character << 8));
|
|
||||||
draw_util::xcb_poly_text_16_patched(m_connection, m_pixmap, m_gcontexts.at(gc::FG), x, y, 1, &ucs);
|
|
||||||
}
|
|
||||||
|
|
||||||
fill_underline(x, width);
|
|
||||||
fill_overline(x, width);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw consecutive character glyphs
|
* Draw consecutive character glyphs
|
||||||
*/
|
*/
|
||||||
void renderer::draw_textstring(const char* text, size_t len) {
|
void renderer::draw_textstring(const uint16_t* text, size_t len) {
|
||||||
m_log.trace_x("renderer: draw_textstring(\"%s\")", text);
|
m_log.trace_x("renderer: draw_textstring(\"%s\")", text);
|
||||||
|
|
||||||
for (size_t n = 0; n < len; n++) {
|
for (size_t n = 0; n < len; n++) {
|
||||||
vector<uint16_t> chars;
|
vector<uint16_t> chars{text[n]};
|
||||||
chars.emplace_back(text[n]);
|
shared_ptr<font_ref> font{m_fontmanager->match_char(chars[0])};
|
||||||
|
uint8_t width{static_cast<const uint8_t>(m_fontmanager->glyph_width(font, chars[0]) * chars.size())};
|
||||||
auto& font = m_fontmanager->match_char(chars[0]);
|
|
||||||
|
|
||||||
if (!font) {
|
if (!font) {
|
||||||
return m_log.warn("No suitable font found (character=%i)", chars[0]);
|
m_log.warn("Could not find glyph for %i", chars[0]);
|
||||||
}
|
continue;
|
||||||
|
} else if (!width) {
|
||||||
if (font->ptr && font->ptr != m_gcfont) {
|
m_log.warn("Could not determine glyph width for %i", chars[0]);
|
||||||
m_gcfont = font->ptr;
|
continue;
|
||||||
m_fontmanager->set_gcontext_font(m_gcontexts.at(gc::FG), m_gcfont);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (n + 1 < len && text[n + 1] == chars[0]) {
|
while (n + 1 < len && text[n + 1] == chars[0]) {
|
||||||
chars.emplace_back(text[++n]);
|
chars.emplace_back(text[n++]);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto width = m_fontmanager->char_width(font, chars[0]) * chars.size();
|
width *= chars.size();
|
||||||
auto x = shift_content(width);
|
auto x = shift_content(width);
|
||||||
auto y = m_rect.height / 2 + font->height / 2 - font->descent + font->offset_y;
|
auto y = m_rect.height / 2 + font->height / 2 - font->descent + font->offset_y;
|
||||||
|
|
||||||
if (font->xft != nullptr) {
|
if (font->ptr != XCB_NONE && m_gcfont != font->ptr) {
|
||||||
XftDrawString16(m_fontmanager->xftdraw(), m_fontmanager->xftcolor(), font->xft, x, y,
|
m_fontmanager->set_gcontext_font(font, m_gcontexts.at(gc::FG), &m_gcfont);
|
||||||
static_cast<uint16_t*>(chars.data()), chars.size());
|
|
||||||
} else {
|
|
||||||
for (unsigned short& i : chars) {
|
|
||||||
i = ((i >> 8) | (i << 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
draw_util::xcb_poly_text_16_patched(
|
|
||||||
m_connection, m_pixmap, m_gcontexts.at(gc::FG), x, y, chars.size(), chars.data());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_fontmanager->drawtext(font, m_pixmap, m_gcontexts.at(gc::FG), x, y, chars.data(), chars.size());
|
||||||
|
|
||||||
fill_underline(x, width);
|
fill_underline(x, width);
|
||||||
fill_overline(x, width);
|
fill_overline(x, width);
|
||||||
}
|
}
|
||||||
@ -531,7 +492,7 @@ void renderer::debug_hints() {
|
|||||||
<< cw_size(action.width() - border_width * 2, m_rect.height - border_width * 2)
|
<< cw_size(action.width() - border_width * 2, m_rect.height - border_width * 2)
|
||||||
<< cw_pos(action.start_x + num * DEBUG_HINTS_OFFSET_X, m_bar.pos.y + m_rect.y + num * DEBUG_HINTS_OFFSET_Y)
|
<< cw_pos(action.start_x + num * DEBUG_HINTS_OFFSET_X, m_bar.pos.y + m_rect.y + num * DEBUG_HINTS_OFFSET_Y)
|
||||||
<< cw_border(border_width)
|
<< cw_border(border_width)
|
||||||
<< cw_depth(32)
|
<< cw_depth(m_depth)
|
||||||
<< cw_visual(m_visual->visual_id)
|
<< cw_visual(m_visual->visual_id)
|
||||||
<< cw_params_colormap(m_colormap)
|
<< cw_params_colormap(m_colormap)
|
||||||
<< cw_params_back_pixel(0)
|
<< cw_params_back_pixel(0)
|
||||||
@ -713,18 +674,20 @@ bool renderer::on(const action_end& evt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool renderer::on(const write_text_ascii& evt) {
|
bool renderer::on(const write_text_ascii& evt) {
|
||||||
draw_character(*evt());
|
const uint16_t data[1]{*evt()};
|
||||||
|
draw_textstring(data, 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool renderer::on(const write_text_unicode& evt) {
|
bool renderer::on(const write_text_unicode& evt) {
|
||||||
draw_character(*evt());
|
const uint16_t data[1]{*evt()};
|
||||||
|
draw_textstring(data, 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool renderer::on(const write_text_string& evt) {
|
bool renderer::on(const write_text_string& evt) {
|
||||||
string text{*evt()};
|
parser::packet pkt{(*evt())};
|
||||||
draw_textstring(text.c_str(), text.size());
|
draw_textstring(pkt.data, pkt.length);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,55 +6,63 @@
|
|||||||
#include "utils/factory.hpp"
|
#include "utils/factory.hpp"
|
||||||
#include "utils/memory.hpp"
|
#include "utils/memory.hpp"
|
||||||
#include "x11/connection.hpp"
|
#include "x11/connection.hpp"
|
||||||
|
#include "x11/draw.hpp"
|
||||||
#include "x11/fonts.hpp"
|
#include "x11/fonts.hpp"
|
||||||
#include "x11/xlib.hpp"
|
#include "x11/xlib.hpp"
|
||||||
#include "x11/xutils.hpp"
|
#include "x11/xutils.hpp"
|
||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
#define XFT_MAXCHARS (1 << 16)
|
void font_ref::_deleter::operator()(font_ref* font) {
|
||||||
|
font->glyph_widths.clear();
|
||||||
|
font->width_lut.clear();
|
||||||
|
|
||||||
array<char, XFT_MAXCHARS> g_xft_widths;
|
if (font->xft != nullptr) {
|
||||||
array<wchar_t, XFT_MAXCHARS> g_xft_chars;
|
XftFontClose(xlib::get_display().get(), font->xft);
|
||||||
|
}
|
||||||
|
if (font->ptr != XCB_NONE) {
|
||||||
|
xcb_close_font(xutils::get_connection().get(), font->ptr);
|
||||||
|
}
|
||||||
|
delete font;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create instance
|
* Create instance
|
||||||
*/
|
*/
|
||||||
font_manager::make_type font_manager::make() {
|
font_manager::make_type font_manager::make() {
|
||||||
return factory_util::unique<font_manager>(
|
return factory_util::unique<font_manager>(
|
||||||
connection::make(), logger::make(), xlib::get_display(), xlib::get_visual());
|
connection::make(), logger::make(), xlib::get_display(), xlib::get_visual(), xlib::create_colormap());
|
||||||
}
|
}
|
||||||
|
|
||||||
void fonttype_deleter::operator()(fonttype* f) {
|
font_manager::font_manager(
|
||||||
if (f->xft != nullptr) {
|
connection& conn, const logger& logger, shared_ptr<Display>&& dsp, shared_ptr<Visual>&& vis, Colormap&& cm)
|
||||||
XftFontClose(xlib::get_display().get(), f->xft);
|
|
||||||
free(f->xft);
|
|
||||||
}
|
|
||||||
if (f->ptr != XCB_NONE) {
|
|
||||||
connection::make().close_font(f->ptr);
|
|
||||||
}
|
|
||||||
delete f;
|
|
||||||
}
|
|
||||||
|
|
||||||
font_manager::font_manager(connection& conn, const logger& logger, shared_ptr<Display>&& dsp, shared_ptr<Visual>&& vis)
|
|
||||||
: m_connection(conn)
|
: m_connection(conn)
|
||||||
, m_logger(logger)
|
, m_logger(logger)
|
||||||
, m_display(forward<decltype(dsp)>(dsp))
|
, m_display(forward<decltype(dsp)>(dsp))
|
||||||
, m_visual(forward<decltype(vis)>(vis)) {
|
, m_visual(forward<decltype(vis)>(vis))
|
||||||
m_colormap = xlib::create_colormap(conn.default_screen());
|
, m_colormap(forward<decltype(cm)>(cm)) {
|
||||||
|
if (!XftInit(nullptr) || !XftInitFtLibrary()) {
|
||||||
|
throw application_error("Could not initialize Xft library");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
font_manager::~font_manager() {
|
font_manager::~font_manager() {
|
||||||
|
cleanup();
|
||||||
if (m_display) {
|
if (m_display) {
|
||||||
if (m_xftcolor != nullptr) {
|
if (m_xftcolor_allocated) {
|
||||||
XftColorFree(m_display.get(), m_visual.get(), m_colormap, m_xftcolor);
|
XftColorFree(m_display.get(), m_visual.get(), m_colormap, &m_xftcolor);
|
||||||
free(m_xftcolor);
|
|
||||||
}
|
}
|
||||||
destroy_xftdraw();
|
|
||||||
XFreeColormap(m_display.get(), m_colormap);
|
XFreeColormap(m_display.get(), m_colormap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void font_manager::cleanup() {
|
||||||
|
if (m_xftdraw != nullptr) {
|
||||||
|
XftDrawDestroy(m_xftdraw);
|
||||||
|
m_xftdraw = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool font_manager::load(const string& name, int8_t fontindex, int8_t offset_y) {
|
bool font_manager::load(const string& name, int8_t fontindex, int8_t offset_y) {
|
||||||
if (fontindex != DEFAULT_FONT_INDEX && m_fonts.find(fontindex) != m_fonts.end()) {
|
if (fontindex != DEFAULT_FONT_INDEX && m_fonts.find(fontindex) != m_fonts.end()) {
|
||||||
m_logger.warn("A font with index '%i' has already been loaded, skip...", fontindex);
|
m_logger.warn("A font with index '%i' has already been loaded, skip...", fontindex);
|
||||||
@ -66,39 +74,40 @@ bool font_manager::load(const string& name, int8_t fontindex, int8_t offset_y) {
|
|||||||
m_logger.trace("font_manager: Add font '%s' to index '%i'", name, fontindex);
|
m_logger.trace("font_manager: Add font '%s' to index '%i'", name, fontindex);
|
||||||
}
|
}
|
||||||
|
|
||||||
fonttype_pointer f{new fonttype_pointer::element_type{}, fonttype_deleter{}};
|
shared_ptr<font_ref> font{new font_ref{}, font_ref::deleter};
|
||||||
f->offset_y = offset_y;
|
|
||||||
|
|
||||||
if (open_xcb_font(f, name)) {
|
font->offset_y = offset_y;
|
||||||
|
|
||||||
|
if (open_xcb_font(font, name)) {
|
||||||
m_logger.info("Loaded font (xlfd=%s)", name);
|
m_logger.info("Loaded font (xlfd=%s)", name);
|
||||||
} else if (f->ptr != XCB_NONE) {
|
} else if (font->ptr != XCB_NONE) {
|
||||||
m_connection.close_font_checked(f->ptr);
|
m_connection.close_font_checked(font->ptr);
|
||||||
f->ptr = XCB_NONE;
|
font->ptr = XCB_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f->ptr == XCB_NONE &&
|
if (font->ptr == XCB_NONE &&
|
||||||
(f->xft = XftFontOpenName(m_display.get(), m_connection.default_screen(), name.c_str())) != nullptr) {
|
(font->xft = XftFontOpenName(m_display.get(), m_connection.default_screen(), name.c_str())) != nullptr) {
|
||||||
f->ascent = f->xft->ascent;
|
font->ascent = font->xft->ascent;
|
||||||
f->descent = f->xft->descent;
|
font->descent = font->xft->descent;
|
||||||
f->height = f->ascent + f->descent;
|
font->height = font->ascent + font->descent;
|
||||||
|
|
||||||
if (f->xft->pattern != nullptr) {
|
if (font->xft->pattern != nullptr) {
|
||||||
FcChar8* file{nullptr};
|
// XftChar8* file;
|
||||||
FcPatternGetString(f->xft->pattern, "file", 0, &file);
|
// XftPatternGetString(font->xft->pattern, "file", 0, &file);
|
||||||
m_logger.info("Loaded font (pattern=%s, file=%s)", name, file);
|
// m_logger.info("Loaded font (pattern=%s, file=%s)", name, file);
|
||||||
free(file);
|
m_logger.info("Loaded font (pattern=%s)", name);
|
||||||
} else {
|
} else {
|
||||||
m_logger.info("Loaded font (pattern=%s)", name);
|
m_logger.info("Loaded font (pattern=%s)", name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f->ptr == XCB_NONE && f->xft == nullptr) {
|
if (font->ptr == XCB_NONE && font->xft == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_fonts.emplace(make_pair(fontindex, move(f)));
|
m_fonts.emplace(make_pair(fontindex, move(font)));
|
||||||
|
|
||||||
int max_height = 0;
|
int max_height{0};
|
||||||
|
|
||||||
for (auto& iter : m_fonts) {
|
for (auto& iter : m_fonts) {
|
||||||
if (iter.second->height > max_height) {
|
if (iter.second->height > max_height) {
|
||||||
@ -127,112 +136,95 @@ void font_manager::set_preferred_font(int8_t index) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fonttype_pointer& font_manager::match_char(uint16_t chr) {
|
shared_ptr<font_ref> font_manager::match_char(const uint16_t chr) {
|
||||||
static fonttype_pointer notfound;
|
if (m_fonts.empty()) {
|
||||||
if (!m_fonts.empty()) {
|
return {};
|
||||||
if (m_fontindex != DEFAULT_FONT_INDEX && size_t(m_fontindex) <= m_fonts.size()) {
|
}
|
||||||
auto iter = m_fonts.find(m_fontindex);
|
|
||||||
if (iter != m_fonts.end() && has_glyph(iter->second, chr)) {
|
if (m_fontindex != DEFAULT_FONT_INDEX && static_cast<size_t>(m_fontindex) <= m_fonts.size()) {
|
||||||
return iter->second;
|
auto iter = m_fonts.find(m_fontindex);
|
||||||
}
|
if (iter == m_fonts.end() || !iter->second) {
|
||||||
}
|
return {};
|
||||||
for (auto& font : m_fonts) {
|
} else if (has_glyph_xft(iter->second, chr)) {
|
||||||
if (has_glyph(font.second, chr)) {
|
return iter->second;
|
||||||
return font.second;
|
} else if (has_glyph_xcb(iter->second, chr)) {
|
||||||
}
|
return iter->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return notfound;
|
|
||||||
|
for (auto&& font : m_fonts) {
|
||||||
|
if (!font.second) {
|
||||||
|
return {};
|
||||||
|
} else if (has_glyph_xft(font.second, chr)) {
|
||||||
|
return font.second;
|
||||||
|
} else if (has_glyph_xcb(font.second, chr)) {
|
||||||
|
return font.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t font_manager::char_width(fonttype_pointer& font, uint16_t chr) {
|
uint8_t font_manager::glyph_width(const shared_ptr<font_ref>& font, const uint16_t chr) {
|
||||||
if (!font) {
|
if (font && font->xft != nullptr) {
|
||||||
|
return glyph_width_xft(move(font), chr);
|
||||||
|
} else if (font && font->ptr != XCB_NONE) {
|
||||||
|
return glyph_width_xcb(move(font), chr);
|
||||||
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (font->xft == nullptr) {
|
void font_manager::drawtext(const shared_ptr<font_ref>& font, xcb_pixmap_t pm, xcb_gcontext_t gc, int16_t x, int16_t y,
|
||||||
if (static_cast<size_t>(chr - font->char_min) < font->width_lut.size()) {
|
const uint16_t* chars, size_t num_chars) {
|
||||||
return font->width_lut[chr - font->char_min].character_width;
|
if (m_xftdraw == nullptr) {
|
||||||
} else {
|
m_xftdraw = XftDrawCreate(m_display.get(), pm, m_visual.get(), m_colormap);
|
||||||
return font->width;
|
}
|
||||||
|
if (font->xft != nullptr) {
|
||||||
|
XftDrawString16(m_xftdraw, &m_xftcolor, font->xft, x, y, chars, num_chars);
|
||||||
|
} else if (font->ptr != XCB_NONE) {
|
||||||
|
uint16_t* ucs = static_cast<uint16_t*>(calloc(num_chars, sizeof(uint16_t)));
|
||||||
|
for (size_t i = 0; i < num_chars; i++) {
|
||||||
|
ucs[i] = ((chars[i] >> 8) | (chars[i] << 8));
|
||||||
}
|
}
|
||||||
}
|
draw_util::xcb_poly_text_16_patched(m_connection, pm, gc, x, y, num_chars, ucs);
|
||||||
|
|
||||||
auto index = chr % XFT_MAXCHARS;
|
|
||||||
while (g_xft_chars[index] != 0 && g_xft_chars[index] != chr) {
|
|
||||||
index = (index + 1) % XFT_MAXCHARS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!g_xft_chars[index]) {
|
|
||||||
XGlyphInfo gi;
|
|
||||||
FT_UInt glyph = XftCharIndex(m_display.get(), font->xft, static_cast<FcChar32>(chr));
|
|
||||||
XftFontLoadGlyphs(m_display.get(), font->xft, FcFalse, &glyph, 1);
|
|
||||||
XftGlyphExtents(m_display.get(), font->xft, &glyph, 1, &gi);
|
|
||||||
XftFontUnloadGlyphs(m_display.get(), font->xft, &glyph, 1);
|
|
||||||
g_xft_chars[index] = chr;
|
|
||||||
g_xft_widths[index] = gi.xOff;
|
|
||||||
return gi.xOff;
|
|
||||||
} else if (g_xft_chars[index] == chr) {
|
|
||||||
return g_xft_widths[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
XftColor* font_manager::xftcolor() {
|
|
||||||
return m_xftcolor;
|
|
||||||
}
|
|
||||||
|
|
||||||
XftDraw* font_manager::xftdraw() {
|
|
||||||
return m_xftdraw;
|
|
||||||
}
|
|
||||||
|
|
||||||
void font_manager::create_xftdraw(xcb_pixmap_t pm) {
|
|
||||||
destroy_xftdraw();
|
|
||||||
m_xftdraw = XftDrawCreate(m_display.get(), pm, m_visual.get(), m_colormap);
|
|
||||||
}
|
|
||||||
|
|
||||||
void font_manager::destroy_xftdraw() {
|
|
||||||
if (m_xftdraw != nullptr) {
|
|
||||||
XftDrawDestroy(m_xftdraw);
|
|
||||||
m_xftdraw = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void font_manager::allocate_color(uint32_t color) {
|
void font_manager::allocate_color(uint32_t color) {
|
||||||
XRenderColor x;
|
// clang-format off
|
||||||
x.red = color_util::red_channel<uint16_t>(color);
|
XRenderColor x{
|
||||||
x.green = color_util::green_channel<uint16_t>(color);
|
color_util::red_channel<uint16_t>(color),
|
||||||
x.blue = color_util::blue_channel<uint16_t>(color);
|
color_util::green_channel<uint16_t>(color),
|
||||||
x.alpha = color_util::alpha_channel<uint16_t>(color);
|
color_util::blue_channel<uint16_t>(color),
|
||||||
|
color_util::alpha_channel<uint16_t>(color)};
|
||||||
|
// clang-format on
|
||||||
allocate_color(x);
|
allocate_color(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
void font_manager::allocate_color(XRenderColor color) {
|
void font_manager::allocate_color(XRenderColor color) {
|
||||||
if (m_xftcolor != nullptr) {
|
if (m_xftcolor_allocated) {
|
||||||
XftColorFree(m_display.get(), m_visual.get(), m_colormap, m_xftcolor);
|
XftColorFree(m_display.get(), m_visual.get(), m_colormap, &m_xftcolor);
|
||||||
free(m_xftcolor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_xftcolor = static_cast<XftColor*>(malloc(sizeof(XftColor)));
|
if (!(m_xftcolor_allocated = XftColorAllocValue(m_display.get(), m_visual.get(), m_colormap, &color, &m_xftcolor))) {
|
||||||
|
|
||||||
if (!XftColorAllocValue(m_display.get(), m_visual.get(), m_colormap, &color, m_xftcolor)) {
|
|
||||||
m_logger.err("Failed to allocate color");
|
m_logger.err("Failed to allocate color");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void font_manager::set_gcontext_font(xcb_gcontext_t gc, xcb_font_t font) {
|
void font_manager::set_gcontext_font(const shared_ptr<font_ref>& font, xcb_gcontext_t gc, xcb_font_t* xcb_font) {
|
||||||
const uint32_t values[1]{font};
|
const uint32_t val[1]{*xcb_font};
|
||||||
m_connection.change_gc(gc, XCB_GC_FONT, values);
|
m_connection.change_gc(gc, XCB_GC_FONT, val);
|
||||||
|
*xcb_font = font->ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool font_manager::open_xcb_font(fonttype_pointer& fontptr, string fontname) {
|
bool font_manager::open_xcb_font(const shared_ptr<font_ref>& font, string fontname) {
|
||||||
try {
|
try {
|
||||||
uint32_t font_id{m_connection.generate_id()};
|
uint32_t font_id{m_connection.generate_id()};
|
||||||
m_connection.open_font_checked(font_id, fontname);
|
m_connection.open_font_checked(font_id, fontname);
|
||||||
|
|
||||||
m_logger.trace("Found X font '%s'", fontname);
|
m_logger.trace("Found X font '%s'", fontname);
|
||||||
fontptr->ptr = font_id;
|
font->ptr = font_id;
|
||||||
|
|
||||||
auto query = m_connection.query_font(font_id);
|
auto query = m_connection.query_font(font_id);
|
||||||
if (query->char_infos_len == 0) {
|
if (query->char_infos_len == 0) {
|
||||||
@ -240,15 +232,15 @@ bool font_manager::open_xcb_font(fonttype_pointer& fontptr, string fontname) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fontptr->descent = query->font_descent;
|
font->descent = query->font_descent;
|
||||||
fontptr->height = query->font_ascent + query->font_descent;
|
font->height = query->font_ascent + query->font_descent;
|
||||||
fontptr->width = query->max_bounds.character_width;
|
font->width = query->max_bounds.character_width;
|
||||||
fontptr->char_max = query->max_byte1 << 8 | query->max_char_or_byte2;
|
font->char_max = query->max_byte1 << 8 | query->max_char_or_byte2;
|
||||||
fontptr->char_min = query->min_byte1 << 8 | query->min_char_or_byte2;
|
font->char_min = query->min_byte1 << 8 | query->min_char_or_byte2;
|
||||||
|
|
||||||
auto chars = query.char_infos();
|
auto chars = query.char_infos();
|
||||||
for (auto it = chars.begin(); it != chars.end(); it++) {
|
for (auto it = chars.begin(); it != chars.end(); it++) {
|
||||||
fontptr->width_lut.emplace_back(forward<xcb_charinfo_t>(*it));
|
font->width_lut.emplace_back(forward<xcb_charinfo_t>(*it));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
@ -258,19 +250,54 @@ bool font_manager::open_xcb_font(fonttype_pointer& fontptr, string fontname) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool font_manager::has_glyph(fonttype_pointer& font, uint16_t chr) {
|
uint8_t font_manager::glyph_width_xft(const shared_ptr<font_ref>& font, const uint16_t chr) {
|
||||||
if (font->xft != nullptr) {
|
auto it = font->glyph_widths.find(chr);
|
||||||
return static_cast<bool>(XftCharExists(m_display.get(), font->xft, static_cast<FcChar32>(chr)));
|
if (it != font->glyph_widths.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
XGlyphInfo extents{};
|
||||||
|
FT_UInt glyph{XftCharIndex(m_display.get(), font->xft, static_cast<FcChar32>(chr))};
|
||||||
|
|
||||||
|
XftFontLoadGlyphs(m_display.get(), font->xft, FcFalse, &glyph, 1);
|
||||||
|
XftGlyphExtents(m_display.get(), font->xft, &glyph, 1, &extents);
|
||||||
|
XftFontUnloadGlyphs(m_display.get(), font->xft, &glyph, 1);
|
||||||
|
|
||||||
|
font->glyph_widths.emplace_hint(it, chr, extents.xOff); //.emplace_back(chr, extents.xOff);
|
||||||
|
|
||||||
|
return extents.xOff;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t font_manager::glyph_width_xcb(const shared_ptr<font_ref>& font, const uint16_t chr) {
|
||||||
|
if (!font || font->ptr == XCB_NONE) {
|
||||||
|
return 0;
|
||||||
|
} else if (static_cast<size_t>(chr - font->char_min) < font->width_lut.size()) {
|
||||||
|
return font->width_lut[chr - font->char_min].character_width;
|
||||||
|
} else {
|
||||||
|
return font->width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool font_manager::has_glyph_xft(const shared_ptr<font_ref>& font, const uint16_t chr) {
|
||||||
|
if (!font || font->xft == nullptr) {
|
||||||
|
return false;
|
||||||
|
} else if (XftCharExists(m_display.get(), font->xft, static_cast<FcChar32>(chr)) == FcFalse) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool font_manager::has_glyph_xcb(const shared_ptr<font_ref>& font, const uint16_t chr) {
|
||||||
|
if (font->ptr == XCB_NONE) {
|
||||||
|
return false;
|
||||||
|
} else if (chr < font->char_min || chr > font->char_max) {
|
||||||
|
return false;
|
||||||
|
} else if (static_cast<size_t>(chr - font->char_min) >= font->width_lut.size()) {
|
||||||
|
return false;
|
||||||
|
} else if (font->width_lut[chr - font->char_min].character_width == 0) {
|
||||||
|
return false;
|
||||||
} else {
|
} else {
|
||||||
if (chr < font->char_min || chr > font->char_max) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (static_cast<size_t>(chr - font->char_min) >= font->width_lut.size()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (font->width_lut[chr - font->char_min].character_width == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user