// 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 // #pragma once #include "ui/text/text.h" #include "ui/text/text_block.h" #include "ui/text/text_custom_emoji.h" #include struct QScriptAnalysis; struct QScriptLine; namespace Ui::Text { class AbstractBlock; struct FixedRange { QFixed from; QFixed till; [[nodiscard]] bool empty() const { return (till <= from); } }; [[nodiscard]] FixedRange Intersected(FixedRange a, FixedRange b); [[nodiscard]] bool Intersects(FixedRange a, FixedRange b); [[nodiscard]] FixedRange United(FixedRange a, FixedRange b); [[nodiscard]] bool Distinct(FixedRange a, FixedRange b); class Renderer final { public: explicit Renderer(const Ui::Text::String &t); ~Renderer(); void draw(QPainter &p, const PaintContext &context); [[nodiscard]] StateResult getState( QPoint point, GeometryDescriptor geometry, StateRequest request); private: static constexpr int kSpoilersRectsSize = 512; struct BidiControl; void enumerate(); [[nodiscard]] crl::time now() const; void initNextParagraph( String::TextBlocks::const_iterator i, int16 paragraphIndex, Qt::LayoutDirection direction); void initNextLine(); void initParagraphBidi(); bool drawLine( uint16 _lineEnd, const String::TextBlocks::const_iterator &_endBlockIter, const String::TextBlocks::const_iterator &_end); void fillSelectRange(FixedRange range); void pushSpoilerRange( FixedRange range, FixedRange selected, bool isElidedItem); void fillSpoilerRects(); void fillSpoilerRects( QVarLengthArray &rects, QVarLengthArray &ranges); void paintSpoilerRects(); void paintSpoilerRects( const QVarLengthArray &rects, const style::color &color, int index); void elideSaveBlock( int32 blockIndex, const AbstractBlock *&_endBlock, int32 elideStart, int32 elideWidth); void setElideBidi(int32 elideStart, int32 elideLen); void prepareElidedLine( QString &lineText, int32 lineStart, int32 &lineLength, const AbstractBlock *&_endBlock, int repeat = 0); void restoreAfterElided(); void fillParagraphBg(int paddingBottom); // COPIED FROM qtextengine.cpp AND MODIFIED static void eAppendItems( QScriptAnalysis *analysis, int &start, int &stop, const BidiControl &control, QChar::Direction dir); void eShapeLine(const QScriptLine &line); void eSetFont(const AbstractBlock *block); void eItemize(); QChar::Direction eSkipBoundryNeutrals( QScriptAnalysis *analysis, const ushort *unicode, int &sor, int &eor, BidiControl &control, String::TextBlocks::const_iterator i); // creates the next QScript items. bool eBidiItemize(QScriptAnalysis *analysis, BidiControl &control); void applyBlockProperties(const AbstractBlock *block); [[nodiscard]] ClickHandlerPtr lookupLink( const AbstractBlock *block) const; const String *_t = nullptr; GeometryDescriptor _geometry; SpoilerData *_spoiler = nullptr; SpoilerMessCache *_spoilerCache = nullptr; QPainter *_p = nullptr; const style::TextPalette *_palette = nullptr; std::span _colors; bool _pausedEmoji = false; bool _pausedSpoiler = false; style::align _align = style::al_topleft; QPen _originalPen; QPen _originalPenSelected; const QPen *_currentPen = nullptr; const QPen *_currentPenSelected = nullptr; struct { bool spoiler = false; bool selectActiveBlock = false; // For monospace. } _background; int _yFrom = 0; int _yTo = 0; TextSelection _selection = { 0, 0 }; bool _fullWidthSelection = true; const QChar *_str = nullptr; mutable crl::time _cachedNow = 0; float64 _spoilerOpacity = 0.; QVarLengthArray _spoilerRanges; QVarLengthArray _spoilerSelectedRanges; QVarLengthArray _spoilerRects; QVarLengthArray _spoilerSelectedRects; std::optional _customEmojiContext; int _customEmojiSize = 0; int _customEmojiSkip = 0; int _indexOfElidedBlock = -1; // For spoilers. // current paragraph data String::TextBlocks::const_iterator _paragraphStartBlock; Qt::LayoutDirection _paragraphDirection = Qt::LayoutDirectionAuto; int _paragraphStart = 0; int _paragraphLength = 0; bool _paragraphHasBidi = false; QVarLengthArray _paragraphAnalysis; QFixed _paragraphWidthRemaining = 0; // current quote data QuoteDetails *_quote = nullptr; Qt::LayoutDirection _quoteDirection = Qt::LayoutDirectionAuto; int _quoteShift = 0; int _quoteIndex = 0; QMargins _quotePadding; int _quoteLineTop = 0; QuotePaintCache *_quotePreCache = nullptr; QuotePaintCache *_quoteBlockquoteCache = nullptr; bool _quotePreValid = false; bool _quoteBlockquoteValid = false; // current line data QTextEngine *_e = nullptr; style::font _f; int _startLeft = 0; int _startTop = 0; int _startLineWidth = 0; QFixed _x, _wLeft, _last_rPadding; int _y = 0; int _yDelta = 0; int _lineHeight = 0; int _fontHeight = 0; bool _breakEverywhere = false; bool _elidedLine = false; // elided hack support int _blocksSize = 0; int _elideSavedIndex = 0; std::optional _elideSavedBlock; int _lineStart = 0; int _localFrom = 0; int _lineStartBlock = 0; QFixed _lineWidth = 0; // link and symbol resolve QFixed _lookupX = 0; int _lookupY = 0; bool _lookupSymbol = false; bool _lookupLink = false; StateRequest _lookupRequest; StateResult _lookupResult; }; } // namespace Ui::Text