summaryrefslogtreecommitdiff
path: root/ui/textbrowser.h
blob: d58a0c2f7cb218b89655ab88c4811eb7c224ba08 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#pragma once

#include <QtWidgets/QTextBrowser>
#include <QtGui/QTextDocument>
#include <QtGui/QTextBlock>
#include <QtGui/QTextFragment>
#include <QtGui/QImage>
#include <QtCore/QThread>
#include <QtCore/QMutex>
#include <QtCore/QWaitCondition>
#include <QtCore/QSharedPointer>
#include <queue>
#include <optional>
#include "binaryninjaapi.h"
#include "uitypes.h"

class TextBrowser;
class TextBrowserDownloadThread;

class BINARYNINJAUIAPI TextBrowserDownloadCache
{
	QMutex m_mutex;
	std::map<QUrl, QByteArray> m_downloadCache;
	std::set<QUrl> m_inProgress;

  public:
	TextBrowserDownloadCache();

	bool lookup(const QUrl& url, QByteArray& result);
	void add(const QUrl& url, const QByteArray& data);

	void beginRequest(const QUrl& url);
	void endRequest(const QUrl& url);
	bool isInProgress(const QUrl& url);
};

class TextBrowserDownloadQueue : public QObject
{
	Q_OBJECT

	QMutex m_mutex;
	QWaitCondition m_cond;
	TextBrowser* m_owner;

	std::queue<QUrl> m_queue;

	size_t m_activeThreads = 0;

	static uint64_t AppendDataCallback(uint8_t* data, uint64_t len, void* ctxt);

  public:
	TextBrowserDownloadQueue(TextBrowser* owner);

	void stop();
	void threadFinished();
	bool processNextEvent(BinaryNinja::DownloadInstance* downloadInstance);
	void downloadData(const QUrl& name);

  Q_SIGNALS:
	void dataDownloaded(QUrl name, QByteArray contents);
};

class TextBrowserDownloadThread : public QThread
{
	Q_OBJECT

	QMutex m_mutex;
	TextBrowserDownloadQueue* m_queue;

	BinaryNinja::Ref<BinaryNinja::DownloadProvider> m_provider;
	BinaryNinja::Ref<BinaryNinja::DownloadInstance> m_downloadInstance;

  protected:
	virtual void run() override;

  public:
	TextBrowserDownloadThread(TextBrowserDownloadQueue* queue);
};

class BINARYNINJAUIAPI TextBrowser : public QTextBrowser
{
	Q_OBJECT

	QSharedPointer<TextBrowserDownloadCache> m_cache;
	bool m_ownedCache;

	TextBrowserDownloadQueue* m_queue;
	bool m_resizeImagesToWidth = false;

	std::set<QUrl> m_requested;
	std::optional<QUrl> m_markdownUrl;
	QString m_markdownPrefix;

	void resizeImageFragment(
	    QTextBlock& block, QTextFragment fragment, QTextImageFormat imgFormat, const QImage& contents);

  protected:
	virtual void resizeEvent(QResizeEvent* e) override;

  public:
	TextBrowser(QSharedPointer<TextBrowserDownloadCache> cache = QSharedPointer<TextBrowserDownloadCache>());
	virtual ~TextBrowser();

	void reset();
	virtual QVariant loadResource(int type, const QUrl& name) override;

	void resizeImagesToWidth();
	QSharedPointer<TextBrowserDownloadCache> cache() { return m_cache; }

	void downloadMarkdown(QUrl url, QString prefix = QString());

  private Q_SLOTS:
	void dataDownloaded(QUrl name, QByteArray contents);
};