231 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			231 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// 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 <private/qtextengine_p.h>
 | 
						|
 | 
						|
class QTextItemInt;
 | 
						|
struct QScriptAnalysis;
 | 
						|
struct QScriptLine;
 | 
						|
struct QScriptItem;
 | 
						|
 | 
						|
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);
 | 
						|
	[[nodiscard]] FixedRange findSelectEmojiRange(
 | 
						|
		const QScriptItem &si,
 | 
						|
		const Ui::Text::AbstractBlock *currentBlock,
 | 
						|
		const Ui::Text::AbstractBlock *nextBlock,
 | 
						|
		QFixed x,
 | 
						|
		QFixed glyphX,
 | 
						|
		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);
 | 
						|
	void fillRectsFromRanges();
 | 
						|
	void fillRectsFromRanges(
 | 
						|
		QVarLengthArray<QRect, kSpoilersRectsSize> &rects,
 | 
						|
		QVarLengthArray<FixedRange> &ranges);
 | 
						|
	void paintSpoilerRects();
 | 
						|
	void paintSpoilerRects(
 | 
						|
		const QVarLengthArray<QRect, kSpoilersRectsSize> &rects,
 | 
						|
		const style::color &color,
 | 
						|
		int index);
 | 
						|
	void composeHighlightPath();
 | 
						|
	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<SpecialColor> _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<FixedRange> _spoilerRanges;
 | 
						|
	QVarLengthArray<FixedRange> _spoilerSelectedRanges;
 | 
						|
	QVarLengthArray<FixedRange> _highlightRanges;
 | 
						|
	QVarLengthArray<QRect, kSpoilersRectsSize> _spoilerRects;
 | 
						|
	QVarLengthArray<QRect, kSpoilersRectsSize> _spoilerSelectedRects;
 | 
						|
	QVarLengthArray<QRect, kSpoilersRectsSize> _highlightRects;
 | 
						|
 | 
						|
	std::optional<CustomEmoji::Context> _customEmojiContext;
 | 
						|
	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<QScriptAnalysis, 4096> _paragraphAnalysis;
 | 
						|
	QFixed _paragraphWidthRemaining = 0;
 | 
						|
 | 
						|
	// current quote data
 | 
						|
	QuoteDetails *_quote = nullptr;
 | 
						|
	Qt::LayoutDirection _quoteDirection = Qt::LayoutDirectionAuto;
 | 
						|
	int _quoteShift = 0;
 | 
						|
	int _quoteIndex = 0;
 | 
						|
	QMargins _quotePadding;
 | 
						|
	int _quoteTop = 0;
 | 
						|
	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<Block> _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
 |