]> git.siccegge.de Git - frida/frida.git/blobdiff - src/gui/widgets/CFGScene.cxx
Add comments on how the graph is drawn
[frida/frida.git] / src / gui / widgets / CFGScene.cxx
index 7bed8f14b9de2d924b28dc12435a882c9a42028c..aa27f2c1722caed1bfc2bb5e277ec10ab5495573 100644 (file)
 #include "CFGScene.hxx"
 
 void CFGScene::drawBackground(QPainter* painter, const QRectF & rect) {
-    QGraphicsScene::drawBackground(painter, rect);
-
-    spaceWidgets();
-
-    for (BasicBlockWidget * widget : widgets) {
-        QPointF kopf = widget->getEntry();
-        painter->setPen(QColor(0x00, 0xff, 0x00, 0xff));
-        painter->drawLine(kopf, kopf - QPointF(0, 20));
-
-        auto tails = widget->getExits();
-        auto next = widget->getNext();
-        if (NULL != next[0]) {
-            if (NULL != next[1]) {
-                painter->setPen(QColor(0xff, 0x00, 0x00, 0xff));
-                painter->drawLine(std::get<0>(tails), std::get<0>(tails) + QPointF(0, 20));
-                drawLine(painter, std::get<0>(tails) + QPointF(0, 20), next[1]->getEntry() - QPointF(0, 20));
-                painter->setPen(QColor(0x00, 0xff, 0x00, 0xff));
-                painter->drawLine(std::get<2>(tails), std::get<2>(tails) + QPointF(0, 20));
-                drawLine(painter, std::get<2>(tails) + QPointF(0, 20), next[0]->getEntry() - QPointF(0, 20));
-            } else {
-                painter->setPen(QColor(0x00, 0x00, 0x00, 0xff));
-                painter->drawLine(std::get<1>(tails), std::get<1>(tails) + QPointF(0, 20));
-                drawLine(painter, std::get<1>(tails) + QPointF(0, 20), next[0]->getEntry() - QPointF(0, 20));
-            }
-        }
-    }
+       QGraphicsScene::drawBackground(painter, rect);
+
+       spaceWidgets();
+
+       for (BasicBlockWidget * widget : widgets) {
+               QPointF kopf = widget->getEntry();
+               painter->setPen(QColor(0x00, 0xff, 0x00, 0xff));
+               painter->drawLine(kopf, kopf - QPointF(0, 20));
+
+               auto tails = widget->getExits();
+               auto next = widget->getNext();
+               if (NULL != next[0]) {
+                       if (NULL != next[1]) {
+                               painter->setPen(QColor(0xff, 0x00, 0x00, 0xff));
+                               painter->drawLine(std::get<0>(tails), std::get<0>(tails) + QPointF(0, 20));
+                               drawLine(painter, widget, next[1], -1);
+
+                               painter->setPen(QColor(0x00, 0xff, 0x00, 0xff));
+                               painter->drawLine(std::get<2>(tails), std::get<2>(tails) + QPointF(0, 20));
+                               drawLine(painter, widget, next[0], 1);
+                       } else {
+                               painter->setPen(QColor(0x00, 0x00, 0x00, 0xff));
+                               painter->drawLine(std::get<1>(tails), std::get<1>(tails) + QPointF(0, 20));
+                               drawLine(painter, widget, next[0], 0);
+                       }
+               }
+       }
 }
 
