init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
This commit is contained in:
276
Telegram/lib_ui/ui/text/text_block.cpp
Normal file
276
Telegram/lib_ui/ui/text/text_block.cpp
Normal file
@@ -0,0 +1,276 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "ui/text/text_block.h"
|
||||
|
||||
#include "styles/style_basic.h"
|
||||
|
||||
#include <private/qfontengine_p.h>
|
||||
|
||||
namespace Ui {
|
||||
namespace Text {
|
||||
|
||||
style::font WithFlags(
|
||||
const style::font &font,
|
||||
TextBlockFlags flags,
|
||||
style::FontFlags fontFlags) {
|
||||
using namespace style::internal;
|
||||
|
||||
using Flag = style::FontFlag;
|
||||
if (!flags && !fontFlags) {
|
||||
return font;
|
||||
} else if (IsMono(flags) || (fontFlags & Flag::Monospace)) {
|
||||
return font->monospace();
|
||||
}
|
||||
auto result = font;
|
||||
if ((flags & TextBlockFlag::Bold) || (fontFlags & Flag::Bold)) {
|
||||
result = result->bold();
|
||||
} else if ((flags & TextBlockFlag::Semibold)
|
||||
|| (fontFlags & Flag::Semibold)) {
|
||||
result = result->semibold();
|
||||
}
|
||||
if ((flags & TextBlockFlag::Italic) || (fontFlags & Flag::Italic)) {
|
||||
result = result->italic();
|
||||
}
|
||||
if ((flags & TextBlockFlag::Underline)
|
||||
|| (fontFlags & Flag::Underline)) {
|
||||
result = result->underline();
|
||||
}
|
||||
if ((flags & TextBlockFlag::StrikeOut)
|
||||
|| (fontFlags & Flag::StrikeOut)) {
|
||||
result = result->strikeout();
|
||||
}
|
||||
if (flags & TextBlockFlag::Tilde) { // Tilde fix in OpenSans.
|
||||
result = result->semibold();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Qt::LayoutDirection UnpackParagraphDirection(bool ltr, bool rtl) {
|
||||
return ltr
|
||||
? Qt::LeftToRight
|
||||
: rtl
|
||||
? Qt::RightToLeft
|
||||
: Qt::LayoutDirectionAuto;
|
||||
}
|
||||
|
||||
AbstractBlock::AbstractBlock(TextBlockType type, BlockDescriptor descriptor)
|
||||
: _position(descriptor.position)
|
||||
, _type(static_cast<uint16>(type))
|
||||
, _flags(descriptor.flags)
|
||||
, _linkIndex(descriptor.linkIndex)
|
||||
, _colorIndex(descriptor.colorIndex) {
|
||||
}
|
||||
|
||||
uint16 AbstractBlock::position() const {
|
||||
return _position;
|
||||
}
|
||||
|
||||
TextBlockType AbstractBlock::type() const {
|
||||
return static_cast<TextBlockType>(_type);
|
||||
}
|
||||
|
||||
TextBlockFlags AbstractBlock::flags() const {
|
||||
return TextBlockFlags::from_raw(_flags);
|
||||
}
|
||||
|
||||
int AbstractBlock::objectWidth() const {
|
||||
switch (type()) {
|
||||
case TextBlockType::Emoji: return st::emojiSize + 2 * st::emojiPadding;
|
||||
case TextBlockType::CustomEmoji:
|
||||
return static_cast<const CustomEmojiBlock*>(this)->custom()->width();
|
||||
case TextBlockType::Skip:
|
||||
return static_cast<const SkipBlock*>(this)->width();
|
||||
}
|
||||
Unexpected("Type in AbstractBlock::objectWidth.");
|
||||
}
|
||||
|
||||
uint16 AbstractBlock::linkIndex() const {
|
||||
return _linkIndex;
|
||||
}
|
||||
|
||||
uint16 AbstractBlock::colorIndex() const {
|
||||
return _colorIndex;
|
||||
}
|
||||
|
||||
void AbstractBlock::setLinkIndex(uint16 index) {
|
||||
_linkIndex = index;
|
||||
}
|
||||
|
||||
TextBlock::TextBlock(BlockDescriptor descriptor)
|
||||
: AbstractBlock(TextBlockType::Text, descriptor) {
|
||||
}
|
||||
|
||||
EmojiBlock::EmojiBlock(BlockDescriptor descriptor, EmojiPtr emoji)
|
||||
: AbstractBlock(TextBlockType::Emoji, descriptor)
|
||||
, _emoji(emoji) {
|
||||
}
|
||||
|
||||
CustomEmojiBlock::CustomEmojiBlock(
|
||||
BlockDescriptor descriptor,
|
||||
std::unique_ptr<CustomEmoji> custom)
|
||||
: AbstractBlock(TextBlockType::CustomEmoji, descriptor)
|
||||
, _custom(std::move(custom)) {
|
||||
}
|
||||
|
||||
NewlineBlock::NewlineBlock(BlockDescriptor descriptor, uint16 quoteIndex)
|
||||
: AbstractBlock(TextBlockType::Newline, descriptor)
|
||||
, _quoteIndex(quoteIndex) {
|
||||
}
|
||||
|
||||
SkipBlock::SkipBlock(BlockDescriptor descriptor, int width, int height)
|
||||
: AbstractBlock(TextBlockType::Skip, descriptor)
|
||||
, _width(width)
|
||||
, _height(height) {
|
||||
}
|
||||
|
||||
int SkipBlock::width() const {
|
||||
return _width;
|
||||
}
|
||||
|
||||
int SkipBlock::height() const {
|
||||
return _height;
|
||||
}
|
||||
|
||||
Block::Block() {
|
||||
Unexpected("Should not be called.");
|
||||
}
|
||||
|
||||
Block::Block(Block &&other) {
|
||||
switch (other->type()) {
|
||||
case TextBlockType::Newline:
|
||||
emplace<NewlineBlock>(std::move(other.unsafe<NewlineBlock>()));
|
||||
break;
|
||||
case TextBlockType::Text:
|
||||
emplace<TextBlock>(std::move(other.unsafe<TextBlock>()));
|
||||
break;
|
||||
case TextBlockType::Emoji:
|
||||
emplace<EmojiBlock>(std::move(other.unsafe<EmojiBlock>()));
|
||||
break;
|
||||
case TextBlockType::CustomEmoji:
|
||||
emplace<CustomEmojiBlock>(
|
||||
std::move(other.unsafe<CustomEmojiBlock>()));
|
||||
break;
|
||||
case TextBlockType::Skip:
|
||||
emplace<SkipBlock>(std::move(other.unsafe<SkipBlock>()));
|
||||
break;
|
||||
default:
|
||||
Unexpected("Bad text block type in Block(Block&&).");
|
||||
}
|
||||
}
|
||||
|
||||
Block &Block::operator=(Block &&other) {
|
||||
if (&other == this) {
|
||||
return *this;
|
||||
}
|
||||
destroy();
|
||||
switch (other->type()) {
|
||||
case TextBlockType::Newline:
|
||||
emplace<NewlineBlock>(std::move(other.unsafe<NewlineBlock>()));
|
||||
break;
|
||||
case TextBlockType::Text:
|
||||
emplace<TextBlock>(std::move(other.unsafe<TextBlock>()));
|
||||
break;
|
||||
case TextBlockType::Emoji:
|
||||
emplace<EmojiBlock>(std::move(other.unsafe<EmojiBlock>()));
|
||||
break;
|
||||
case TextBlockType::CustomEmoji:
|
||||
emplace<CustomEmojiBlock>(
|
||||
std::move(other.unsafe<CustomEmojiBlock>()));
|
||||
break;
|
||||
case TextBlockType::Skip:
|
||||
emplace<SkipBlock>(std::move(other.unsafe<SkipBlock>()));
|
||||
break;
|
||||
default:
|
||||
Unexpected("Bad text block type in operator=(Block&&).");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Block::~Block() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
Block Block::Newline(BlockDescriptor descriptor, uint16 quoteIndex) {
|
||||
return New<NewlineBlock>(descriptor, quoteIndex);
|
||||
}
|
||||
|
||||
Block Block::Text(BlockDescriptor descriptor) {
|
||||
return New<TextBlock>(descriptor);
|
||||
}
|
||||
|
||||
Block Block::Emoji(BlockDescriptor descriptor, EmojiPtr emoji) {
|
||||
return New<EmojiBlock>(descriptor, emoji);
|
||||
}
|
||||
|
||||
Block Block::CustomEmoji(
|
||||
BlockDescriptor descriptor,
|
||||
std::unique_ptr<Text::CustomEmoji> custom) {
|
||||
return New<CustomEmojiBlock>(descriptor, std::move(custom));
|
||||
}
|
||||
|
||||
Block Block::Skip(BlockDescriptor descriptor, int width, int height) {
|
||||
return New<SkipBlock>(descriptor, width, height);
|
||||
}
|
||||
|
||||
AbstractBlock *Block::get() {
|
||||
return &unsafe<AbstractBlock>();
|
||||
}
|
||||
|
||||
const AbstractBlock *Block::get() const {
|
||||
return &unsafe<AbstractBlock>();
|
||||
}
|
||||
|
||||
AbstractBlock *Block::operator->() {
|
||||
return get();
|
||||
}
|
||||
|
||||
const AbstractBlock *Block::operator->() const {
|
||||
return get();
|
||||
}
|
||||
|
||||
AbstractBlock &Block::operator*() {
|
||||
return *get();
|
||||
}
|
||||
|
||||
const AbstractBlock &Block::operator*() const {
|
||||
return *get();
|
||||
}
|
||||
|
||||
void Block::destroy() {
|
||||
switch (get()->type()) {
|
||||
case TextBlockType::Newline:
|
||||
unsafe<NewlineBlock>().~NewlineBlock();
|
||||
break;
|
||||
case TextBlockType::Text:
|
||||
unsafe<TextBlock>().~TextBlock();
|
||||
break;
|
||||
case TextBlockType::Emoji:
|
||||
unsafe<EmojiBlock>().~EmojiBlock();
|
||||
break;
|
||||
case TextBlockType::CustomEmoji:
|
||||
unsafe<CustomEmojiBlock>().~CustomEmojiBlock();
|
||||
break;
|
||||
case TextBlockType::Skip:
|
||||
unsafe<SkipBlock>().~SkipBlock();
|
||||
break;
|
||||
default:
|
||||
Unexpected("Bad text block type in Block(Block&&).");
|
||||
}
|
||||
}
|
||||
|
||||
int CountBlockHeight(
|
||||
const AbstractBlock *block,
|
||||
const style::TextStyle *st) {
|
||||
return (block->type() == TextBlockType::Skip)
|
||||
? static_cast<const SkipBlock*>(block)->height()
|
||||
: st->lineHeight
|
||||
? st->lineHeight
|
||||
: st->font->height;
|
||||
}
|
||||
|
||||
} // namespace Text
|
||||
} // namespace Ui
|
||||
Reference in New Issue
Block a user