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