text_block.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #pragma once
  8. #include "base/flags.h"
  9. #include "ui/text/text_custom_emoji.h"
  10. #include "ui/style/style_core.h"
  11. #include "ui/emoji_config.h"
  12. #include <crl/crl_time.h>
  13. #include <private/qfixed_p.h>
  14. namespace style {
  15. struct TextStyle;
  16. } // namespace style
  17. namespace Ui::Text {
  18. enum class TextBlockType : uint16 {
  19. Newline = 0x01,
  20. Text = 0x02,
  21. Emoji = 0x03,
  22. CustomEmoji = 0x04,
  23. Skip = 0x05,
  24. };
  25. enum class TextBlockFlag : uint16 {
  26. Bold = 0x001,
  27. Italic = 0x002,
  28. Underline = 0x004,
  29. StrikeOut = 0x008,
  30. Tilde = 0x010, // Tilde fix in OpenSans.
  31. Semibold = 0x020,
  32. Code = 0x040,
  33. Pre = 0x080,
  34. Spoiler = 0x100,
  35. Blockquote = 0x200,
  36. };
  37. inline constexpr bool is_flag_type(TextBlockFlag) { return true; }
  38. using TextBlockFlags = base::flags<TextBlockFlag>;
  39. [[nodiscard]] style::font WithFlags(
  40. const style::font &font,
  41. TextBlockFlags flags,
  42. style::FontFlags fontFlags = 0);
  43. [[nodiscard]] Qt::LayoutDirection UnpackParagraphDirection(
  44. bool ltr,
  45. bool rtl);
  46. struct BlockDescriptor {
  47. uint16 position = 0;
  48. TextBlockFlags flags;
  49. uint16 linkIndex = 0;
  50. uint16 colorIndex = 0;
  51. };
  52. class AbstractBlock {
  53. public:
  54. [[nodiscard]] uint16 position() const;
  55. [[nodiscard]] TextBlockType type() const;
  56. [[nodiscard]] TextBlockFlags flags() const;
  57. [[nodiscard]] int objectWidth() const;
  58. [[nodiscard]] uint16 colorIndex() const;
  59. [[nodiscard]] uint16 linkIndex() const;
  60. void setLinkIndex(uint16 index);
  61. protected:
  62. AbstractBlock(TextBlockType type, BlockDescriptor descriptor);
  63. uint16 _position = 0;
  64. uint16 _type : 4 = 0;
  65. uint16 _flags : 12 = 0;
  66. uint16 _linkIndex = 0;
  67. uint16 _colorIndex = 0;
  68. };
  69. class NewlineBlock final : public AbstractBlock {
  70. public:
  71. NewlineBlock(BlockDescriptor descriptor, uint16 quoteIndex);
  72. void setQuoteIndex(uint16 index) {
  73. _quoteIndex = index;
  74. }
  75. [[nodiscard]] uint16 quoteIndex() const {
  76. return _quoteIndex;
  77. }
  78. void setParagraphDirection(Qt::LayoutDirection direction) {
  79. _paragraphLTR = (direction == Qt::LeftToRight);
  80. _paragraphRTL = (direction == Qt::RightToLeft);
  81. }
  82. [[nodiscard]] Qt::LayoutDirection paragraphDirection() const {
  83. return UnpackParagraphDirection(_paragraphLTR, _paragraphRTL);
  84. }
  85. private:
  86. uint16 _quoteIndex = 0;
  87. bool _paragraphLTR : 1 = false;
  88. bool _paragraphRTL : 1 = false;
  89. };
  90. class TextBlock final : public AbstractBlock {
  91. public:
  92. explicit TextBlock(BlockDescriptor descriptor);
  93. };
  94. class EmojiBlock final : public AbstractBlock {
  95. public:
  96. EmojiBlock(BlockDescriptor descriptor, EmojiPtr emoji);
  97. [[nodiscard]] EmojiPtr emoji() const {
  98. return _emoji;
  99. }
  100. private:
  101. EmojiPtr _emoji = nullptr;
  102. };
  103. class CustomEmojiBlock final : public AbstractBlock {
  104. public:
  105. CustomEmojiBlock(
  106. BlockDescriptor descriptor,
  107. std::unique_ptr<CustomEmoji> custom);
  108. [[nodiscard]] not_null<CustomEmoji*> custom() const {
  109. return _custom.get();
  110. }
  111. private:
  112. std::unique_ptr<CustomEmoji> _custom;
  113. };
  114. class SkipBlock final : public AbstractBlock {
  115. public:
  116. SkipBlock(BlockDescriptor descriptor, int width, int height);
  117. [[nodiscard]] int width() const;
  118. [[nodiscard]] int height() const;
  119. private:
  120. int _width = 0;
  121. int _height = 0;
  122. };
  123. class Block final {
  124. public:
  125. Block();
  126. Block(Block &&other);
  127. Block &operator=(Block &&other);
  128. ~Block();
  129. [[nodiscard]] static Block Newline(
  130. BlockDescriptor descriptor,
  131. uint16 quoteIndex);
  132. [[nodiscard]] static Block Text(BlockDescriptor descriptor);
  133. [[nodiscard]] static Block Emoji(
  134. BlockDescriptor descriptor,
  135. EmojiPtr emoji);
  136. [[nodiscard]] static Block CustomEmoji(
  137. BlockDescriptor descriptor,
  138. std::unique_ptr<CustomEmoji> custom);
  139. [[nodiscard]] static Block Skip(
  140. BlockDescriptor descriptor,
  141. int width,
  142. int height);
  143. template <typename FinalBlock>
  144. [[nodiscard]] FinalBlock &unsafe() {
  145. return *reinterpret_cast<FinalBlock*>(&_data);
  146. }
  147. template <typename FinalBlock>
  148. [[nodiscard]] const FinalBlock &unsafe() const {
  149. return *reinterpret_cast<const FinalBlock*>(&_data);
  150. }
  151. [[nodiscard]] AbstractBlock *get();
  152. [[nodiscard]] const AbstractBlock *get() const;
  153. [[nodiscard]] AbstractBlock *operator->();
  154. [[nodiscard]] const AbstractBlock *operator->() const;
  155. [[nodiscard]] AbstractBlock &operator*();
  156. [[nodiscard]] const AbstractBlock &operator*() const;
  157. private:
  158. struct Tag {
  159. };
  160. explicit Block(const Tag &) {
  161. }
  162. template <typename FinalType, typename ...Args>
  163. [[nodiscard]] static Block New(Args &&...args) {
  164. auto result = Block(Tag{});
  165. result.emplace<FinalType>(std::forward<Args>(args)...);
  166. return result;
  167. }
  168. template <typename FinalType, typename ...Args>
  169. void emplace(Args &&...args) {
  170. new (&_data) FinalType(std::forward<Args>(args)...);
  171. }
  172. void destroy();
  173. static_assert(sizeof(NewlineBlock) <= sizeof(SkipBlock));
  174. static_assert(alignof(NewlineBlock) <= alignof(void*));
  175. static_assert(sizeof(EmojiBlock) <= sizeof(SkipBlock));
  176. static_assert(alignof(EmojiBlock) <= alignof(void*));
  177. static_assert(sizeof(TextBlock) <= sizeof(SkipBlock));
  178. static_assert(alignof(TextBlock) <= alignof(void*));
  179. static_assert(sizeof(CustomEmojiBlock) <= sizeof(SkipBlock));
  180. static_assert(alignof(CustomEmojiBlock) <= alignof(void*));
  181. std::aligned_storage_t<sizeof(SkipBlock), alignof(void*)> _data;
  182. };
  183. using Blocks = std::vector<Block>;
  184. [[nodiscard]] inline uint16 CountPosition(Blocks::const_iterator i) {
  185. return (*i)->position();
  186. }
  187. [[nodiscard]] int CountBlockHeight(
  188. const AbstractBlock *block,
  189. const style::TextStyle *st);
  190. [[nodiscard]] inline bool IsMono(TextBlockFlags flags) {
  191. return (flags & TextBlockFlag::Pre) || (flags & TextBlockFlag::Code);
  192. }
  193. } // namespace Ui::Text