[kgraphviewer-devel] [kgraphviewer] src/part: optimize: cache slow QFontMetrics calculations over paint events
Milian Wolff
mail at milianw.de
Thu Sep 22 20:57:02 UTC 2011
Git commit a12378611d1137d300a826e785a0e7270f8f2208 by Milian Wolff.
Committed on 15/07/2011 at 19:19.
Pushed by mwolff into branch 'master'.
optimize: cache slow QFontMetrics calculations over paint events
the introductions of the renderOperationsRevision should allow more optimizations
across paint events when nothing actually changed (i.e. only scrolling occurred)
M +12 -8 src/part/DotGraphParsingHelper.cpp
M +36 -12 src/part/canvaselement.cpp
M +4 -1 src/part/canvaselement.h
M +11 -6 src/part/dotgraph.cpp
M +17 -13 src/part/graphedge.cpp
M +8 -1 src/part/graphelement.cpp
M +8 -3 src/part/graphelement.h
M +9 -5 src/part/graphnode.cpp
M +11 -7 src/part/graphsubgraph.cpp
http://commits.kde.org/kgraphviewer/a12378611d1137d300a826e785a0e7270f8f2208
diff --git a/src/part/DotGraphParsingHelper.cpp b/src/part/DotGraphParsingHelper.cpp
index 0be9e81..69cac49 100644
--- a/src/part/DotGraphParsingHelper.cpp
+++ b/src/part/DotGraphParsingHelper.cpp
@@ -90,26 +90,28 @@ void DotGraphParsingHelper::setgraphelementattributes(GraphElement* ge, const At
}
}
+ DotRenderOpVec ops = ge->renderOperations();
if (attributes.find("_draw_") != attributes.end())
{
- parse_renderop((attributes.find("_draw_"))->second, ge->renderOperations());
+ parse_renderop((attributes.find("_draw_"))->second, ops);
// kDebug() << "element renderOperations size is now " << ge->renderOperations().size();
}
if (attributes.find("_ldraw_") != attributes.end())
{
- parse_renderop(attributes.find("_ldraw_")->second, ge->renderOperations());
+ parse_renderop(attributes.find("_ldraw_")->second, ops);
// kDebug() << "element renderOperations size is now " << ge->renderOperations().size();
}
if (attributes.find("_hldraw_") != attributes.end())
{
- parse_renderop(attributes.find("_hldraw_")->second, ge->renderOperations());
+ parse_renderop(attributes.find("_hldraw_")->second, ops);
// kDebug() << "element renderOperations size is now " << ge->renderOperations().size();
}
if (attributes.find("_tldraw_") != attributes.end())
{
- parse_renderop(attributes.find("_tldraw_")->second, ge->renderOperations());
+ parse_renderop(attributes.find("_tldraw_")->second, ops);
// kDebug() << "element renderOperations size is now " << ge->renderOperations().size();
}
+ ge->setRenderOperations(ops);
}
void DotGraphParsingHelper::setgraphattributes()
@@ -150,24 +152,26 @@ void DotGraphParsingHelper::setedgeattributes()
// kDebug() << "z="<<ge->z();
setgraphelementattributes(ge, edgesAttributes);
+ DotRenderOpVec ops = ge->renderOperations();
if (edgesAttributes.find("_tdraw_") != edgesAttributes.end())
{
- parse_renderop(edgesAttributes["_tdraw_"], ge->renderOperations());
+ parse_renderop(edgesAttributes["_tdraw_"], ops);
// kDebug() << "edge renderOperations size is now " << ge->renderOperations().size();
DotRenderOpVec::const_iterator it, it_end;
- it = ge->renderOperations().constBegin(); it_end = ge->renderOperations().constEnd();
+ it = ops.constBegin(); it_end = ops.constEnd();
for (; it != it_end; it++)
ge->arrowheads().push_back(*it);
}
if (edgesAttributes.find("_hdraw_") != edgesAttributes.end())
{
- parse_renderop(edgesAttributes["_hdraw_"], ge->renderOperations());
+ parse_renderop(edgesAttributes["_hdraw_"], ops);
// kDebug() << "edge renderOperations size is now " << ge->renderOperations().size();
DotRenderOpVec::const_iterator it, it_end;
- it = ge->renderOperations().constBegin(); it_end = ge->renderOperations().constEnd();
+ it = ops.constBegin(); it_end = ops.constEnd();
for (; it != it_end; it++)
ge->arrowheads().push_back(*it);
}
+ ge->setRenderOperations(ops);
}
void DotGraphParsingHelper::setattributedlist()
diff --git a/src/part/canvaselement.cpp b/src/part/canvaselement.cpp
index dcbb28e..57f1b1d 100644
--- a/src/part/canvaselement.cpp
+++ b/src/part/canvaselement.cpp
@@ -54,10 +54,12 @@ CanvasElement::CanvasElement(
m_font(0),
m_pen(Dot2QtConsts::componentData().qtColor(gelement->fontColor())),
m_popup(new QMenu()),
- m_hovered(false)
+ m_hovered(false),
+ m_lastRenderOpRev(0)
{
// kDebug();
m_font = FontsCache::changeable().fromName(gelement->fontName());
+
/* kDebug() << "Creating CanvasElement for "<<gelement->id();
kDebug() << " data: " << wdhcf << "," << hdvcf << "," << gh << ","
<< scaleX << "," << scaleY << "," << xMargin << "," << yMargin << endl;*/
@@ -206,9 +208,14 @@ void CanvasElement::computeBoundingRect()
setPos(0,0);
}
+///TODO: optimize more!
void CanvasElement::paint(QPainter* p, const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
+ if (m_lastRenderOpRev != element()->renderOperationsRevision()) {
+ m_fontSizeCache.clear();
+ }
+
Q_UNUSED(option)
Q_UNUSED(widget)
/// computes the scaling of line width
@@ -422,6 +429,7 @@ QWidget *widget)
// kDebug() << "Drawing" << element()->id() << "labels";
QString color = lineColor.name();
it.toFront();
+ uint num_T = 0;
while (it.hasNext())
{
const DotRenderOp& dro = it.next();
@@ -438,6 +446,7 @@ QWidget *widget)
}
else if ( dro.renderop == "T" )
{
+ ++num_T;
// we suppose here that the color has been set just before
element()->setFontColor(color);
// draw a label
@@ -447,20 +456,33 @@ QWidget *widget)
// << " (" << element()->fontName() << ", " << element()->fontSize()
// << ", " << element()->fontColor() << ")";
- int stringWidthGoal = int(dro.integers[3] * m_scaleX);
- int fontSize = element()->fontSize();
+ int fontWidth = 0;
+ bool cacheValid = false;
// kDebug() << element()->id() << " initial fontSize " << fontSize;
- m_font->setPointSize(fontSize);
-
- QFontMetrics fm(*m_font);
- int fontWidth = fm.width(dro.str);
- while (fontWidth > stringWidthGoal && fontSize > 1)
- {
- // use floor'ed extrapolated font size
- fontSize = double(stringWidthGoal) / fontWidth * fontSize;
+ if (m_lastRenderOpRev == element()->renderOperationsRevision()) {
+ FontSizeCache::iterator cacheIt = m_fontSizeCache.find(num_T);
+ if (cacheIt != m_fontSizeCache.end()) {
+ m_font->setPointSize(cacheIt->first);
+ fontWidth = cacheIt->second;
+ cacheValid = true;
+ }
+ }
+ if (!cacheValid) {
+ int stringWidthGoal = int(dro.integers[3] * m_scaleX);
+ int fontSize = element()->fontSize();
m_font->setPointSize(fontSize);
- fm = QFontMetrics(*m_font);
+
+ QFontMetrics fm(*m_font);
fontWidth = fm.width(dro.str);
+ while (fontWidth > stringWidthGoal && fontSize > 1)
+ {
+ // use floor'ed extrapolated font size
+ fontSize = double(stringWidthGoal) / fontWidth * fontSize;
+ m_font->setPointSize(fontSize);
+ fm = QFontMetrics(*m_font);
+ fontWidth = fm.width(dro.str);
+ }
+ m_fontSizeCache[num_T] = qMakePair(fontSize, fontWidth);
}
p->save();
@@ -495,6 +517,8 @@ QWidget *widget)
p->drawRect(QRectF(m_boundingRect.bottomRight()-QPointF(6,6),QSizeF(6,6)));
p->restore();
}
+
+ m_lastRenderOpRev = element()->renderOperationsRevision();
}
void CanvasElement::mousePressEvent(QGraphicsSceneMouseEvent* event)
diff --git a/src/part/canvaselement.h b/src/part/canvaselement.h
index 40aedb3..5a79576 100644
--- a/src/part/canvaselement.h
+++ b/src/part/canvaselement.h
@@ -83,7 +83,10 @@ public:
QMenu* m_popup;
bool m_hovered;
-
+
+ quint32 m_lastRenderOpRev;
+ typedef QHash<int, QPair<int, int> > FontSizeCache;
+ FontSizeCache m_fontSizeCache;
Q_SIGNALS:
void selected(CanvasElement*, Qt::KeyboardModifiers);
void elementContextMenuEvent(const QString&, const QPoint&);
diff --git a/src/part/dotgraph.cpp b/src/part/dotgraph.cpp
index fdb53ad..b9f2b9b 100644
--- a/src/part/dotgraph.cpp
+++ b/src/part/dotgraph.cpp
@@ -399,18 +399,23 @@ void DotGraph::updateWithGraph(graph_t* newGraph)
kDebug();
// copy global graph render operations and attributes
- renderOperations().clear();
+ DotRenderOpVec ops;
+ // decrease mem peak
+ setRenderOperations(ops);
+
if (agget(newGraph, (char*)"_draw_") != NULL)
{
- parse_renderop(agget(newGraph, (char*)"_draw_"), renderOperations());
- kDebug() << "_draw_: element renderOperations size is now " << renderOperations().size();
+ parse_renderop(agget(newGraph, (char*)"_draw_"), ops);
+ kDebug() << "_draw_: element renderOperations size is now " << ops.size();
}
if (agget(newGraph, (char*)"_ldraw_") != NULL)
{
- parse_renderop(agget(newGraph, (char*)"_ldraw_"), renderOperations());
- kDebug() << "_ldraw_: element renderOperations size is now " << renderOperations().size();
+ parse_renderop(agget(newGraph, (char*)"_ldraw_"), ops);
+ kDebug() << "_ldraw_: element renderOperations size is now " << ops.size();
}
-
+
+ setRenderOperations(ops);
+
Agsym_t *attr = agfstattr(newGraph);
while(attr)
{
diff --git a/src/part/graphedge.cpp b/src/part/graphedge.cpp
index bfe5665..3492f99 100644
--- a/src/part/graphedge.cpp
+++ b/src/part/graphedge.cpp
@@ -106,37 +106,41 @@ void GraphEdge::updateWithEdge(const GraphEdge& edge)
void GraphEdge::updateWithEdge(edge_t* edge)
{
kDebug();
- renderOperations().clear();
+ DotRenderOpVec ops;
+ // decrease mem peak
+ setRenderOperations(ops);
+
if (agget(edge, (char*)"_draw_") != NULL)
{
- parse_renderop(agget(edge, (char*)"_draw_"), renderOperations());
- kDebug() << "element renderOperations size is now " << renderOperations().size();
+ parse_renderop(agget(edge, (char*)"_draw_"), ops);
+ kDebug() << "element renderOperations size is now " << ops.size();
}
if (agget(edge, (char*)"_ldraw_") != NULL)
{
- parse_renderop(agget(edge, (char*)"_ldraw_"), renderOperations());
- kDebug() << "element renderOperations size is now " << renderOperations().size();
+ parse_renderop(agget(edge, (char*)"_ldraw_"), ops);
+ kDebug() << "element renderOperations size is now " << ops.size();
}
if (agget(edge, (char*)"_hdraw_") != NULL)
{
- parse_renderop(agget(edge, (char*)"_hdraw_"), renderOperations());
- kDebug() << "element renderOperations size is now " << renderOperations().size();
+ parse_renderop(agget(edge, (char*)"_hdraw_"), ops);
+ kDebug() << "element renderOperations size is now " << ops.size();
}
if (agget(edge, (char*)"_tdraw_") != NULL)
{
- parse_renderop(agget(edge, (char*)"_tdraw_"), renderOperations());
- kDebug() << "element renderOperations size is now " << renderOperations().size();
+ parse_renderop(agget(edge, (char*)"_tdraw_"), ops);
+ kDebug() << "element renderOperations size is now " << ops.size();
}
if (agget(edge, (char*)"_hldraw_") != NULL)
{
- parse_renderop(agget(edge, (char*)"_hldraw_"), renderOperations());
- kDebug() << "element renderOperations size is now " << renderOperations().size();
+ parse_renderop(agget(edge, (char*)"_hldraw_"), ops);
+ kDebug() << "element renderOperations size is now " << ops.size();
}
if (agget(edge, (char*)"_tldraw_") != NULL)
{
- parse_renderop(agget(edge, (char*)"_tldraw_"), renderOperations());
- kDebug() << "element renderOperations size is now " << renderOperations().size();
+ parse_renderop(agget(edge, (char*)"_tldraw_"), ops);
+ kDebug() << "element renderOperations size is now " << ops.size();
}
+ setRenderOperations(ops);
Agsym_t *attr = agfstattr(edge);
while(attr)
{
diff --git a/src/part/graphelement.cpp b/src/part/graphelement.cpp
index 52d9fa8..bc409f8 100644
--- a/src/part/graphelement.cpp
+++ b/src/part/graphelement.cpp
@@ -58,12 +58,19 @@ GraphElement::GraphElement(const GraphElement& element) : QObject(),
m_ce(element.m_ce),
m_z(element.m_z),
m_renderOperations(),
+ m_renderOperationsRevision(0),
m_selected(element.m_selected)
{
kDebug() ;
updateWithElement(element);
}
+void GraphElement::setRenderOperations(const DotRenderOpVec& drov)
+{
+ m_renderOperations = drov;
+ ++m_renderOperationsRevision;
+}
+
void GraphElement::updateWithElement(const GraphElement& element)
{
kDebug() << element.id();
@@ -91,7 +98,7 @@ void GraphElement::updateWithElement(const GraphElement& element)
if (modified)
{
kDebug() << "modified: update render operations";
- m_renderOperations = element.m_renderOperations;
+ setRenderOperations(element.m_renderOperations);
/* foreach (DotRenderOp op, m_renderOperations)
{
QString msg;
diff --git a/src/part/graphelement.h b/src/part/graphelement.h
index 5a65574..a840300 100644
--- a/src/part/graphelement.h
+++ b/src/part/graphelement.h
@@ -68,10 +68,14 @@ public:
inline QString fontColor() const {return m_attributes["fontcolor"];}
inline void setFontColor(const QString& fc) {m_attributes["fontcolor"] = fc;}
- inline DotRenderOpVec& renderOperations() {return m_renderOperations;};
inline const DotRenderOpVec& renderOperations() const {return m_renderOperations;};
- inline void setRenderOperations(DotRenderOpVec& drov) {m_renderOperations = drov;};
-
+ void setRenderOperations(const DotRenderOpVec& drov);
+ /**
+ * indicates the version of the render operations, gets increased everytime
+ * @c setRenderOperations gets called.
+ */
+ inline quint32 renderOperationsRevision() const {return m_renderOperationsRevision;};
+
inline double z() const {return m_z;}
inline void setZ(double thez) {m_z = thez;}
@@ -118,6 +122,7 @@ private:
bool m_visible;
DotRenderOpVec m_renderOperations;
+ quint32 m_renderOperationsRevision;
bool m_selected;
};
diff --git a/src/part/graphnode.cpp b/src/part/graphnode.cpp
index 60d7ed1..cc283aa 100644
--- a/src/part/graphnode.cpp
+++ b/src/part/graphnode.cpp
@@ -82,19 +82,23 @@ void GraphNode::updateWithNode(node_t* node)
m_attributes["id"] = node->name;
m_attributes["label"] = ND_label(node)->text;
+ DotRenderOpVec ops;
+ // decrease mem peak
+ setRenderOperations(ops);
- renderOperations().clear();
if (agget(node, (char*)"_draw_") != NULL)
{
- parse_renderop(agget(node, (char*)"_draw_"), renderOperations());
- kDebug() << "_draw_: element renderOperations size is now " << renderOperations().size();
+ parse_renderop(agget(node, (char*)"_draw_"), ops);
+ kDebug() << "_draw_: element renderOperations size is now " << ops.size();
}
if (agget(node, (char*)"_ldraw_") != NULL)
{
- parse_renderop(agget(node, (char*)"_ldraw_"), renderOperations());
- kDebug() << "_ldraw_: element renderOperations size is now " << renderOperations().size();
+ parse_renderop(agget(node, (char*)"_ldraw_"), ops);
+ kDebug() << "_ldraw_: element renderOperations size is now " << ops.size();
}
+ setRenderOperations(ops);
+
Agsym_t *attr = agfstattr(node);
while(attr)
{
diff --git a/src/part/graphsubgraph.cpp b/src/part/graphsubgraph.cpp
index d664dec..07bc8db 100644
--- a/src/part/graphsubgraph.cpp
+++ b/src/part/graphsubgraph.cpp
@@ -107,19 +107,23 @@ void GraphSubgraph::updateWithSubgraph(graph_t* subgraph)
if (GD_label(subgraph))
m_attributes["label"] = GD_label(subgraph)->text;
-
- renderOperations().clear();
+ DotRenderOpVec ops;
+ // decrease mem peak
+ setRenderOperations(ops);
+
if (agget(subgraph, (char*)"_draw_") != NULL)
{
- parse_renderop(agget(subgraph, (char*)"_draw_"), renderOperations());
- kDebug() << "_draw_: element renderOperations size is now " << renderOperations().size();
+ parse_renderop(agget(subgraph, (char*)"_draw_"), ops);
+ kDebug() << "_draw_: element renderOperations size is now " << ops.size();
}
if (agget(subgraph, (char*)"_ldraw_") != NULL)
{
- parse_renderop(agget(subgraph, (char*)"_ldraw_"), renderOperations());
- kDebug() << "_ldraw_: element renderOperations size is now " << renderOperations().size();
+ parse_renderop(agget(subgraph, (char*)"_ldraw_"), ops);
+ kDebug() << "_ldraw_: element renderOperations size is now " << ops.size();
}
-
+
+ setRenderOperations(ops);
+
Agsym_t *attr = agfstattr(subgraph);
while(attr)
{
More information about the kgraphviewer-devel
mailing list