1 /****************************************************************************
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Copyright (C) 2016 Ivailo Monev
6 ** This file is part of the FOO module of the Katie Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser
12 ** General Public License version 2.1 as published by the Free Software
13 ** Foundation and appearing in the file LICENSE.LGPL included in the
14 ** packaging of this file. Please review the following information to
15 ** ensure the GNU Lesser General Public License version 2.1 requirements
16 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
20 ****************************************************************************/
22 #ifndef BENCHMARKTESTS_H
23 #define BENCHMARKTESTS_H
25 #include <QApplication>
26 #include <QTextDocument>
27 #include <QDesktopWidget>
28 #include <QTextLayout>
29 #include <QFontMetrics>
35 virtual ~Benchmark() {}
37 Benchmark(const QSize &size)
40 for (int i=0; i<16; ++i) {
41 m_colors[i] = QColor::fromRgbF((rand() % 4) / 3.0,
48 virtual void draw(QPainter *p, const QRect &rect, int iteration) = 0;
49 virtual QString name() const = 0;
51 inline const QSize &size() const
55 virtual void begin(QPainter *, int iterations = 1) { Q_UNUSED(iterations); }
56 virtual void end(QPainter *) { }
58 inline const QColor &randomColor(int i) { return m_colors[i % 16]; }
65 class PaintingRectAdjuster
68 PaintingRectAdjuster()
71 m_screen_filled(false)
75 const QRect &newPaintingRect() {
76 m_rect.translate(m_rect.width(), 0);
78 if (m_rect.right() > m_bounds.width()) {
79 m_rect.moveLeft(m_bounds.left());
80 m_rect.translate(0,m_rect.height());
81 if (m_rect.bottom() > m_bounds.height()) {
82 m_screen_filled = true;
83 m_rect.moveTo(m_bounds.topLeft());
89 inline bool isScreenFilled() const
90 { return m_screen_filled; }
92 void reset(const QRect &bounds)
95 m_rect.moveTo(m_bounds.topLeft());
96 m_rect = QRect(m_bounds.topLeft(),m_benchmark->size());
97 m_rect.translate(-m_rect.width(),0);
98 m_screen_filled = false;
101 inline void setNewBenchmark( Benchmark *benchmark )
103 m_benchmark = benchmark;
107 Benchmark *m_benchmark;
110 bool m_screen_filled;
113 class FillRectBenchmark : public Benchmark
116 FillRectBenchmark(int size)
117 : Benchmark(QSize(size, size))
121 virtual void draw(QPainter *p, const QRect &rect, int iterationCount) {
122 p->fillRect(rect, randomColor(iterationCount));
125 virtual QString name() const {
126 return QString::fromLatin1("fillRect(%1)").arg(m_size.width());
130 class ImageFillRectBenchmark : public Benchmark
133 ImageFillRectBenchmark(int size)
134 : Benchmark(QSize(size, size))
136 int s = rand() % 24 + 8;
137 m_content = QImage(s, s, QImage::Format_ARGB32_Premultiplied);
138 QPainter p(&m_content);
139 p.fillRect(0, 0, s, s, Qt::white);
140 p.fillRect(s/2, 0, s/2, s/2, Qt::gray);
141 p.fillRect(0, s/2, s/2, s/2, Qt::gray);
144 m_brush = QBrush(m_content);
147 virtual void draw(QPainter *p, const QRect &rect, int) {
148 p->fillRect(rect, m_brush);
151 virtual QString name() const {
152 return QString::fromLatin1("fillRect with image(%1)").arg(m_size.width());
161 class DrawRectBenchmark : public Benchmark
164 DrawRectBenchmark(int size)
165 : Benchmark(QSize(size, size))
169 virtual void begin(QPainter *p, int) {
170 p->setPen(Qt::NoPen);
171 p->setBrush(randomColor(m_size.width()));
175 virtual void draw(QPainter *p, const QRect &rect, int) {
179 virtual QString name() const {
180 return QString::fromLatin1("drawRect(%1)").arg(m_size.width());
185 class DrawRectWithBrushChangeBenchmark : public Benchmark
188 DrawRectWithBrushChangeBenchmark(int size)
189 : Benchmark(QSize(size, size))
193 virtual void begin(QPainter *p, int) {
194 p->setPen(Qt::NoPen);
198 virtual void draw(QPainter *p, const QRect &rect, int i) {
199 p->setBrush(randomColor(i));
203 virtual QString name() const {
204 return QString::fromLatin1("drawRect with brushchange(%1)").arg(m_size.width());
208 class RoundRectBenchmark : public Benchmark
211 RoundRectBenchmark(int size)
212 : Benchmark(QSize(size, size))
214 m_roundness = size / 4.;
217 virtual void begin(QPainter *p, int) {
218 p->setPen(Qt::NoPen);
219 p->setBrush(Qt::red);
222 virtual void draw(QPainter *p, const QRect &rect, int) {
223 p->drawRoundedRect(rect, m_roundness, m_roundness);
226 virtual QString name() const {
227 return QString::fromLatin1("drawRoundedRect(%1)").arg(m_size.width());
234 class ArcsBenchmark : public Benchmark
244 CircleShape = 0x0080,
249 ArcsBenchmark(int size, uint type)
250 : Benchmark(QSize(size, size)),
255 virtual void begin(QPainter *p, int) {
256 if (m_type & Stroked)
257 p->setPen(Qt::black);
259 p->setPen(Qt::NoPen);
262 p->setBrush(Qt::red);
264 p->setBrush(Qt::NoBrush);
267 virtual void draw(QPainter *p, const QRect &rect, int) {
268 switch (m_type & Shapes) {
270 p->drawArc(rect, 45*16, 120*16);
273 p->drawChord(rect, 45*16, 120*16);
276 p->drawPie(rect, 45*16, 120*16);
279 p->drawEllipse(rect);
284 virtual QString name() const {
287 if ((m_type & (Stroked|Filled)) == (Stroked|Filled)) {
288 fillStroke = QLatin1String("Fill & Outline");
289 } else if (m_type & Stroked) {
290 fillStroke = QLatin1String("Outline");
291 } else if (m_type & Filled) {
292 fillStroke = QLatin1String("Fill");
296 if (m_type & PieShape) shape = QLatin1String("drawPie");
297 else if (m_type & ChordShape) shape = QLatin1String("drawChord");
298 else if (m_type & ArcShape) shape = QLatin1String("drawArc");
299 else if (m_type & CircleShape) shape = QLatin1String("drawEllipse");
301 return QString::fromLatin1("%1(%2) %3").arg(shape).arg(m_size.width()).arg(fillStroke);
308 class DrawScaledImage : public Benchmark
311 DrawScaledImage(const QImage &image, qreal scale, bool asPixmap)
312 : Benchmark(QSize(image.width(), image.height())),
314 m_type(asPixmap ? QLatin1String("Pixmap") : QLatin1String("Image")),
316 m_as_pixmap(asPixmap)
318 m_pixmap = QPixmap::fromImage(m_image);
320 DrawScaledImage(const QString& type, const QPixmap &pixmap, qreal scale)
321 : Benchmark(QSize(pixmap.width(), pixmap.height())),
329 virtual void begin(QPainter *p, int) {
330 p->scale(m_scale, m_scale);
333 virtual void draw(QPainter *p, const QRect &rect, int) {
335 p->drawPixmap(rect.topLeft(), m_pixmap);
337 p->drawImage(rect.topLeft(), m_image);
340 virtual QString name() const {
341 return QString::fromLatin1("draw%4(%1) at scale=%2, depth=%3")
344 .arg(m_as_pixmap ? m_pixmap.depth() : m_image.depth())
356 class DrawTransformedImage : public Benchmark
359 DrawTransformedImage(const QImage &image, bool asPixmap)
360 : Benchmark(QSize(image.width(), image.height())),
362 m_type(asPixmap ? QLatin1String("Pixmap") : QLatin1String("Image")),
363 m_as_pixmap(asPixmap)
365 m_pixmap = QPixmap::fromImage(m_image);
367 DrawTransformedImage(const QString& type, const QPixmap &pixmap)
368 : Benchmark(QSize(pixmap.width(), pixmap.height())),
375 virtual void draw(QPainter *p, const QRect &rect, int) {
376 QTransform oldTransform = p->transform();
377 p->translate(0.5 * rect.width() + rect.left(), 0.5 * rect.height() + rect.top());
381 p->drawPixmap(-0.5 * rect.width(), -0.5 * rect.height(), m_pixmap);
383 p->drawImage(-0.5 * rect.width(), -0.5 * rect.height(), m_image);
384 p->setTransform(oldTransform);
387 virtual QString name() const {
388 return QString::fromLatin1("draw%3(%1) w/transform, depth=%2")
390 .arg(m_as_pixmap ? m_pixmap.depth() : m_image.depth())
402 class DrawImage : public Benchmark
405 DrawImage(const QImage &image, bool asPixmap)
406 : Benchmark(QSize(image.width(), image.height())),
408 m_type(asPixmap ? QLatin1String("Pixmap") : QLatin1String("Image")),
409 m_as_pixmap(asPixmap)
411 m_pixmap = QPixmap::fromImage(image);
413 DrawImage(const QString& type, const QPixmap &pixmap)
414 : Benchmark(QSize(pixmap.width(), pixmap.height())),
421 virtual void draw(QPainter *p, const QRect &rect, int) {
423 p->drawPixmap(rect.topLeft(), m_pixmap);
425 p->drawImage(rect.topLeft(), m_image);
428 virtual QString name() const {
429 return QString::fromLatin1("draw%2(%1), depth=%3")
432 .arg(m_as_pixmap ? m_pixmap.depth() : m_image.depth());
443 class DrawText : public Benchmark
454 DrawText(const QString &text, Mode mode)
455 : Benchmark(QSize()), m_mode(mode), m_text(text), m_document(text), m_layout(text)
459 virtual void begin(QPainter *p, int iterations) {
462 QRect m_bounds = QRect(0,0,p->device()->width(), p->device()->height());
465 m_size = (p->boundingRect(m_bounds, 0, m_text)).size();
466 // m_rect = m_rect.translated(-m_rect.topLeft());
469 m_size = QSize(m_document.size().toSize());
472 for (int i=0; i<4; ++i) {
473 m_size = (p->boundingRect(m_bounds, 0, m_text)).size();
474 QPixmap pixmap = QPixmap(m_size);
475 pixmap.fill(Qt::transparent);
478 p.drawText(pixmap.rect(), m_text);
480 m_pixmaps.append(pixmap);
484 QRect r = p->boundingRect(m_bounds, 0, m_text);
485 QStringList lines = m_text.split(QLatin1Char('\n'));
487 int leading = p->fontMetrics().leading();
488 m_layout.beginLayout();
489 for (int i=0; i<lines.size(); ++i) {
490 QTextLine textLine = m_layout.createLine();
491 if (textLine.isValid()) {
492 textLine.setLineWidth(r.width());
493 textLine.setPosition(QPointF(0, height));
494 height += leading + textLine.height();
497 m_layout.endLayout();
498 m_layout.setCacheEnabled(true);
499 m_size = m_layout.boundingRect().toRect().size();
503 case PainterQPointMode: {
504 QFontMetrics fm(p->font());
505 m_size = QSize(fm.width(m_text, m_text.length()), fm.height());
512 virtual void draw(QPainter *p, const QRect &rect, int)
516 p->drawText(rect, 0, m_text);
518 case PainterQPointMode:
519 p->drawText(rect.topLeft(), m_text);
522 p->drawPixmap(rect.topLeft(), m_pixmaps.at(m_currentPixmap));
523 m_currentPixmap = (m_currentPixmap + 1) % m_pixmaps.size();
526 p->translate(rect.topLeft());
527 m_document.drawContents(p);
528 p->translate(-rect.topLeft());
531 m_layout.draw(p, rect.topLeft());
536 virtual QString name() const {
537 int letters = m_text.length();
538 int lines = m_text.count(QLatin1Char('\n'));
543 case PainterMode: type = QLatin1String("drawText(rect)"); break;
544 case PainterQPointMode: type = QLatin1String("drawText(point)"); break;
545 case LayoutMode: type = QLatin1String("layout.draw()"); break;
546 case DocumentMode: type = QLatin1String("doc.drawContents()"); break;
547 case PixmapMode: type = QLatin1String("pixmap cached text"); break;
550 return QString::fromLatin1("%3, len=%1, lines=%2")
559 QTextDocument m_document;
560 QTextLayout m_layout;
562 QList<QPixmap> m_pixmaps;
569 class ClippedDrawRectBenchmark : public Benchmark
579 EllipseRegionThenRectClip,
580 EllipsePathThenRectClip
583 ClippedDrawRectBenchmark(int size, ClipType type)
584 : Benchmark(QSize(size, size)), m_type(type)
588 virtual void begin(QPainter *p, int) {
589 QRect m_bounds = QRect(0,0,p->device()->width(), p->device()->height());
590 p->setPen(Qt::NoPen);
591 p->setBrush(Qt::red);
595 p->setClipRect(m_bounds.adjusted(1, 1, -1, -1));
597 case TwoRectRegionClip:
598 p->setClipRegion(QRegion(m_bounds.adjusted(0, 0, -1, -1))
599 | QRegion(m_bounds.adjusted(1, 1, 0, 0)));
601 case EllipseRegionClip:
602 p->setClipRegion(QRegion(m_bounds, QRegion::Ellipse));
604 case TwoRectPathClip:
607 path.addRect(m_bounds.adjusted(0, 0, -1, -1));
608 path.addRect(m_bounds.adjusted(1, 1, 0, 0));
609 path.setFillRule(Qt::WindingFill);
610 p->setClipPath(path);
613 case EllipsePathClip:
616 path.addEllipse(m_bounds);
617 p->setClipPath(path);
620 case AAEllipsePathClip:
623 path.addEllipse(m_bounds);
624 p->setRenderHint(QPainter::Antialiasing);
625 p->setClipPath(path);
626 p->setRenderHint(QPainter::Antialiasing, false);
629 case EllipseRegionThenRectClip:
630 p->setClipRegion(QRegion(m_bounds, QRegion::Ellipse));
631 p->setClipRegion(QRegion(m_bounds.width() / 4,
632 m_bounds.height() / 4,
633 m_bounds.width() / 2,
634 m_bounds.height() / 2), Qt::IntersectClip);
636 case EllipsePathThenRectClip:
639 path.addEllipse(m_bounds);
640 p->setClipPath(path);
641 p->setClipRegion(QRegion(m_bounds.width() / 4,
642 m_bounds.height() / 4,
643 m_bounds.width() / 2,
644 m_bounds.height() / 2), Qt::IntersectClip);
650 virtual void draw(QPainter *p, const QRect &rect, int) {
654 virtual QString name() const {
658 namedType = QLatin1String("rect");
660 case TwoRectRegionClip:
661 namedType = QLatin1String("two-rect-region");
663 case EllipseRegionClip:
664 namedType = QLatin1String("ellipse-region");
666 case TwoRectPathClip:
667 namedType = QLatin1String("two-rect-path");
669 case EllipsePathClip:
670 namedType = QLatin1String("ellipse-path");
672 case AAEllipsePathClip:
673 namedType = QLatin1String("aa-ellipse-path");
675 case EllipseRegionThenRectClip:
676 namedType = QLatin1String("ellipseregion&rect");
678 case EllipsePathThenRectClip:
679 namedType = QLatin1String("ellipsepath&rect");
682 return QString::fromLatin1("%1-clipped-drawRect(%2)").arg(namedType).arg(m_size.width());
688 class LinesBenchmark : public Benchmark
700 LinesBenchmark(int length, LineType type)
701 : Benchmark(QSize(qAbs(length), qAbs(length))),
708 virtual void draw(QPainter *p, const QRect &rect, int) {
710 case Horizontal_Integer:
711 p->drawLine(QLine(rect.x(), rect.y(), rect.x() + m_length, rect.y()));
713 case Diagonal_Integer:
714 p->drawLine(QLine(rect.x(), rect.y(), rect.x() + m_length, rect.y() + m_length));
716 case Vertical_Integer:
717 p->drawLine(QLine(rect.x() + 4, rect.y(), rect.x() + 4, rect.y() + m_length));
719 case Horizontal_Float:
720 p->drawLine(QLineF(rect.x(), rect.y(), rect.x() + m_length, rect.y()));
723 p->drawLine(QLineF(rect.x(), rect.y(), rect.x() + m_length, rect.y() + m_length));
726 p->drawLine(QLineF(rect.x() + 4, rect.y(), rect.x() + 4, rect.y() + m_length));
731 virtual QString name() const {
732 const char *names[] = {
740 return QString::fromLatin1("drawLine(size=%1,type=%2)").arg(m_length).arg(names[m_type]);
747 #endif // BENCHMARKTESTS_H