X-Git-Url: https://git.siccegge.de//index.cgi?p=frida%2Ffrida.git;a=blobdiff_plain;f=src%2Fgui%2Fwidgets%2FCFGScene.cxx;h=aa27f2c1722caed1bfc2bb5e277ec10ab5495573;hp=a297c856f3dd7dc8aa91e5a29e8d3c9da59cb7dc;hb=cfd10a87780a598987c3de0b2850fa22addb0798;hpb=fae0fc8f1d90f5f36cfc336a92aa9d488471332d diff --git a/src/gui/widgets/CFGScene.cxx b/src/gui/widgets/CFGScene.cxx index a297c85..aa27f2c 100644 --- a/src/gui/widgets/CFGScene.cxx +++ b/src/gui/widgets/CFGScene.cxx @@ -1,73 +1,137 @@ #include "CFGScene.hxx" void CFGScene::drawBackground(QPainter* painter, const QRectF & rect) { - QGraphicsScene::drawBackground(painter, rect); + QGraphicsScene::drawBackground(painter, rect); - spaceWidgets(); + spaceWidgets(); - for (BasicBlockWidget * widget : widgets) { - QPointF kopf = widget->getEntry(); - painter->setPen(QColor(0x00, 0xff, 0x00, 0xff)); - painter->drawLine(kopf, kopf - QPointF(0, 20)); + 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)); - } - } - } + 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(); + bool changed = false; - 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); + /* 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()); + } + } + } + } +} - for (BasicBlockWidget * widget : widgets) { - for (QGraphicsItem * item : widget->collidingItems()) { - while (widget->collidesWithItem(item)) { - if (widget->scenePos().x() > item->scenePos().x()) - widget->moveBy(1, 0); - else - item->moveBy(1, 0); - } - } - } +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()); }