blob: 11887652fc36feb5ed3d5bb66ea0f7dc3e9378fc [file] [log] [blame]
#ifndef _WIN32
# include <unistd.h>
#else
# include <windows.h>
# define sleep Sleep
#endif
#include <ctime>
#include <poppler-qt6.h>
#include <poppler-form.h>
#include <QDebug>
#include <QFile>
#include <QImage>
#include <QMutex>
#include <QRandomGenerator>
#include <QThread>
class SillyThread : public QThread
{
Q_OBJECT
public:
explicit SillyThread(Poppler::Document *document, QObject *parent = nullptr);
void run() override;
private:
Poppler::Document *m_document;
std::vector<std::unique_ptr<Poppler::Page>> m_pages;
};
class CrazyThread : public QThread
{
Q_OBJECT
public:
CrazyThread(Poppler::Document *document, QMutex *annotationMutex, QObject *parent = nullptr);
void run() override;
private:
Poppler::Document *m_document;
QMutex *m_annotationMutex;
};
static std::unique_ptr<Poppler::Page> loadPage(Poppler::Document *document, int index)
{
std::unique_ptr<Poppler::Page> page = document->page(index);
if (page == nullptr) {
qDebug() << "!Document::page";
exit(EXIT_FAILURE);
}
return page;
}
static std::unique_ptr<Poppler::Page> loadRandomPage(Poppler::Document *document)
{
return loadPage(document, QRandomGenerator::global()->bounded(document->numPages()));
}
SillyThread::SillyThread(Poppler::Document *document, QObject *parent) : QThread(parent), m_document(document), m_pages()
{
m_pages.reserve(m_document->numPages());
for (int index = 0; index < m_document->numPages(); ++index) {
m_pages.push_back(loadPage(m_document, index));
}
}
void SillyThread::run()
{
forever {
for (std::unique_ptr<Poppler::Page> &page : m_pages) {
QImage image = page->renderToImage();
if (image.isNull()) {
qDebug() << "!Page::renderToImage";
::exit(EXIT_FAILURE);
}
}
}
}
CrazyThread::CrazyThread(Poppler::Document *document, QMutex *annotationMutex, QObject *parent) : QThread(parent), m_document(document), m_annotationMutex(annotationMutex) { }
void CrazyThread::run()
{
typedef std::unique_ptr<Poppler::Page> PagePointer;
forever {
if (QRandomGenerator::global()->bounded(2) == 0) {
qDebug() << "search...";
PagePointer page(loadRandomPage(m_document));
page->search(QStringLiteral("c"), Poppler::Page::IgnoreCase);
page->search(QStringLiteral("r"));
page->search(QStringLiteral("a"), Poppler::Page::IgnoreCase);
page->search(QStringLiteral("z"));
page->search(QStringLiteral("y"), Poppler::Page::IgnoreCase);
}
if (QRandomGenerator::global()->bounded(2) == 0) {
qDebug() << "links...";
PagePointer page(loadRandomPage(m_document));
std::vector<std::unique_ptr<Poppler::Link>> links = page->links();
}
if (QRandomGenerator::global()->bounded(2) == 0) {
qDebug() << "form fields...";
PagePointer page(loadRandomPage(m_document));
std::vector<std::unique_ptr<Poppler::FormField>> formFields = page->formFields();
}
if (QRandomGenerator::global()->bounded(2) == 0) {
qDebug() << "thumbnail...";
PagePointer page(loadRandomPage(m_document));
page->thumbnail();
}
if (QRandomGenerator::global()->bounded(2) == 0) {
qDebug() << "text...";
PagePointer page(loadRandomPage(m_document));
page->text(QRectF(QPointF(), page->pageSizeF()));
}
if (QRandomGenerator::global()->bounded(2) == 0) {
QMutexLocker mutexLocker(m_annotationMutex);
qDebug() << "add annotation...";
PagePointer page(loadRandomPage(m_document));
Poppler::Annotation *annotation = nullptr;
switch (QRandomGenerator::global()->bounded(3)) {
default:
case 0:
annotation = new Poppler::TextAnnotation(QRandomGenerator::global()->bounded(2) == 0 ? Poppler::TextAnnotation::Linked : Poppler::TextAnnotation::InPlace);
break;
case 1:
annotation = new Poppler::HighlightAnnotation();
break;
case 2:
annotation = new Poppler::InkAnnotation();
break;
}
annotation->setBoundary(QRectF(0.0, 0.0, 0.5, 0.5));
annotation->setContents(QStringLiteral("crazy"));
page->addAnnotation(annotation);
delete annotation;
}
if (QRandomGenerator::global()->bounded(2) == 0) {
QMutexLocker mutexLocker(m_annotationMutex);
for (int index = 0; index < m_document->numPages(); ++index) {
PagePointer page(loadPage(m_document, index));
std::vector<std::unique_ptr<Poppler::Annotation>> annotations = page->annotations();
if (!annotations.empty()) {
qDebug() << "modify annotation...";
// size is now a qsizetype which confuses bounded(), pretend we will never have that many annotations anyway
const quint32 annotationsSize = annotations.size();
annotations.at(QRandomGenerator::global()->bounded(annotationsSize))->setBoundary(QRectF(0.5, 0.5, 0.25, 0.25));
annotations.at(QRandomGenerator::global()->bounded(annotationsSize))->setAuthor(QStringLiteral("foo"));
annotations.at(QRandomGenerator::global()->bounded(annotationsSize))->setContents(QStringLiteral("bar"));
annotations.at(QRandomGenerator::global()->bounded(annotationsSize))->setCreationDate(QDateTime::currentDateTime());
annotations.at(QRandomGenerator::global()->bounded(annotationsSize))->setModificationDate(QDateTime::currentDateTime());
}
if (!annotations.empty()) {
break;
}
}
}
if (QRandomGenerator::global()->bounded(2) == 0) {
QMutexLocker mutexLocker(m_annotationMutex);
for (int index = 0; index < m_document->numPages(); ++index) {
PagePointer page(loadPage(m_document, index));
std::vector<std::unique_ptr<Poppler::Annotation>> annotations = page->annotations();
if (!annotations.empty()) {
qDebug() << "remove annotation...";
// size is now a qsizetype which confuses bounded(), pretend we will never have that many annotations anyway
const quint32 annotationsSize = annotations.size();
page->removeAnnotation(annotations[QRandomGenerator::global()->bounded(annotationsSize)].get());
annotations.erase(annotations.begin() + QRandomGenerator::global()->bounded(annotationsSize));
}
if (!annotations.empty()) {
break;
}
}
}
if (QRandomGenerator::global()->bounded(2) == 0) {
qDebug() << "fonts...";
m_document->fonts();
}
}
}
int main(int argc, char **argv)
{
if (argc < 5) {
qDebug() << "usage: stress-threads-qt duration sillyCount crazyCount file(s)";
return EXIT_FAILURE;
}
const int duration = atoi(argv[1]);
const int sillyCount = atoi(argv[2]);
const int crazyCount = atoi(argv[3]);
for (int argi = 4; argi < argc; ++argi) {
const QString file = QFile::decodeName(argv[argi]);
std::unique_ptr<Poppler::Document> document = Poppler::Document::load(file);
if (document == nullptr) {
qDebug() << "Could not load" << file;
continue;
}
if (document->isLocked()) {
qDebug() << file << "is locked";
continue;
}
for (int i = 0; i < sillyCount; ++i) {
(new SillyThread(document.get()))->start();
}
QMutex *annotationMutex = new QMutex();
for (int i = 0; i < crazyCount; ++i) {
(new CrazyThread(document.get(), annotationMutex))->start();
}
}
sleep(duration);
return EXIT_SUCCESS;
}
#include "stress-threads-qt6.moc"