diff --git a/src/gui/Src/BasicView/AbstractTableView.cpp b/src/gui/Src/BasicView/AbstractTableView.cpp index 50fe75c3..7af24201 100644 --- a/src/gui/Src/BasicView/AbstractTableView.cpp +++ b/src/gui/Src/BasicView/AbstractTableView.cpp @@ -2,7 +2,9 @@ #include #include "Configuration.h" -AbstractTableView::AbstractTableView(QWidget* parent) : QAbstractScrollArea(parent) +AbstractTableView::AbstractTableView(QWidget* parent) + : QAbstractScrollArea(parent), + mFontMetrics(nullptr) { // Class variable initialization mTableOffset = 0; @@ -75,6 +77,8 @@ void AbstractTableView::updateColors() void AbstractTableView::updateFonts() { setFont(ConfigFont("AbstractTableView")); + puts("updateFonts()"); + mFontMetrics = new CachedFontMetrics(this, font()); } void AbstractTableView::updateShortcuts() diff --git a/src/gui/Src/BasicView/AbstractTableView.h b/src/gui/Src/BasicView/AbstractTableView.h index 74c027bd..d87c891c 100644 --- a/src/gui/Src/BasicView/AbstractTableView.h +++ b/src/gui/Src/BasicView/AbstractTableView.h @@ -12,6 +12,7 @@ #include "Configuration.h" #include "MenuBuilder.h" #include "QActionLambda.h" +#include "CachedFontMetrics.h" //Hacky class that fixes a really annoying cursor problem class AbstractTableScrollBar : public QScrollBar @@ -204,6 +205,9 @@ protected: QColor headerTextColor; QColor selectionColor; + // Font metrics + CachedFontMetrics* mFontMetrics; + //action helpers private: struct ActionShortcut diff --git a/src/gui/Src/BasicView/Disassembly.cpp b/src/gui/Src/BasicView/Disassembly.cpp index 047c1154..6a40f8ac 100644 --- a/src/gui/Src/BasicView/Disassembly.cpp +++ b/src/gui/Src/BasicView/Disassembly.cpp @@ -424,7 +424,7 @@ QString Disassembly::paintContent(QPainter* painter, dsint rowBase, int rowOffse curByte.textColor = mBytesColor; richBytes.push_back(curByte); } - RichTextPainter::paintRichText(painter, x, y, getColumnWidth(col), getRowHeight(), jumpsize + funcsize, richBytes, font()); + RichTextPainter::paintRichText(painter, x, y, getColumnWidth(col), getRowHeight(), jumpsize + funcsize, richBytes, mFontMetrics); } break; @@ -467,7 +467,7 @@ QString Disassembly::paintContent(QPainter* painter, dsint rowBase, int rowOffse else CapstoneTokenizer::TokenToRichText(token, richText, 0); int xinc = 4; - RichTextPainter::paintRichText(painter, x + loopsize, y, getColumnWidth(col) - loopsize, getRowHeight(), xinc, richText, font()); + RichTextPainter::paintRichText(painter, x + loopsize, y, getColumnWidth(col) - loopsize, getRowHeight(), xinc, richText, mFontMetrics); token.x = x + loopsize + xinc; } break; @@ -648,7 +648,7 @@ void Disassembly::mousePressEvent(QMouseEvent* event) if(rowOffset < mInstBuffer.size()) { CapstoneTokenizer::SingleToken token; - if(CapstoneTokenizer::TokenFromX(mInstBuffer.at(rowOffset).tokens, token, event->x(), font())) + if(CapstoneTokenizer::TokenFromX(mInstBuffer.at(rowOffset).tokens, token, event->x(), mFontMetrics)) { if(CapstoneTokenizer::IsHighlightableToken(token) && !CapstoneTokenizer::TokenEquals(&token, &mHighlightToken)) mHighlightToken = token; diff --git a/src/gui/Src/BasicView/HexDump.cpp b/src/gui/Src/BasicView/HexDump.cpp index 5266d955..3930c4e0 100644 --- a/src/gui/Src/BasicView/HexDump.cpp +++ b/src/gui/Src/BasicView/HexDump.cpp @@ -465,7 +465,7 @@ QString HexDump::paintContent(QPainter* painter, dsint rowBase, int rowOffset, i RichTextPainter::List richText; getColumnRichText(col, wRva, richText); - RichTextPainter::paintRichText(painter, x, y, w, h, 4, richText, font()); + RichTextPainter::paintRichText(painter, x, y, w, h, 4, richText, mFontMetrics); return ""; } diff --git a/src/gui/Src/BasicView/SearchListViewTable.cpp b/src/gui/Src/BasicView/SearchListViewTable.cpp index dd1a9420..b95d1293 100644 --- a/src/gui/Src/BasicView/SearchListViewTable.cpp +++ b/src/gui/Src/BasicView/SearchListViewTable.cpp @@ -100,7 +100,7 @@ QString SearchListViewTable::paintContent(QPainter* painter, dsint rowBase, int } //paint the rich text - RichTextPainter::paintRichText(painter, x + 1, y, w, h, 4, richText, font()); + RichTextPainter::paintRichText(painter, x + 1, y, w, h, 4, richText, mFontMetrics); text = ""; } return text; diff --git a/src/gui/Src/Disassembler/capstone_gui.cpp b/src/gui/Src/Disassembler/capstone_gui.cpp index 2fa826d2..fe376663 100644 --- a/src/gui/Src/Disassembler/capstone_gui.cpp +++ b/src/gui/Src/Disassembler/capstone_gui.cpp @@ -171,16 +171,15 @@ void CapstoneTokenizer::TokenToRichText(const InstructionToken & instr, RichText } } -bool CapstoneTokenizer::TokenFromX(const InstructionToken & instr, SingleToken & token, int x, const QFont & font) +bool CapstoneTokenizer::TokenFromX(const InstructionToken & instr, SingleToken & token, int x, CachedFontMetrics* fontMetrics) { if(x < instr.x) //before the first token return false; int len = int(instr.tokens.size()); - QFontMetrics metrics(font); for(int i = 0, xStart = instr.x; i < len; i++) { const auto & curToken = instr.tokens.at(i); - int curWidth = metrics.width(curToken.text); + int curWidth = fontMetrics->width(curToken.text); int xEnd = xStart + curWidth; if(x >= xStart && x < xEnd) { diff --git a/src/gui/Src/Disassembler/capstone_gui.h b/src/gui/Src/Disassembler/capstone_gui.h index 35a00fb2..49b5afbd 100644 --- a/src/gui/Src/Disassembler/capstone_gui.h +++ b/src/gui/Src/Disassembler/capstone_gui.h @@ -145,7 +145,7 @@ public: static void UpdateColors(); static void UpdateStringPool(); static void TokenToRichText(const InstructionToken & instr, RichTextPainter::List & richTextList, const SingleToken* highlightToken); - static bool TokenFromX(const InstructionToken & instr, SingleToken & token, int x, const QFont & font); + static bool TokenFromX(const InstructionToken & instr, SingleToken & token, int x, CachedFontMetrics* fontMetrics); static bool IsHighlightableToken(const SingleToken & token); static bool TokenEquals(const SingleToken* a, const SingleToken* b, bool ignoreSize = true); diff --git a/src/gui/Src/Gui/ScriptView.cpp b/src/gui/Src/Gui/ScriptView.cpp index f15363e0..22cfe4a5 100644 --- a/src/gui/Src/Gui/ScriptView.cpp +++ b/src/gui/Src/Gui/ScriptView.cpp @@ -260,7 +260,7 @@ QString ScriptView::paintContent(QPainter* painter, dsint rowBase, int rowOffset } //paint the rich text - RichTextPainter::paintRichText(painter, x + 1, y, w, h, xadd, richText, font()); + RichTextPainter::paintRichText(painter, x + 1, y, w, h, xadd, richText, mFontMetrics); returnString = ""; } else //no syntax highlighting diff --git a/src/gui/Src/Utils/CachedFontMetrics.h b/src/gui/Src/Utils/CachedFontMetrics.h new file mode 100644 index 00000000..9ef4c6fa --- /dev/null +++ b/src/gui/Src/Utils/CachedFontMetrics.h @@ -0,0 +1,39 @@ +#ifndef CACHEDFONTMETRICS_H +#define CACHEDFONTMETRICS_H + +#include +#include +#include + +class CachedFontMetrics : public QObject +{ + Q_OBJECT +public: + explicit CachedFontMetrics(QObject* parent, const QFont & font) + : QObject(parent), + mFontMetrics(font) + { + } + + int width(const QChar & ch) + { + auto unicode = ch.unicode(); + if(!mWidths[unicode]) + return mWidths[unicode] = mFontMetrics.width(ch); + return mWidths[unicode]; + } + + int width(const QString & text) + { + int result = 0; + for(const QChar & ch : text) + result += width(ch); + return result; + } + +private: + QFontMetrics mFontMetrics; + ushort mWidths[65536]; +}; + +#endif // CACHEDFONTMETRICS_H diff --git a/src/gui/Src/Utils/RichTextPainter.cpp b/src/gui/Src/Utils/RichTextPainter.cpp index 4a63ebb3..060481f7 100644 --- a/src/gui/Src/Utils/RichTextPainter.cpp +++ b/src/gui/Src/Utils/RichTextPainter.cpp @@ -1,16 +1,15 @@ #include "RichTextPainter.h" -//TODO: fix performance -void RichTextPainter::paintRichText(QPainter* painter, int x, int y, int w, int h, int xinc, const List & richText, const QFont & font) +//TODO: fix performance (possibly use QTextLayout?) +void RichTextPainter::paintRichText(QPainter* painter, int x, int y, int w, int h, int xinc, const List & richText, CachedFontMetrics* fontMetrics) { QPen pen; QPen highlightPen; highlightPen.setWidth(2); QBrush brush(Qt::cyan); - QFontMetrics metrics(font); for(const auto & curRichText : richText) { - int textWidth = metrics.width(curRichText.text); + int textWidth = fontMetrics->width(curRichText.text); int backgroundWidth = textWidth; if(backgroundWidth + xinc > w) backgroundWidth = w - xinc; diff --git a/src/gui/Src/Utils/RichTextPainter.h b/src/gui/Src/Utils/RichTextPainter.h index 3fdefda7..4f6bce96 100644 --- a/src/gui/Src/Utils/RichTextPainter.h +++ b/src/gui/Src/Utils/RichTextPainter.h @@ -4,6 +4,7 @@ #include #include #include +#include "CachedFontMetrics.h" class RichTextPainter { @@ -30,7 +31,7 @@ public: typedef std::vector List; //functions - static void paintRichText(QPainter* painter, int x, int y, int w, int h, int xinc, const List & richText, const QFont & font); + static void paintRichText(QPainter* painter, int x, int y, int w, int h, int xinc, const List & richText, CachedFontMetrics* fontMetrics); }; #endif // RICHTEXTPAINTER_H diff --git a/src/gui/x64dbg.pro b/src/gui/x64dbg.pro index 4ef8ab29..4abde197 100644 --- a/src/gui/x64dbg.pro +++ b/src/gui/x64dbg.pro @@ -247,7 +247,8 @@ HEADERS += \ Src/Utils/LongLongValidator.h \ Src/Utils/MiscUtil.h \ Src/Gui/XrefBrowseDialog.h \ - Src/Gui/CodepageSelectionDialog.h + Src/Gui/CodepageSelectionDialog.h \ + Src/Utils/CachedFontMetrics.h FORMS += \ Src/Gui/MainWindow.ui \