#pragma once #include #include #include #include "common.hpp" #include "utils/string.hpp" POLYBAR_NS namespace cairo { namespace utils { /** * @brief RAII wrapper used acquire cairo_device_t */ class device_lock { public: explicit device_lock(cairo_device_t* device) { auto status = cairo_device_acquire(device); if (status == CAIRO_STATUS_SUCCESS) { m_device = device; } } ~device_lock() { cairo_device_release(m_device); } operator bool() const { return m_device != nullptr; } operator cairo_device_t*() const { return m_device; } private: cairo_device_t* m_device{nullptr}; }; /** * @brief RAII wrapper used to access the underlying * FT_Face of a scaled font face */ class ft_face_lock { public: explicit ft_face_lock(cairo_scaled_font_t* font) : m_font(font) { m_face = cairo_ft_scaled_font_lock_face(m_font); } ~ft_face_lock() { cairo_ft_scaled_font_unlock_face(m_font); } operator FT_Face() const { return m_face; } private: cairo_scaled_font_t* m_font; FT_Face m_face; }; /** * @brief Unicode character containing converted codepoint * and details on where its position in the source string */ struct unicode_character { explicit unicode_character() : codepoint(0), offset(0), length(0) {} unsigned long codepoint; int offset; int length; }; using unicode_charlist = std::list; /** * @see */ cairo_operator_t str2operator(const string& mode, cairo_operator_t fallback) { if (mode.empty()) { return fallback; } static std::map modes; if (modes.empty()) { modes["clear"s] = CAIRO_OPERATOR_CLEAR; modes["source"s] = CAIRO_OPERATOR_SOURCE; modes["over"s] = CAIRO_OPERATOR_OVER; modes["in"s] = CAIRO_OPERATOR_IN; modes["out"s] = CAIRO_OPERATOR_OUT; modes["atop"s] = CAIRO_OPERATOR_ATOP; modes["dest"s] = CAIRO_OPERATOR_DEST; modes["dest-over"s] = CAIRO_OPERATOR_DEST_OVER; modes["dest-in"s] = CAIRO_OPERATOR_DEST_IN; modes["dest-out"s] = CAIRO_OPERATOR_DEST_OUT; modes["dest-atop"s] = CAIRO_OPERATOR_DEST_ATOP; modes["xor"s] = CAIRO_OPERATOR_XOR; modes["add"s] = CAIRO_OPERATOR_ADD; modes["saturate"s] = CAIRO_OPERATOR_SATURATE; modes["multiply"s] = CAIRO_OPERATOR_MULTIPLY; modes["screen"s] = CAIRO_OPERATOR_SCREEN; modes["overlay"s] = CAIRO_OPERATOR_OVERLAY; modes["darken"s] = CAIRO_OPERATOR_DARKEN; modes["lighten"s] = CAIRO_OPERATOR_LIGHTEN; modes["color-dodge"s] = CAIRO_OPERATOR_COLOR_DODGE; modes["color-burn"s] = CAIRO_OPERATOR_COLOR_BURN; modes["hard-light"s] = CAIRO_OPERATOR_HARD_LIGHT; modes["soft-light"s] = CAIRO_OPERATOR_SOFT_LIGHT; modes["difference"s] = CAIRO_OPERATOR_DIFFERENCE; modes["exclusion"s] = CAIRO_OPERATOR_EXCLUSION; modes["hsl-hue"s] = CAIRO_OPERATOR_HSL_HUE; modes["hsl-saturation"s] = CAIRO_OPERATOR_HSL_SATURATION; modes["hsl-color"s] = CAIRO_OPERATOR_HSL_COLOR; modes["hsl-luminosity"s] = CAIRO_OPERATOR_HSL_LUMINOSITY; } auto it = modes.find(mode); return it != modes.end() ? it->second : fallback; } /** * @brief Create a UCS-4 codepoint from a utf-8 encoded string */ bool utf8_to_ucs4(const unsigned char* src, unicode_charlist& result_list) { if (!src) { return false; } const unsigned char* first = src; while (*first) { int len = 0; unsigned long result = 0; if ((*first >> 7) == 0) { len = 1; result = *first; } else if ((*first >> 5) == 6) { len = 2; result = *first & 31; } else if ((*first >> 4) == 14) { len = 3; result = *first & 15; } else if ((*first >> 3) == 30) { len = 4; result = *first & 7; } else { return false; } const unsigned char* next; for (next = first + 1; *next && ((*next >> 6) == 2) && (next - first < len); next++) { result = result << 6; result |= *next & 63; } unicode_character uc_char; uc_char.codepoint = result; uc_char.offset = first - src; uc_char.length = next - first; result_list.push_back(uc_char); first = next; } return true; } /** * @brief Convert a UCS-4 codepoint to a utf-8 encoded string */ size_t ucs4_to_utf8(char* utf8, unsigned int ucs) { if (ucs <= 0x7f) { *utf8 = ucs; return 1; } else if (ucs <= 0x07ff) { *(utf8++) = ((ucs >> 6) & 0xff) | 0xc0; *utf8 = (ucs & 0x3f) | 0x80; return 2; } else if (ucs <= 0xffff) { *(utf8++) = ((ucs >> 12) & 0x0f) | 0xe0; *(utf8++) = ((ucs >> 6) & 0x3f) | 0x80; *utf8 = (ucs & 0x3f) | 0x80; return 3; } else if (ucs <= 0x1fffff) { *(utf8++) = ((ucs >> 18) & 0x07) | 0xf0; *(utf8++) = ((ucs >> 12) & 0x3f) | 0x80; *(utf8++) = ((ucs >> 6) & 0x3f) | 0x80; *utf8 = (ucs & 0x3f) | 0x80; return 4; } else if (ucs <= 0x03ffffff) { *(utf8++) = ((ucs >> 24) & 0x03) | 0xf8; *(utf8++) = ((ucs >> 18) & 0x3f) | 0x80; *(utf8++) = ((ucs >> 12) & 0x3f) | 0x80; *(utf8++) = ((ucs >> 6) & 0x3f) | 0x80; *utf8 = (ucs & 0x3f) | 0x80; return 5; } else if (ucs <= 0x7fffffff) { *(utf8++) = ((ucs >> 30) & 0x01) | 0xfc; *(utf8++) = ((ucs >> 24) & 0x3f) | 0x80; *(utf8++) = ((ucs >> 18) & 0x3f) | 0x80; *(utf8++) = ((ucs >> 12) & 0x3f) | 0x80; *(utf8++) = ((ucs >> 6) & 0x3f) | 0x80; *utf8 = (ucs & 0x3f) | 0x80; return 6; } else { return 0; } } } } POLYBAR_NS_END