// 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 class QTextItemInt; struct QScriptAnalysis; struct QScriptLine; struct QScriptItem; namespace Ui::Text { inline constexpr auto kQuoteCollapsedLines = 3; 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( Blocks::const_iterator i, int16 paragraphIndex, Qt::LayoutDirection direction); void initNextLine(); void initParagraphBidi(); bool drawLine( uint16 lineEnd, Blocks::const_iterator blocksEnd); [[nodiscard]] FixedRange findSelectEmojiRange( const QScriptItem &si, std::vector::const_iterator blockIt, QFixed x, TextSelection selection) const; [[nodiscard]] FixedRange findSelectTextRange( const QScriptItem &si, int itemStart, int itemEnd, QFixed x, QFixed itemWidth, const QTextItemInt &gf, TextSelection selection) const; void fillSelectRange(FixedRange range); void pushHighlightRange(FixedRange range); void pushSpoilerRange( FixedRange range, FixedRange selected, bool isElidedItem, bool rtl); void fillRectsFromRanges(); void fillRectsFromRanges( QVarLengthArray &rects, QVarLengthArray &ranges); void paintSpoilerRects(); void paintSpoilerRects( const QVarLengthArray &rects, const style::color &color, int index); void composeHighlightPath(); [[nodiscard]] const AbstractBlock *markBlockForElisionGetEnd( int blockIndex); void setElideBidi(int elideStart); void prepareElidedLine( QString &lineText, int lineStart, int &lineLength, const AbstractBlock *&endBlock, int recursed = 0); void prepareElisionAt( QString &lineText, int &lineLength, uint16 position); void restoreAfterElided(); void fillParagraphBg(int paddingBottom); void applyBlockProperties( QTextEngine &e, not_null 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; QPen _quoteLinkPenOverride; 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; HighlightInfoRequest *_highlight = nullptr; const QChar *_str = nullptr; mutable crl::time _cachedNow = 0; float64 _spoilerOpacity = 0.; QVarLengthArray _spoilerRanges; QVarLengthArray _spoilerSelectedRanges; QVarLengthArray _highlightRanges; QVarLengthArray _spoilerRects; QVarLengthArray _spoilerSelectedRects; QVarLengthArray _highlightRects; std::optional _customEmojiContext; int _customEmojiSkip = 0; int _indexOfElidedBlock = -1; // For spoilers. // current paragraph data Blocks::const_iterator _paragraphStartBlock; Qt::LayoutDirection _paragraphDirection = Qt::LayoutDirectionAuto; int _paragraphStart = 0; int _paragraphLength = 0; QVarLengthArray _paragraphAnalysis; // current quote data QuoteDetails *_quote = nullptr; Qt::LayoutDirection _quoteDirection = Qt::LayoutDirectionAuto; int _quoteShift = 0; int _quoteIndex = 0; QMargins _quotePadding; int _quoteLinesLeft = -1; int _quoteTop = 0; int _quoteLineTop = 0; QuotePaintCache *_quotePreCache = nullptr; QuotePaintCache *_quoteBlockquoteCache = nullptr; bool _quotePreValid = false; bool _quoteBlockquoteValid = false; ClickHandlerPtr _quoteExpandLink; bool _quoteExpandLinkLookup = false; // current line data style::font _f; int _startLeft = 0; int _startTop = 0; int _startLineWidth = 0; QFixed _x, _wLeft, _last_rPadding; int _y = 0; int _yDelta = 0; int _lineIndex = 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 _lineStartPadding = 0; QFixed _lineWidth = 0; // link and symbol resolve QFixed _lookupX = 0; int _lookupY = 0; bool _lookupSymbol = false; bool _lookupLink = false; StateRequest _lookupRequest; StateResult _lookupResult; bool _elisionMiddle = false; }; } // namespace Ui::Text