#include "qpainterpath.h"
#include "qpainterpath_p.h"
#include <qbitmap.h>
#include <qdebug.h>
#include <qiodevice.h>
#include <qlist.h>
#include <qmatrix.h>
#include <qpen.h>
#include <qpolygon.h>
#include <qtextlayout.h>
#include <qvarlengtharray.h>
#include <private/qbezier_p.h>
#include <private/qfontengine_p.h>
#include <private/qmath_p.h>
#include <private/qnumeric_p.h>
#include <private/qobject_p.h>
#include <private/qstroker_p.h>
#include <private/qtextengine_p.h>
#include <limits.h>
#include <math.h>
Include dependency graph for qpainterpath.cpp:

Go to the source code of this file.
Classes | |
| class | QPainterPathStrokerPrivate |
Defines | |
| #define | M_PI 3.14159265358979323846 |
| #define | PM_INIT |
| #define | PM_MEASURE(x) |
| #define | PM_DISPLAY |
| #define | KAPPA 0.5522847498 |
| #define | ANGLE(t) ((t) * 2 * M_PI / 360.0) |
| #define | QT_BEZIER_A(bezier, coord) |
| #define | QT_BEZIER_B(bezier, coord) |
| #define | QT_BEZIER_C(bezier, coord) |
| #define | QT_BEZIER_CHECK_T(bezier, t) |
Functions | |
| QPainterPath | qt_stroke_dash (const QPainterPath &path, qreal *dashes, int dashCount) |
| void | qt_find_ellipse_coords (const QRectF &r, qreal angle, qreal length, QPointF *startPoint, QPointF *endPoint) |
| static QRectF | qt_painterpath_bezier_extrema (const QBezier &b) |
| static bool | rect_intersects (const QRectF &r1, const QRectF &r2) |
| static void | qt_painterpath_isect_line (const QPointF &p1, const QPointF &p2, const QPointF &pos, int *winding) |
| static void | qt_painterpath_isect_curve (const QBezier &bezier, const QPointF &pt, int *winding) |
| static bool | qt_painterpath_isect_line_rect (qreal x1, qreal y1, qreal x2, qreal y2, const QRectF &rect) |
| static bool | qt_isect_curve_horizontal (const QBezier &bezier, qreal y, qreal x1, qreal x2) |
| static bool | qt_isect_curve_vertical (const QBezier &bezier, qreal x, qreal y1, qreal y2) |
| static bool | qt_painterpath_check_crossing (const QPainterPath *path, const QRectF &rect) |
| QDataStream & | operator<< (QDataStream &s, const QPainterPath &p) |
| QDataStream & | operator>> (QDataStream &s, QPainterPath &p) |
| void | qt_path_stroke_move_to (qfixed x, qfixed y, void *data) |
| void | qt_path_stroke_line_to (qfixed x, qfixed y, void *data) |
| void | qt_path_stroke_cubic_to (qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey, void *data) |
| #define ANGLE | ( | t | ) | ((t) * 2 * M_PI / 360.0) |
Referenced by qt_curves_for_arc(), and qt_find_ellipse_coords().
| #define KAPPA 0.5522847498 |
Definition at line 72 of file qpainterpath.cpp.
| #define M_PI 3.14159265358979323846 |
Definition at line 58 of file qpainterpath.cpp.
Referenced by PieView::indexAt(), qdesigner_internal::QtGradientWidget::mouseMoveEvent(), qdesigner_internal::QtGradientWidget::mousePressEvent(), qdesigner_internal::QtGradientWidget::paintEvent(), pathArc(), pathArcSegment(), and KAsteroidsView::processShip().
| #define PM_DISPLAY |
Definition at line 66 of file qpainterpath.cpp.
| #define PM_INIT |
Definition at line 64 of file qpainterpath.cpp.
| #define PM_MEASURE | ( | x | ) |
Definition at line 65 of file qpainterpath.cpp.
| #define QT_BEZIER_A | ( | bezier, | |||
| coord | ) |
Value:
3 * (-bezier.coord##1 \
+ 3*bezier.coord##2 \
- 3*bezier.coord##3 \
+bezier.coord##4)
Definition at line 1287 of file qpainterpath.cpp.
Referenced by qt_painterpath_bezier_extrema().
| #define QT_BEZIER_B | ( | bezier, | |||
| coord | ) |
Value:
6 * (bezier.coord##1 \
- 2*bezier.coord##2 \
+ bezier.coord##3)
Definition at line 1292 of file qpainterpath.cpp.
Referenced by qt_painterpath_bezier_extrema().
| #define QT_BEZIER_C | ( | bezier, | |||
| coord | ) |
Value:
3 * (- bezier.coord##1 \
+ bezier.coord##2)
Definition at line 1296 of file qpainterpath.cpp.
Referenced by qt_painterpath_bezier_extrema().
| #define QT_BEZIER_CHECK_T | ( | bezier, | |||
| t | ) |
Value:
if (t >= 0 && t <= 1) { \ QPointF p(b.pointAt(t)); \ if (p.x() < minx) minx = p.x(); \ else if (p.x() > maxx) maxx = p.x(); \ if (p.y() < miny) miny = p.y(); \ else if (p.y() > maxy) maxy = p.y(); \ }
Definition at line 1299 of file qpainterpath.cpp.
Referenced by qt_painterpath_bezier_extrema().
| QDataStream& operator<< | ( | QDataStream & | s, | |
| const QPainterPath & | p | |||
| ) |
Definition at line 2199 of file qpainterpath.cpp.
02200 { 02201 if (p.isEmpty()) { 02202 s << 0; 02203 return s; 02204 } 02205 02206 s << p.elementCount(); 02207 for (int i=0; i < p.d_func()->elements.size(); ++i) { 02208 const QPainterPath::Element &e = p.d_func()->elements.at(i); 02209 s << int(e.type); 02210 s << double(e.x) << double(e.y); 02211 } 02212 s << p.d_func()->cStart; 02213 s << int(p.d_func()->fillRule); 02214 return s; 02215 }
| QDataStream& operator>> | ( | QDataStream & | s, | |
| QPainterPath & | p | |||
| ) |
Definition at line 2226 of file qpainterpath.cpp.
02227 { 02228 int size; 02229 s >> size; 02230 02231 if (size == 0) 02232 return s; 02233 02234 p.ensureData(); // in case if p.d_func() == 0 02235 if (p.d_func()->elements.size() == 1) { 02236 Q_ASSERT(p.d_func()->elements.at(0).type == QPainterPath::MoveToElement); 02237 p.d_func()->elements.clear(); 02238 } 02239 p.d_func()->elements.reserve(p.d_func()->elements.size() + size); 02240 for (int i=0; i<size; ++i) { 02241 int type; 02242 double x, y; 02243 s >> type; 02244 s >> x; 02245 s >> y; 02246 Q_ASSERT(type >= 0 && type <= 3); 02247 #ifndef QT_NO_DEBUG 02248 if (qIsNan(x) || qIsNan(y)) 02249 qWarning("QDataStream::operator>>: Adding a NaN element to path, results are undefined"); 02250 #endif 02251 QPainterPath::Element elm = { x, y, QPainterPath::ElementType(type) }; 02252 p.d_func()->elements.append(elm); 02253 } 02254 s >> p.d_func()->cStart; 02255 int fillRule; 02256 s >> fillRule; 02257 Q_ASSERT(fillRule == Qt::OddEvenFill || Qt::WindingFill); 02258 p.d_func()->fillRule = Qt::FillRule(fillRule); 02259 return s; 02260 }
| void qt_find_ellipse_coords | ( | const QRectF & | r, | |
| qreal | angle, | |||
| qreal | length, | |||
| QPointF * | startPoint, | |||
| QPointF * | endPoint | |||
| ) |
Definition at line 80 of file qpainterpath.cpp.
References a, ANGLE, b, QRectF::center(), QRectF::height(), and QRectF::width().
Referenced by QPainterPath::arcMoveTo(), and Q3PointArray::makeArc().
00082 { 00083 #define ANGLE(t) ((t) * 2 * M_PI / 360.0) 00084 qreal a = r.width() / 2.0; 00085 qreal b = r.height() / 2.0; 00086 00087 if (startPoint) { 00088 *startPoint = r.center() 00089 + QPointF(a * cos(ANGLE(angle)), -b * sin(ANGLE(angle))); 00090 } 00091 if (endPoint) { 00092 *endPoint = r.center() 00093 + QPointF(a * cos(ANGLE(angle + length)), -b * sin(ANGLE(angle + length))); 00094 } 00095 }
Here is the call graph for this function:

| static bool qt_isect_curve_horizontal | ( | const QBezier & | bezier, | |
| qreal | y, | |||
| qreal | x1, | |||
| qreal | x2 | |||
| ) | [static] |
Definition at line 1931 of file qpainterpath.cpp.
References QRectF::bottom(), QBezier::bounds(), QRectF::height(), QRectF::left(), QRectF::right(), QBezier::split(), QRectF::top(), and QRectF::width().
Referenced by qt_isect_curve_vertical(), and qt_painterpath_check_crossing().
01932 { 01933 QRectF bounds = bezier.bounds(); 01934 01935 if (y >= bounds.top() && y < bounds.bottom() 01936 && bounds.right() >= x1 && bounds.left() < x2) { 01937 const qreal lower_bound = .01; 01938 if (bounds.width() < lower_bound && bounds.height() < lower_bound) 01939 return true; 01940 01941 QBezier first_half, second_half; 01942 bezier.split(&first_half, &second_half); 01943 qreal midpoint = x1 + (x2 - x1) / 2; 01944 if (qt_isect_curve_horizontal(first_half, y, x1, midpoint) 01945 || qt_isect_curve_horizontal(first_half, y, midpoint, x2) 01946 || qt_isect_curve_horizontal(second_half, y, x1, midpoint) 01947 || qt_isect_curve_horizontal(second_half, y, midpoint, x2)) 01948 return true; 01949 } 01950 return false; 01951 }
Here is the call graph for this function:

| static bool qt_isect_curve_vertical | ( | const QBezier & | bezier, | |
| qreal | x, | |||
| qreal | y1, | |||
| qreal | y2 | |||
| ) | [static] |
Definition at line 1953 of file qpainterpath.cpp.
References QRectF::bottom(), QBezier::bounds(), QRectF::height(), QRectF::left(), qt_isect_curve_horizontal(), QRectF::right(), QBezier::split(), QRectF::top(), and QRectF::width().
Referenced by qt_painterpath_check_crossing().
01954 { 01955 QRectF bounds = bezier.bounds(); 01956 01957 if (x >= bounds.left() && x < bounds.right() 01958 && bounds.top() >= y1 && bounds.bottom() < y2) { 01959 const qreal lower_bound = .01; 01960 if (bounds.width() < lower_bound && bounds.height() < lower_bound) 01961 return true; 01962 01963 QBezier first_half, second_half; 01964 bezier.split(&first_half, &second_half); 01965 qreal midpoint = y1 + (y2 - y1) / 2; 01966 if (qt_isect_curve_horizontal(first_half, x, y1, midpoint) 01967 || qt_isect_curve_horizontal(first_half, x, midpoint, y2) 01968 || qt_isect_curve_horizontal(second_half, x, y1, midpoint) 01969 || qt_isect_curve_horizontal(second_half, x, midpoint, y2)) 01970 return true; 01971 } 01972 return false; 01973 }
Here is the call graph for this function:

Definition at line 1309 of file qpainterpath.cpp.
References b, QT_BEZIER_A, QT_BEZIER_B, QT_BEZIER_C, QT_BEZIER_CHECK_T, t, x, and y.
Referenced by QPainterPath::boundingRect().
01310 { 01311 qreal minx, miny, maxx, maxy; 01312 01313 // initialize with end points 01314 if (b.x1 < b.x4) { 01315 minx = b.x1; 01316 maxx = b.x4; 01317 } else { 01318 minx = b.x4; 01319 maxx = b.x1; 01320 } 01321 if (b.y1 < b.y4) { 01322 miny = b.y1; 01323 maxy = b.y4; 01324 } else { 01325 miny = b.y4; 01326 maxy = b.y1; 01327 } 01328 01329 // Update for the X extrema 01330 { 01331 qreal ax = QT_BEZIER_A(b, x); 01332 qreal bx = QT_BEZIER_B(b, x); 01333 qreal cx = QT_BEZIER_C(b, x); 01334 // specialcase quadratic curves to avoid div by zero 01335 if (qFuzzyCompare(ax, 0)) { 01336 01337 // linear curves are covered by initialization. 01338 if (!qFuzzyCompare(bx, 0)) { 01339 qreal t = -cx / bx; 01340 QT_BEZIER_CHECK_T(b, t); 01341 } 01342 01343 } else { 01344 qreal t1 = (-bx + sqrt(bx * bx - 4 * ax * cx)) / (2 * ax); 01345 QT_BEZIER_CHECK_T(b, t1); 01346 01347 qreal t2 = (-bx - sqrt(bx * bx - 4 * ax * cx)) / (2 * ax); 01348 QT_BEZIER_CHECK_T(b, t2); 01349 } 01350 } 01351 01352 // Update for the Y extrema 01353 { 01354 qreal ay = QT_BEZIER_A(b, y); 01355 qreal by = QT_BEZIER_B(b, y); 01356 qreal cy = QT_BEZIER_C(b, y); 01357 01358 // specialcase quadratic curves to avoid div by zero 01359 if (qFuzzyCompare(ay, 0)) { 01360 01361 // linear curves are covered by initialization. 01362 if (!qFuzzyCompare(by, 0)) { 01363 qreal t = -cy / by; 01364 QT_BEZIER_CHECK_T(b, t); 01365 } 01366 01367 } else { 01368 qreal t1 = (-by + sqrt(by * by - 4 * ay * cy)) / (2 * ay); 01369 QT_BEZIER_CHECK_T(b, t1); 01370 01371 qreal t2 = (-by - sqrt(by * by - 4 * ay * cy)) / (2 * ay); 01372 QT_BEZIER_CHECK_T(b, t2); 01373 } 01374 } 01375 return QRectF(minx, miny, maxx - minx, maxy - miny); 01376 }
| static bool qt_painterpath_check_crossing | ( | const QPainterPath * | path, | |
| const QRectF & | rect | |||
| ) | [static] |
Definition at line 1978 of file qpainterpath.cpp.
References QRectF::bottom(), QPainterPath::CurveToElement, QBezier::fromPoints(), i, QRectF::left(), QPainterPath::LineToElement, QPainterPath::MoveToElement, path, qt_isect_curve_horizontal(), qt_isect_curve_vertical(), qt_painterpath_isect_line_rect(), QRectF::right(), QRectF::top(), QPointF::x(), and QPointF::y().
Referenced by QPainterPath::contains(), and QPainterPath::intersects().
01979 { 01980 QPointF last_pt; 01981 QPointF last_start; 01982 for (int i=0; i<path->elementCount(); ++i) { 01983 const QPainterPath::Element &e = path->elementAt(i); 01984 01985 switch (e.type) { 01986 01987 case QPainterPath::MoveToElement: 01988 if (i > 0 01989 && qFuzzyCompare(last_pt.x(), last_start.y()) 01990 && qFuzzyCompare(last_pt.y(), last_start.y()) 01991 && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(), 01992 last_start.x(), last_start.y(), rect)) 01993 return true; 01994 last_start = last_pt = e; 01995 break; 01996 01997 case QPainterPath::LineToElement: 01998 if (qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(), e.x, e.y, rect)) 01999 return true; 02000 last_pt = e; 02001 break; 02002 02003 case QPainterPath::CurveToElement: 02004 { 02005 QPointF cp2 = path->elementAt(++i); 02006 QPointF ep = path->elementAt(++i); 02007 QBezier bezier = QBezier::fromPoints(last_pt, e, cp2, ep); 02008 if (qt_isect_curve_horizontal(bezier, rect.top(), rect.left(), rect.right()) 02009 || qt_isect_curve_horizontal(bezier, rect.bottom(), rect.left(), rect.right()) 02010 || qt_isect_curve_vertical(bezier, rect.left(), rect.top(), rect.bottom()) 02011 || qt_isect_curve_vertical(bezier, rect.right(), rect.top(), rect.bottom())) 02012 return true; 02013 last_pt = ep; 02014 } 02015 break; 02016 02017 default: 02018 break; 02019 } 02020 } 02021 02022 // implicitly close last subpath 02023 if (last_pt != last_start 02024 && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(), 02025 last_start.x(), last_start.y(), rect)) 02026 return true; 02027 02028 return false; 02029 }
Here is the call graph for this function:

| static void qt_painterpath_isect_curve | ( | const QBezier & | bezier, | |
| const QPointF & | pt, | |||
| int * | winding | |||
| ) | [static] |
Definition at line 1757 of file qpainterpath.cpp.
References QBezier::bounds(), QRectF::height(), QBezier::pt1(), QBezier::pt4(), QBezier::split(), QRectF::width(), QPointF::x(), x, QRectF::y(), QPointF::y(), and y.
Referenced by QPainterPath::contains().
01759 { 01760 qreal y = pt.y(); 01761 qreal x = pt.x(); 01762 QRectF bounds = bezier.bounds(); 01763 01764 // potential intersection, divide and try again... 01765 // Please note that a sideeffect of the bottom exclusion is that 01766 // horizontal lines are dropped, but this is correct according to 01767 // scan conversion rules. 01768 if (y >= bounds.y() && y < bounds.y() + bounds.height()) { 01769 01770 // hit lower limit... This is a rough threshold, but its a 01771 // tradeoff between speed and precision. 01772 const qreal lower_bound = .01; 01773 if (bounds.width() < lower_bound && bounds.height() < lower_bound) { 01774 // We make the assumption here that the curve starts to 01775 // approximate a line after while (i.e. that it doesn't 01776 // change direction drastically during its slope) 01777 if (bezier.pt1().x() <= x) { 01778 (*winding) += (bezier.pt4().y() > bezier.pt1().y() ? 1 : -1); 01779 } 01780 return; 01781 } 01782 01783 // split curve and try again... 01784 QBezier first_half, second_half; 01785 bezier.split(&first_half, &second_half); 01786 qt_painterpath_isect_curve(first_half, pt, winding); 01787 qt_painterpath_isect_curve(second_half, pt, winding); 01788 } 01789 }
Here is the call graph for this function:

| static void qt_painterpath_isect_line | ( | const QPointF & | p1, | |
| const QPointF & | p2, | |||
| const QPointF & | pos, | |||
| int * | winding | |||
| ) | [static] |
Definition at line 1727 of file qpainterpath.cpp.
References QPointF::x(), x, QPointF::y(), and y.
Referenced by QPainterPath::contains().
01729 { 01730 qreal x1 = p1.x(); 01731 qreal y1 = p1.y(); 01732 qreal x2 = p2.x(); 01733 qreal y2 = p2.y(); 01734 qreal y = pos.y(); 01735 01736 int dir = 1; 01737 01738 if (qFuzzyCompare(y1, y2)) { 01739 // ignore horizontal lines according to scan conversion rule 01740 return; 01741 } else if (y2 < y1) { 01742 qreal x_tmp = x2; x2 = x1; x1 = x_tmp; 01743 qreal y_tmp = y2; y2 = y1; y1 = y_tmp; 01744 dir = -1; 01745 } 01746 01747 if (y >= y1 && y < y2) { 01748 qreal x = x1 + ((x2 - x1) / (y2 - y1)) * (y - y1); 01749 01750 // count up the winding number if we're 01751 if (x<=pos.x()) { 01752 (*winding) += dir; 01753 } 01754 } 01755 }
Here is the call graph for this function:

| static bool qt_painterpath_isect_line_rect | ( | qreal | x1, | |
| qreal | y1, | |||
| qreal | x2, | |||
| qreal | y2, | |||
| const QRectF & | rect | |||
| ) | [static] |
Definition at line 1851 of file qpainterpath.cpp.
References QCss::Bottom, QRectF::bottom(), QTextStream::left(), QCss::Left, QRectF::left(), QCss::Right, QTextStream::right(), QRectF::right(), QCss::Top, and QRectF::top().
Referenced by qt_painterpath_check_crossing().
01853 { 01854 qreal left = rect.left(); 01855 qreal right = rect.right(); 01856 qreal top = rect.top(); 01857 qreal bottom = rect.bottom(); 01858 01859 enum { Left, Right, Top, Bottom }; 01860 // clip the lines, after cohen-sutherland, see e.g. http://www.nondot.org/~sabre/graphpro/line6.html 01861 int p1 = ((x1 < left) << Left) 01862 | ((x1 > right) << Right) 01863 | ((y1 < top) << Top) 01864 | ((y1 > bottom) << Bottom); 01865 int p2 = ((x2 < left) << Left) 01866 | ((x2 > right) << Right) 01867 | ((y2 < top) << Top) 01868 | ((y2 > bottom) << Bottom); 01869 01870 if (p1 & p2) 01871 // completely inside 01872 return false; 01873 01874 if (p1 | p2) { 01875 qreal dx = x2 - x1; 01876 qreal dy = y2 - y1; 01877 01878 // clip x coordinates 01879 if (x1 < left) { 01880 y1 += dy/dx * (left - x1); 01881 x1 = left; 01882 } else if (x1 > right) { 01883 y1 -= dy/dx * (x1 - right); 01884 x1 = right; 01885 } 01886 if (x2 < left) { 01887 y2 += dy/dx * (left - x2); 01888 x2 = left; 01889 } else if (x2 > right) { 01890 y2 -= dy/dx * (x2 - right); 01891 x2 = right; 01892 } 01893 01894 p1 = ((y1 < top) << Top) 01895 | ((y1 > bottom) << Bottom); 01896 p2 = ((y2 < top) << Top) 01897 | ((y2 > bottom) << Bottom); 01898 01899 if (p1 & p2) 01900 return false; 01901 01902 // clip y coordinates 01903 if (y1 < top) { 01904 x1 += dx/dy * (top - y1); 01905 y1 = top; 01906 } else if (y1 > bottom) { 01907 x1 -= dx/dy * (y1 - bottom); 01908 y1 = bottom; 01909 } 01910 if (y2 < top) { 01911 x2 += dx/dy * (top - y2); 01912 y2 = top; 01913 } else if (y2 > bottom) { 01914 x2 -= dx/dy * (y2 - bottom); 01915 y2 = bottom; 01916 } 01917 01918 p1 = ((x1 < left) << Left) 01919 | ((x1 > right) << Right); 01920 p2 = ((x2 < left) << Left) 01921 | ((x2 > right) << Right); 01922 01923 if (p1 & p2) 01924 return false; 01925 01926 return true; 01927 } 01928 return false; 01929 }
Here is the call graph for this function:

| void qt_path_stroke_cubic_to | ( | qfixed | c1x, | |
| qfixed | c1y, | |||
| qfixed | c2x, | |||
| qfixed | c2y, | |||
| qfixed | ex, | |||
| qfixed | ey, | |||
| void * | data | |||
| ) |
Definition at line 2278 of file qpainterpath.cpp.
References qt_fixed_to_real.
Referenced by QPainterPathStrokerPrivate::QPainterPathStrokerPrivate().
02282 { 02283 ((QPainterPath *) data)->cubicTo(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y), 02284 qt_fixed_to_real(c2x), qt_fixed_to_real(c2y), 02285 qt_fixed_to_real(ex), qt_fixed_to_real(ey)); 02286 }
Definition at line 2273 of file qpainterpath.cpp.
References qt_fixed_to_real.
Referenced by QPainterPathStrokerPrivate::QPainterPathStrokerPrivate().
02274 { 02275 ((QPainterPath *) data)->lineTo(qt_fixed_to_real(x), qt_fixed_to_real(y)); 02276 }
Definition at line 2268 of file qpainterpath.cpp.
References qt_fixed_to_real.
Referenced by QPainterPathStrokerPrivate::QPainterPathStrokerPrivate().
02269 { 02270 ((QPainterPath *) data)->moveTo(qt_fixed_to_real(x), qt_fixed_to_real(y)); 02271 }
| QPainterPath qt_stroke_dash | ( | const QPainterPath & | path, | |
| qreal * | dashes, | |||
| int | dashCount | |||
| ) |
Definition at line 1606 of file qpainterpath.cpp.
References QRectF::bottom(), QRectF::left(), qMax(), qMin(), QRectF::right(), and QRectF::top().
Referenced by QRegion::intersects(), and QPainterPath::toFillPolygons().
01607 { 01608 return qMax(r1.left(), r2.left()) <= qMin(r1.right(), r2.right()) 01609 && qMax(r1.top(), r2.top()) <= qMin(r1.bottom(), r2.bottom()); 01610 }
Here is the call graph for this function:

1.5.1