mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-19 03:16:10 +00:00
Fix non-integer Font Metrics in Graph (#1545)
This commit is contained in:
parent
61b0374a82
commit
ef22f20548
@ -1,60 +1,62 @@
|
||||
#ifndef CACHEDFONTMETRICS_H
|
||||
#define CACHEDFONTMETRICS_H
|
||||
|
||||
#include "common/Metrics.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QFont>
|
||||
#include <QFontMetrics>
|
||||
|
||||
class CachedFontMetrics : public QObject
|
||||
template<typename T>
|
||||
class CachedFontMetrics
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CachedFontMetrics(QObject *parent, const QFont &font)
|
||||
: QObject(parent),
|
||||
mFontMetrics(font)
|
||||
explicit CachedFontMetrics(const QFont &font)
|
||||
: mFontMetrics(font)
|
||||
{
|
||||
memset(mWidths, 0, sizeof(mWidths));
|
||||
mHeight = mFontMetrics.height();
|
||||
}
|
||||
|
||||
int width(const QChar &ch)
|
||||
T width(const QChar &ch)
|
||||
{
|
||||
//return mFontMetrics.width(ch);
|
||||
auto unicode = ch.unicode();
|
||||
if (unicode >= 0xD800) {
|
||||
if (unicode >= 0xE000)
|
||||
unicode -= 0xE000 - 0xD800;
|
||||
else
|
||||
// is lonely surrogate
|
||||
return mFontMetrics.width(ch);
|
||||
return fetchWidth(ch);
|
||||
}
|
||||
if (!mWidths[unicode])
|
||||
return mWidths[unicode] = mFontMetrics.width(ch);
|
||||
return mWidths[unicode] = fetchWidth(ch);
|
||||
return mWidths[unicode];
|
||||
}
|
||||
|
||||
int width(const QString &text)
|
||||
T width(const QString &text)
|
||||
{
|
||||
int result = 0;
|
||||
T result = 0;
|
||||
QChar temp;
|
||||
for (const QChar &ch : text) {
|
||||
if (ch.isHighSurrogate())
|
||||
temp = ch;
|
||||
else if (ch.isLowSurrogate())
|
||||
result += mFontMetrics.width(QString(temp) + ch);
|
||||
result += fetchWidth(QString(temp) + ch);
|
||||
else
|
||||
result += width(ch);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int height()
|
||||
T height()
|
||||
{
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
int position(const QString &text, int offset)
|
||||
T position(const QString &text, T offset)
|
||||
{
|
||||
int curWidth = 0;
|
||||
T curWidth = 0;
|
||||
QChar temp;
|
||||
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
@ -63,7 +65,7 @@ public:
|
||||
if (ch.isHighSurrogate())
|
||||
temp = ch;
|
||||
else if (ch.isLowSurrogate())
|
||||
curWidth += mFontMetrics.width(QString(temp) + ch);
|
||||
curWidth += fetchWidth(QString(temp) + ch);
|
||||
else
|
||||
curWidth += width(ch);
|
||||
|
||||
@ -76,9 +78,27 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
QFontMetrics mFontMetrics;
|
||||
uchar mWidths[0x10000 - 0xE000 + 0xD800];
|
||||
int mHeight;
|
||||
typename Metrics<T>::FontMetrics mFontMetrics;
|
||||
T mWidths[0x10000 - 0xE000 + 0xD800];
|
||||
T mHeight;
|
||||
|
||||
T fetchWidth(QChar c)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,11,0)
|
||||
return mFontMetrics.width(c);
|
||||
#else
|
||||
return mFontMetrics.horizontalAdvance(c);
|
||||
#endif
|
||||
}
|
||||
|
||||
T fetchWidth(const QString &s)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,11,0)
|
||||
return mFontMetrics.width(s);
|
||||
#else
|
||||
return mFontMetrics.horizontalAdvance(s);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CACHEDFONTMETRICS_H
|
||||
|
26
src/common/Metrics.h
Normal file
26
src/common/Metrics.h
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
#ifndef METRICS_H
|
||||
#define METRICS_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
class QRect;
|
||||
class QRectF;
|
||||
class QFontMetrics;
|
||||
class QFontMetricsF;
|
||||
|
||||
template<typename T> struct Metrics {};
|
||||
|
||||
template<> struct Metrics<int>
|
||||
{
|
||||
using Rect = QRect;
|
||||
using FontMetrics = QFontMetrics;
|
||||
};
|
||||
|
||||
template<> struct Metrics<qreal>
|
||||
{
|
||||
using Rect = QRectF;
|
||||
using FontMetrics = QFontMetricsF;
|
||||
};
|
||||
|
||||
#endif //METRICS_H
|
@ -7,15 +7,18 @@
|
||||
#include <QTextFragment>
|
||||
|
||||
//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)
|
||||
|
||||
|
||||
template<typename T>
|
||||
void RichTextPainter::paintRichText(QPainter *painter, T x, T y, T w, T h, T xinc,
|
||||
const List &richText, CachedFontMetrics<T> *fontMetrics)
|
||||
{
|
||||
QPen pen;
|
||||
QPen highlightPen;
|
||||
QBrush brush(Qt::cyan);
|
||||
for (const CustomRichText_t &curRichText : richText) {
|
||||
int textWidth = fontMetrics->width(curRichText.text);
|
||||
int backgroundWidth = textWidth;
|
||||
T textWidth = fontMetrics->width(curRichText.text);
|
||||
T backgroundWidth = textWidth;
|
||||
if (backgroundWidth + xinc > w)
|
||||
backgroundWidth = w - xinc;
|
||||
if (backgroundWidth <= 0) //stop drawing when going outside the specified width
|
||||
@ -32,24 +35,24 @@ void RichTextPainter::paintRichText(QPainter *painter, int x, int y, int w, int
|
||||
case FlagBackground: //background only
|
||||
if (backgroundWidth > 0 && curRichText.textBackground.alpha()) {
|
||||
brush.setColor(curRichText.textBackground);
|
||||
painter->fillRect(QRect(x + xinc, y, backgroundWidth, h), brush);
|
||||
painter->fillRect(QRectF(x + xinc, y, backgroundWidth, h), brush);
|
||||
}
|
||||
break;
|
||||
case FlagAll: //color+background
|
||||
if (backgroundWidth > 0 && curRichText.textBackground.alpha()) {
|
||||
brush.setColor(curRichText.textBackground);
|
||||
painter->fillRect(QRect(x + xinc, y, backgroundWidth, h), brush);
|
||||
painter->fillRect(QRectF(x + xinc, y, backgroundWidth, h), brush);
|
||||
}
|
||||
pen.setColor(curRichText.textColor);
|
||||
painter->setPen(pen);
|
||||
break;
|
||||
}
|
||||
painter->drawText(QRect(x + xinc, y, w - xinc, h), Qt::TextBypassShaping, curRichText.text);
|
||||
painter->drawText(typename Metrics<T>::Rect(x + xinc, y, w - xinc, h), Qt::TextBypassShaping, curRichText.text);
|
||||
if (curRichText.highlight && curRichText.highlightColor.alpha()) {
|
||||
highlightPen.setColor(curRichText.highlightColor);
|
||||
highlightPen.setWidth(curRichText.highlightWidth);
|
||||
painter->setPen(highlightPen);
|
||||
int highlightOffsetX = curRichText.highlightConnectPrev ? -1 : 1;
|
||||
T highlightOffsetX = curRichText.highlightConnectPrev ? -1 : 1;
|
||||
painter->drawLine(x + xinc + highlightOffsetX, y + h - 1, x + xinc + backgroundWidth - 1,
|
||||
y + h - 1);
|
||||
}
|
||||
@ -57,6 +60,11 @@ void RichTextPainter::paintRichText(QPainter *painter, int x, int y, int w, int
|
||||
}
|
||||
}
|
||||
|
||||
template
|
||||
void RichTextPainter::paintRichText<qreal>(QPainter *painter, qreal x, qreal y, qreal w, qreal h, qreal xinc,
|
||||
const List &richText, CachedFontMetrics<qreal> *fontMetrics);
|
||||
|
||||
|
||||
/**
|
||||
* @brief RichTextPainter::htmlRichText Convert rich text in x64dbg to HTML, for use by other applications
|
||||
* @param richText The rich text to be converted to HTML format
|
||||
|
@ -2,12 +2,15 @@
|
||||
#ifndef RICHTEXTPAINTER_H
|
||||
#define RICHTEXTPAINTER_H
|
||||
|
||||
#include "common/Metrics.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QTextDocument>
|
||||
#include <QColor>
|
||||
#include <vector>
|
||||
|
||||
class CachedFontMetrics;
|
||||
class QFontMetricsF;
|
||||
template<typename T> class CachedFontMetrics;
|
||||
class QPainter;
|
||||
|
||||
class RichTextPainter
|
||||
@ -35,8 +38,9 @@ public:
|
||||
typedef std::vector<CustomRichText_t> List;
|
||||
|
||||
//functions
|
||||
static void paintRichText(QPainter *painter, int x, int y, int w, int h, int xinc,
|
||||
const List &richText, CachedFontMetrics *fontMetrics);
|
||||
template<typename T = qreal>
|
||||
static void paintRichText(QPainter *painter, T x, T y, T w, T h, T xinc,
|
||||
const List &richText, CachedFontMetrics<T> *fontMetrics);
|
||||
static void htmlRichText(const List &richText, QString &textHtml, QString &textPlain);
|
||||
|
||||
static List fromTextDocument(const QTextDocument &doc);
|
||||
|
@ -377,8 +377,7 @@ void DisassemblerGraphView::initFont()
|
||||
charWidth = metrics.width('X');
|
||||
charHeight = static_cast<int>(metrics.height());
|
||||
charOffset = 0;
|
||||
delete mFontMetrics;
|
||||
mFontMetrics = new CachedFontMetrics(this, font());
|
||||
mFontMetrics.reset(new CachedFontMetrics<qreal>(font()));
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
|
||||
@ -464,7 +463,7 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
|
||||
// Highlight selected tokens
|
||||
if (highlight_token != nullptr) {
|
||||
int y = static_cast<int>(blockY + (2 * charWidth) + (db.header_text.lines.size() * charHeight));
|
||||
int tokenWidth = mFontMetrics->width(highlight_token->content);
|
||||
qreal tokenWidth = mFontMetrics->width(highlight_token->content);
|
||||
|
||||
for (const Instr &instr : db.instrs) {
|
||||
int pos = -1;
|
||||
@ -477,19 +476,19 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
|
||||
continue;
|
||||
}
|
||||
|
||||
int widthBefore = mFontMetrics->width(instr.plainText.left(pos));
|
||||
qreal widthBefore = mFontMetrics->width(instr.plainText.left(pos));
|
||||
if (charWidth * 3 + widthBefore > block.width - (10 + 2 * charWidth)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int highlightWidth = tokenWidth;
|
||||
qreal highlightWidth = tokenWidth;
|
||||
if (charWidth * 3 + widthBefore + tokenWidth >= block.width - (10 + 2 * charWidth)) {
|
||||
highlightWidth = static_cast<int>(block.width - widthBefore - (10 + 4 * charWidth));
|
||||
highlightWidth = block.width - widthBefore - (10 + 4 * charWidth);
|
||||
}
|
||||
|
||||
QColor selectionColor = ConfigColor("wordhl");
|
||||
|
||||
p.fillRect(QRect(static_cast<int>(blockX + charWidth * 3 + widthBefore), y, highlightWidth,
|
||||
p.fillRect(QRectF(blockX + charWidth * 3 + widthBefore, y, highlightWidth,
|
||||
charHeight), selectionColor);
|
||||
}
|
||||
|
||||
@ -535,8 +534,8 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
|
||||
continue;
|
||||
}
|
||||
|
||||
RichTextPainter::paintRichText(&p, static_cast<int>(x), y, block.width, charHeight, 0, line,
|
||||
mFontMetrics);
|
||||
RichTextPainter::paintRichText<qreal>(&p, x, y, block.width, charHeight, 0, line,
|
||||
mFontMetrics.get());
|
||||
y += charHeight;
|
||||
}
|
||||
|
||||
@ -569,9 +568,9 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
|
||||
QRectF bpRect(x - rectSize / 3.0, y + (charHeight - rectSize) / 2.0, rectSize, rectSize);
|
||||
Q_UNUSED(bpRect);
|
||||
|
||||
RichTextPainter::paintRichText(&p, static_cast<int>(x + charWidth), y,
|
||||
static_cast<int>(block.width - charWidth), charHeight, 0, line,
|
||||
mFontMetrics);
|
||||
RichTextPainter::paintRichText<qreal>(&p, x + charWidth, y,
|
||||
block.width - charWidth, charHeight, 0, line,
|
||||
mFontMetrics.get());
|
||||
y += charHeight;
|
||||
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ private:
|
||||
|
||||
Token *highlight_token;
|
||||
// Font data
|
||||
CachedFontMetrics *mFontMetrics;
|
||||
std::unique_ptr<CachedFontMetrics<qreal>> mFontMetrics;
|
||||
qreal charWidth;
|
||||
int charHeight;
|
||||
int charOffset;
|
||||
|
Loading…
Reference in New Issue
Block a user