-void CFGScene::drawLine(QPainter* painter, QPointF from, QPointF to, bool left) {
-    if ((to - from).y() > 0) {
-        QPointF angle1(from + QPointF(0, (to - from).y())), angle2(to - QPointF(0, (to - from).y() / 2));
-        painter->drawLine(from,   angle1);
-        painter->drawLine(angle1, to);
-    }
+/* Forward edges:  Forward (downward) edges are just drawn straight
+ *                 down and then to the right side
+ * Backward edges: Consider the smallest rectangle that contains both,
+ *                 source and destination block. Draw the edge along
+ *                 the shorter side of that rectangle
+ */
+void CFGScene::drawLine(QPainter* painter, BasicBlockWidget * from, BasicBlockWidget * to, int8_t side) {
+       QPointF from_p = from->getExits()[side+1] + QPointF(0, 20);
+       QPointF to_p = to->getEntry() - QPointF(0, 20);
+       if ((to_p - from_p).y() > 0) {
+               /* Forward Edge */
+               QPointF angle1(from_p + QPointF(0, (to_p - from_p).y()));
+               painter->drawLine(from_p,   angle1);
+               painter->drawLine(angle1, to_p);
+       } else {
+               /* Backward Edge */
+               QRectF from_r(from->boundingRect()), to_r(to->boundingRect());
+               from_r.moveTo(from->scenePos());
+               to_r.moveTo(to->scenePos());
+               QRectF bound = from_r | to_r;
+               if (std::abs(bound.right() - from_p.x()) > std::abs(bound.left() - to_p.x())) {
+                       /* we go left */
+                       QPointF middle1 = from_p + QPointF(bound.left() - from_p.x() - 20, 0);
+                       QPointF middle2 = to_p   + QPointF(bound.left() - to_p.x()   - 20, 0);
+
+                       painter->drawLine(from_p, middle1);
+                       painter->drawLine(middle1, middle2);
+                       painter->drawLine(middle2, to_p);
+               } else {
+                       /* we go right */
+                       QPointF middle1 = from_p - QPointF(from_p.x() - bound.right() - 20, 0);
+                       QPointF middle2 = to_p   - QPointF(to_p.x()   - bound.right() - 20, 0);
+
+                       painter->drawLine(from_p, middle1);
+                       painter->drawLine(middle1, middle2);
+                       painter->drawLine(middle2, to_p);
+               }
+       }
 }
 
 void CFGScene::spaceWidgets() {
-    bool changed = false;
-    do {
-        changed = false;
-        for (BasicBlockWidget * widget : widgets) {
-            QPointF out(std::get<0>(widget->getExits()));
-            BasicBlockWidget ** next = widget->getNext();
-
-            if (NULL != next[0]
-                && (next[0]->getEntry() - widget->getEntry()).y() > 0
-                && (next[0]->getEntry() - out).y() < 50) {
-                next[0]->moveBy(0, 1);
-                changed = true;
-            }
-            if (NULL != next[1]
-                && (next[1]->getEntry() - widget->getEntry()).y() > 0
-                && (next[1]->getEntry() - out).y() < 50) {
-                next[1]->moveBy(0, 1);
-                changed = true;
-            }
-        }
-    } while (changed);
+       bool changed = false;
+
+       /* While some BasicBlockWidget overlaps with a direct predecessor,
+        * move that widget down one step. Move each widget at most once
+        * per iteration so that widgets with severall incoming edges
+        * don't outrun these with less -- preserving order by address
+        * where appropriate.
+        */
+       do {
+               changed = false;
+               for (BasicBlockWidget * widget : widgets) {
+                       QPointF out(std::get<0>(widget->getExits()));
+                       BasicBlockWidget ** next = widget->getNext();
+
+                       if (NULL != next[0]
+                           && (next[0]->getEntry() - widget->getEntry()).y() > 0
+                           && (next[0]->getEntry() - out).y() < 50) {
+                               widget->moveBy(0, -1);
+                               changed = true;
+                       } else if (NULL != next[1]
+                           && (next[1]->getEntry() - widget->getEntry()).y() > 0
+                           && (next[1]->getEntry() - out).y() < 50) {
+                               widget->moveBy(0, -1);
+                               changed = true;
+                       }
+               }
+       } while (changed);
+
+       /* If there are still BasicBlockWidgets overlapping (BasicBlocks
+        * that don't have a direct edge) spread them sideways.
+        */
+       for (BasicBlockWidget * widget : widgets) {
+               QRectF relevantRect = widget->boundingRect();
+               relevantRect.moveTo(widget->scenePos());
+               relevantRect.adjust(-20, -20, 20, 20);
+               for (QGraphicsItem * item : items(relevantRect)) {
+                       if (item == widget) continue;
+                       if (std::find(widgets.begin(), widgets.end(), item) == widgets.end()) continue;
+                       QRectF itemrect = item->boundingRect();
+                       itemrect.moveTo(item->scenePos());
+                       while (relevantRect.intersects(itemrect)) {
+                               if (widget->scenePos().x() > item->scenePos().x()) {
+                                       widget->moveBy(1, 0);
+                                       relevantRect.moveTo(widget->scenePos());
+                               } else {
+                                       item->moveBy(1, 0);
+                                       itemrect.moveTo(item->scenePos());
+                               }
+                       }
+               }
+       }
+}
+
+void CFGScene::highlightBlock(BasicBlockWidget* block) {
+       QGraphicsView* view = *(views().begin());
+       if (highlightedBlock) {
+               highlightedBlock->setColor(highlightedBlock->defaultColor);
+               update(highlightedBlock->boundingRect());
+       }
+       highlightedBlock = block;
+       view->centerOn(block);
+       block->setColor(block->highlightColor);
+       update(block->boundingRect());
 }