summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRusty Wagner <rusty.wagner@gmail.com>2021-03-12 03:22:01 -0500
committerRusty Wagner <rusty.wagner@gmail.com>2021-03-16 20:40:13 -0400
commit2cb36d8f7ba30e1ba2b4e3566aede9016e15399f (patch)
tree5aadc214e3a2ec97ab2b38436c7b7ad8934baac9
parente43222c3e8da9f42d0d95207fa94335165a27d9d (diff)
Add a QTextBrowser capable of showing remote images
-rw-r--r--ui/textbrowser.h114
1 files changed, 114 insertions, 0 deletions
diff --git a/ui/textbrowser.h b/ui/textbrowser.h
new file mode 100644
index 00000000..9d4d33c3
--- /dev/null
+++ b/ui/textbrowser.h
@@ -0,0 +1,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);
+};