mirror of
https://github.com/rizinorg/cutter.git
synced 2025-02-20 13:46:06 +00:00
Overview optimization (#1262)
* Overview optimization * Better cache algorithm * Fix a bug of the multiple graphs
This commit is contained in:
parent
31a832c34d
commit
0be50ac36f
@ -200,7 +200,10 @@ void MainWindow::initUI()
|
||||
connect(ui->actionOverview, &QAction::toggled, [this](bool checked) {
|
||||
if (checked) {
|
||||
overviewDock->userClosed = false;
|
||||
adjustOverview();
|
||||
forceUpdateOverview();
|
||||
if (targetGraphDock) {
|
||||
toggleOverview(true, targetGraphDock);
|
||||
}
|
||||
}
|
||||
});
|
||||
sectionsDock = new SectionsWidget(this, ui->actionSections);
|
||||
@ -298,34 +301,35 @@ void MainWindow::toggleOverview(bool visibility, GraphWidget *targetGraph)
|
||||
return;
|
||||
}
|
||||
targetGraphDock = targetGraph;
|
||||
connect(targetGraphDock->graphView, SIGNAL(refreshBlock()), this, SLOT(adjustOverview()));
|
||||
connect(targetGraphDock->graphView, SIGNAL(viewRefreshed()), this, SLOT(adjustOverview()));
|
||||
connect(targetGraphDock->graphView, SIGNAL(viewZoomed()), this, SLOT(adjustOverview()));
|
||||
connect(targetGraphDock->graphView, SIGNAL(refreshBlock()), this, SLOT(updateOverview()));
|
||||
connect(targetGraphDock->graphView, SIGNAL(viewRefreshed()), this, SLOT(updateOverview()));
|
||||
connect(targetGraphDock->graphView, SIGNAL(viewZoomed()), this, SLOT(updateOverview()));
|
||||
connect(targetGraphDock, &GraphWidget::graphClose, [this]() {
|
||||
disconnectOverview();
|
||||
enableOverviewMenu(false);
|
||||
overviewDock->hide();
|
||||
});
|
||||
connect(overviewDock->graphView, SIGNAL(mouseMoved()), this, SLOT(adjustGraph()));
|
||||
connect(overviewDock, &QDockWidget::dockLocationChanged, this, &MainWindow::adjustOverview);
|
||||
connect(overviewDock->graphView, SIGNAL(refreshBlock()), this, SLOT(updateOverviewAddr()));
|
||||
connect(overviewDock, &QDockWidget::dockLocationChanged, this, &MainWindow::forceUpdateOverview);
|
||||
connect(overviewDock, &OverviewWidget::graphClose, [this]() {
|
||||
ui->actionOverview->setChecked(false);
|
||||
if (!core->isGraphEmpty()) {
|
||||
overviewDock->userClosed = true;
|
||||
}
|
||||
});
|
||||
connect(overviewDock, SIGNAL(resized()), this, SLOT(adjustOverview()));
|
||||
connect(overviewDock, SIGNAL(resized()), this, SLOT(forceUpdateOverview()));
|
||||
}
|
||||
|
||||
void MainWindow::disconnectOverview()
|
||||
{
|
||||
disconnect(targetGraphDock->graphView, SIGNAL(refreshBlock()), this, SLOT(adjustOverview()));
|
||||
disconnect(targetGraphDock->graphView, SIGNAL(viewRefreshed()), this, SLOT(adjustOverview()));
|
||||
disconnect(targetGraphDock->graphView, SIGNAL(viewZoomed()), this, SLOT(adjustOverview()));
|
||||
disconnect(targetGraphDock->graphView, SIGNAL(refreshBlock()), this, SLOT(updateOverview()));
|
||||
disconnect(targetGraphDock->graphView, SIGNAL(viewRefreshed()), this, SLOT(updateOverview()));
|
||||
disconnect(targetGraphDock->graphView, SIGNAL(viewZoomed()), this, SLOT(updateOverview()));
|
||||
disconnect(overviewDock->graphView, SIGNAL(mouseMoved()), this, SLOT(adjustGraph()));
|
||||
disconnect(overviewDock, &QDockWidget::dockLocationChanged, this, &MainWindow::adjustOverview);
|
||||
disconnect(overviewDock, SIGNAL(resized()), this, SLOT(adjustOverview()));
|
||||
disconnect(overviewDock, &QDockWidget::visibilityChanged, this, nullptr);
|
||||
disconnect(overviewDock->graphView, SIGNAL(refreshBlock()), this, SLOT(updateOverviewAddr()));
|
||||
disconnect(overviewDock, &QDockWidget::dockLocationChanged, this, &MainWindow::forceUpdateOverview);
|
||||
disconnect(overviewDock, SIGNAL(resized()), this, SLOT(forceUpdateOverview()));
|
||||
}
|
||||
|
||||
void MainWindow::setOverviewData()
|
||||
@ -334,17 +338,50 @@ void MainWindow::setOverviewData()
|
||||
targetGraphDock->graphView->getHeight(), targetGraphDock->graphView->getBlocks());
|
||||
}
|
||||
|
||||
void MainWindow::adjustOverview()
|
||||
bool MainWindow::isOverviewActive()
|
||||
{
|
||||
if (!overviewDock || overviewDock->userClosed) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (core->isGraphEmpty()) {
|
||||
enableOverviewMenu(false);
|
||||
overviewDock->hide();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::updateOverviewAddr()
|
||||
{
|
||||
overviewDock->graphView->currentFcnAddr = targetGraphDock->graphView->currentFcnAddr;
|
||||
}
|
||||
|
||||
void MainWindow::forceUpdateOverview()
|
||||
{
|
||||
if (!isOverviewActive()) {
|
||||
return;
|
||||
}
|
||||
overviewDock->graphView->useCache = false;
|
||||
setOverviewData();
|
||||
drawOverview();
|
||||
}
|
||||
|
||||
void MainWindow::updateOverview()
|
||||
{
|
||||
if (!isOverviewActive()) {
|
||||
return;
|
||||
}
|
||||
if (overviewDock->graphView->currentFcnAddr != targetGraphDock->graphView->currentFcnAddr) {
|
||||
overviewDock->graphView->useCache = false;
|
||||
setOverviewData();
|
||||
} else {
|
||||
overviewDock->graphView->useCache = true;
|
||||
}
|
||||
drawOverview();
|
||||
}
|
||||
|
||||
void MainWindow::drawOverview()
|
||||
{
|
||||
qreal curScale = overviewDock->graphView->current_scale;
|
||||
qreal baseScale = targetGraphDock->graphView->current_scale;
|
||||
qreal w = targetGraphDock->graphView->viewport()->width() * curScale / baseScale;
|
||||
|
@ -137,10 +137,6 @@ public slots:
|
||||
void openNewFileFailed();
|
||||
|
||||
void toggleOverview(bool visibility, GraphWidget *targetGraph);
|
||||
void disconnectOverview();
|
||||
void adjustOverview();
|
||||
void adjustGraph();
|
||||
|
||||
private slots:
|
||||
void on_actionAbout_triggered();
|
||||
void on_actionIssue_triggered();
|
||||
@ -193,6 +189,13 @@ private slots:
|
||||
void changeDebugView();
|
||||
void changeDefinedView();
|
||||
|
||||
void disconnectOverview();
|
||||
void updateOverview();
|
||||
void forceUpdateOverview();
|
||||
void updateOverviewAddr();
|
||||
void drawOverview();
|
||||
void adjustGraph();
|
||||
|
||||
private:
|
||||
CutterCore *core;
|
||||
|
||||
@ -271,6 +274,7 @@ private:
|
||||
|
||||
void updateDockActionsChecked();
|
||||
void setOverviewData();
|
||||
bool isOverviewActive();
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
@ -182,6 +182,7 @@ void DisassemblerGraphView::loadCurrentGraph()
|
||||
QJsonArray functions;
|
||||
RAnalFunction *fcn = Core()->functionAt(seekable->getOffset());
|
||||
if (fcn) {
|
||||
currentFcnAddr = fcn->addr;
|
||||
QJsonDocument functionsDoc = Core()->cmdj("agJ " + RAddressString(fcn->addr));
|
||||
functions = functionsDoc.array();
|
||||
}
|
||||
@ -211,14 +212,8 @@ void DisassemblerGraphView::loadCurrentGraph()
|
||||
// Refresh global "empty graph" variable so other widget know there is nothing to show here
|
||||
Core()->setGraphEmpty(emptyGraph);
|
||||
|
||||
Analysis anal;
|
||||
anal.ready = true;
|
||||
|
||||
QJsonValue funcRef = functions.first();
|
||||
QJsonObject func = funcRef.toObject();
|
||||
Function f;
|
||||
f.ready = true;
|
||||
f.entry = func["offset"].toVariant().toULongLong();
|
||||
|
||||
windowTitle = tr("Graph");
|
||||
QString funcName = func["name"].toString().trimmed();
|
||||
@ -312,15 +307,10 @@ void DisassemblerGraphView::loadCurrentGraph()
|
||||
}
|
||||
disassembly_blocks[db.entry] = db;
|
||||
prepareGraphNode(gb);
|
||||
f.blocks.push_back(db);
|
||||
|
||||
addBlock(gb);
|
||||
}
|
||||
|
||||
anal.functions[f.entry] = f;
|
||||
anal.status = "Ready.";
|
||||
anal.entry = f.entry;
|
||||
|
||||
if (!func["blocks"].toArray().isEmpty()) {
|
||||
computeGraph(entry);
|
||||
}
|
||||
|
@ -83,32 +83,6 @@ class DisassemblerGraphView : public GraphView
|
||||
bool indirectcall = false;
|
||||
};
|
||||
|
||||
struct Function {
|
||||
bool ready;
|
||||
ut64 entry;
|
||||
ut64 update_id;
|
||||
std::vector<DisassemblyBlock> blocks;
|
||||
};
|
||||
|
||||
struct Analysis {
|
||||
ut64 entry = 0;
|
||||
std::unordered_map<ut64, Function> functions;
|
||||
bool ready = false;
|
||||
ut64 update_id = 0;
|
||||
QString status = "Analyzing...";
|
||||
|
||||
bool find_instr(ut64 addr, ut64 &func, ut64 &instr)
|
||||
{
|
||||
//TODO implement
|
||||
Q_UNUSED(addr);
|
||||
Q_UNUSED(func);
|
||||
Q_UNUSED(instr);
|
||||
return false;
|
||||
}
|
||||
|
||||
//dummy class
|
||||
};
|
||||
|
||||
public:
|
||||
DisassemblerGraphView(QWidget *parent);
|
||||
~DisassemblerGraphView() override;
|
||||
@ -129,7 +103,6 @@ public:
|
||||
|
||||
int getWidth() { return width; }
|
||||
int getHeight() { return height; }
|
||||
|
||||
std::unordered_map<ut64, GraphBlock> getBlocks() { return blocks; }
|
||||
public slots:
|
||||
void refreshView();
|
||||
|
@ -381,7 +381,12 @@ QPolygonF GraphView::recalculatePolygon(QPolygonF polygon)
|
||||
void GraphView::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
QPainter p(viewport());
|
||||
if (useCache) {
|
||||
drawGraph();
|
||||
return;
|
||||
}
|
||||
pixmap = QPixmap(viewport()->width(), viewport()->height());
|
||||
QPainter p(&pixmap);
|
||||
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
@ -436,10 +441,18 @@ void GraphView::paintEvent(QPaintEvent *event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawGraph();
|
||||
emit refreshBlock();
|
||||
}
|
||||
|
||||
void GraphView::drawGraph()
|
||||
{
|
||||
QRectF target(0.0, 0.0, viewport()->width(), viewport()->height());
|
||||
QRectF source(0.0, 0.0, viewport()->width(), viewport()->height());
|
||||
QPainter p(viewport());
|
||||
p.drawPixmap(target, pixmap, source);
|
||||
}
|
||||
|
||||
// Prepare graph
|
||||
// This computes the position and (row/col based) size of the block
|
||||
// Recursively calls itself for each child of the GraphBlock
|
||||
|
@ -104,6 +104,18 @@ public:
|
||||
int offset_x = 0;
|
||||
int offset_y = 0;
|
||||
|
||||
/**
|
||||
* @brief flag to control if the cached pixmap should be used
|
||||
*/
|
||||
bool useCache = false;
|
||||
|
||||
/**
|
||||
* @brief keep the current addr of the fcn of Graph
|
||||
* Everytime overview updates its contents, it compares this value with the one in Graph
|
||||
* if they aren't same, then Overview needs to update the pixmap cache.
|
||||
*/
|
||||
ut64 currentFcnAddr = 0;
|
||||
|
||||
protected:
|
||||
std::unordered_map<ut64, GraphBlock> blocks;
|
||||
QColor backgroundColor = QColor(Qt::white);
|
||||
@ -129,6 +141,7 @@ protected:
|
||||
virtual void wheelEvent(QWheelEvent *event) override;
|
||||
virtual EdgeConfiguration edgeConfiguration(GraphView::GraphBlock &from, GraphView::GraphBlock *to);
|
||||
|
||||
void drawGraph();
|
||||
bool event(QEvent *event) override;
|
||||
|
||||
// Mouse events
|
||||
@ -142,6 +155,12 @@ protected:
|
||||
void centerY();
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
/**
|
||||
* @brief pixmap that caches the graph nodes
|
||||
*/
|
||||
QPixmap pixmap;
|
||||
|
||||
private:
|
||||
bool checkPointClicked(QPointF &point, int x, int y, bool above_y = false);
|
||||
|
||||
|
@ -19,14 +19,14 @@ void OverviewView::setData(int baseWidth, int baseHeight, std::unordered_map<ut6
|
||||
width = baseWidth;
|
||||
height = baseHeight;
|
||||
blocks = baseBlocks;
|
||||
refreshView();
|
||||
scaleAndCenter();
|
||||
}
|
||||
|
||||
OverviewView::~OverviewView()
|
||||
{
|
||||
}
|
||||
|
||||
void OverviewView::refreshView()
|
||||
void OverviewView::scaleAndCenter()
|
||||
{
|
||||
current_scale = (qreal)viewport()->width() / width;
|
||||
qreal h_scale = (qreal)viewport()->height() / height;
|
||||
@ -34,6 +34,11 @@ void OverviewView::refreshView()
|
||||
current_scale = h_scale;
|
||||
}
|
||||
center();
|
||||
}
|
||||
|
||||
void OverviewView::refreshView()
|
||||
{
|
||||
scaleAndCenter();
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
@ -94,6 +99,7 @@ void OverviewView::mousePressEvent(QMouseEvent *event)
|
||||
qreal x = event->localPos().x() - w / 2;
|
||||
qreal y = event->localPos().y() - h / 2;
|
||||
rangeRect = QRectF(x, y, w, h);
|
||||
useCache = true;
|
||||
viewport()->update();
|
||||
emit mouseMoved();
|
||||
mouseContainsRect(event);
|
||||
@ -113,6 +119,7 @@ void OverviewView::mouseMoveEvent(QMouseEvent *event)
|
||||
qreal x = event->localPos().x() - initialDiff.x();
|
||||
qreal y = event->localPos().y() - initialDiff.y();
|
||||
rangeRect = QRectF(x, y, rangeRect.width(), rangeRect.height());
|
||||
useCache = true;
|
||||
viewport()->update();
|
||||
emit mouseMoved();
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ public:
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief refresh the view and adjust the scale
|
||||
* @brief scale and center all nodes in, then run update
|
||||
*/
|
||||
void refreshView();
|
||||
|
||||
@ -79,6 +79,11 @@ private:
|
||||
*/
|
||||
QPointF initialDiff;
|
||||
|
||||
/**
|
||||
* @brief calculate the scale to fit the all nodes in and center them in the viewport
|
||||
*/
|
||||
void scaleAndCenter();
|
||||
|
||||
/**
|
||||
* @brief draw the computed blocks passed by Graph
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user