1
2 #ifndef _WIN32
3 # include <unistd.h>
4 #else
5 # include <windows.h>
6 # define sleep Sleep
7 #endif
8 #include <ctime>
9
10 #include <poppler-qt5.h>
11 #include <poppler-form.h>
12
13 #include <QtCore/QDebug>
14 #include <QtCore/QFile>
15 #include <QtCore/QMutex>
16 #include <QtCore/QThread>
17 #include <QtGui/QImage>
18
19 class SillyThread : public QThread
20 {
21 Q_OBJECT
22 public:
23 explicit SillyThread(Poppler::Document *document, QObject *parent = nullptr);
24
25 void run() override;
26
27 private:
28 Poppler::Document *m_document;
29 QVector<Poppler::Page *> m_pages;
30 };
31
32 class CrazyThread : public QThread
33 {
34 Q_OBJECT
35 public:
36 CrazyThread(uint seed, Poppler::Document *document, QMutex *annotationMutex, QObject *parent = nullptr);
37
38 void run() override;
39
40 private:
41 uint m_seed;
42 Poppler::Document *m_document;
43 QMutex *m_annotationMutex;
44 };
45
loadPage(Poppler::Document * document,int index)46 static Poppler::Page *loadPage(Poppler::Document *document, int index)
47 {
48 Poppler::Page *page = document->page(index);
49
50 if (page == nullptr) {
51 qDebug() << "!Document::page";
52
53 exit(EXIT_FAILURE);
54 }
55
56 return page;
57 }
58
loadRandomPage(Poppler::Document * document)59 static Poppler::Page *loadRandomPage(Poppler::Document *document)
60 {
61 return loadPage(document, qrand() % document->numPages());
62 }
63
SillyThread(Poppler::Document * document,QObject * parent)64 SillyThread::SillyThread(Poppler::Document *document, QObject *parent) : QThread(parent), m_document(document), m_pages()
65 {
66 m_pages.reserve(m_document->numPages());
67
68 for (int index = 0; index < m_document->numPages(); ++index) {
69 m_pages.append(loadPage(m_document, index));
70 }
71 }
72
run()73 void SillyThread::run()
74 {
75 forever {
76 foreach (Poppler::Page *page, m_pages) {
77 QImage image = page->renderToImage();
78
79 if (image.isNull()) {
80 qDebug() << "!Page::renderToImage";
81
82 ::exit(EXIT_FAILURE);
83 }
84 }
85 }
86 }
87
CrazyThread(uint seed,Poppler::Document * document,QMutex * annotationMutex,QObject * parent)88 CrazyThread::CrazyThread(uint seed, Poppler::Document *document, QMutex *annotationMutex, QObject *parent) : QThread(parent), m_seed(seed), m_document(document), m_annotationMutex(annotationMutex) { }
89
run()90 void CrazyThread::run()
91 {
92 typedef QScopedPointer<Poppler::Page> PagePointer;
93
94 qsrand(m_seed);
95
96 forever {
97 if (qrand() % 2 == 0) {
98 qDebug() << "search...";
99
100 PagePointer page(loadRandomPage(m_document));
101
102 page->search(QStringLiteral("c"), Poppler::Page::IgnoreCase);
103 page->search(QStringLiteral("r"));
104 page->search(QStringLiteral("a"), Poppler::Page::IgnoreCase);
105 page->search(QStringLiteral("z"));
106 page->search(QStringLiteral("y"), Poppler::Page::IgnoreCase);
107 }
108
109 if (qrand() % 2 == 0) {
110 qDebug() << "links...";
111
112 PagePointer page(loadRandomPage(m_document));
113
114 QList<Poppler::Link *> links = page->links();
115
116 qDeleteAll(links);
117 }
118
119 if (qrand() % 2 == 0) {
120 qDebug() << "form fields...";
121
122 PagePointer page(loadRandomPage(m_document));
123
124 QList<Poppler::FormField *> formFields = page->formFields();
125
126 qDeleteAll(formFields);
127 }
128
129 if (qrand() % 2 == 0) {
130 qDebug() << "thumbnail...";
131
132 PagePointer page(loadRandomPage(m_document));
133
134 page->thumbnail();
135 }
136
137 if (qrand() % 2 == 0) {
138 qDebug() << "text...";
139
140 PagePointer page(loadRandomPage(m_document));
141
142 page->text(QRectF(QPointF(), page->pageSizeF()));
143 }
144
145 if (qrand() % 2 == 0) {
146 QMutexLocker mutexLocker(m_annotationMutex);
147
148 qDebug() << "add annotation...";
149
150 PagePointer page(loadRandomPage(m_document));
151
152 Poppler::Annotation *annotation = nullptr;
153
154 switch (qrand() % 3) {
155 default:
156 case 0:
157 annotation = new Poppler::TextAnnotation(qrand() % 2 == 0 ? Poppler::TextAnnotation::Linked : Poppler::TextAnnotation::InPlace);
158 break;
159 case 1:
160 annotation = new Poppler::HighlightAnnotation();
161 break;
162 case 2:
163 annotation = new Poppler::InkAnnotation();
164 break;
165 }
166
167 annotation->setBoundary(QRectF(0.0, 0.0, 0.5, 0.5));
168 annotation->setContents(QStringLiteral("crazy"));
169
170 page->addAnnotation(annotation);
171
172 delete annotation;
173 }
174
175 if (qrand() % 2 == 0) {
176 QMutexLocker mutexLocker(m_annotationMutex);
177
178 for (int index = 0; index < m_document->numPages(); ++index) {
179 PagePointer page(loadPage(m_document, index));
180
181 QList<Poppler::Annotation *> annotations = page->annotations();
182
183 if (!annotations.isEmpty()) {
184 qDebug() << "modify annotation...";
185
186 annotations.at(qrand() % annotations.size())->setBoundary(QRectF(0.5, 0.5, 0.25, 0.25));
187 annotations.at(qrand() % annotations.size())->setAuthor(QStringLiteral("foo"));
188 annotations.at(qrand() % annotations.size())->setContents(QStringLiteral("bar"));
189 annotations.at(qrand() % annotations.size())->setCreationDate(QDateTime::currentDateTime());
190 annotations.at(qrand() % annotations.size())->setModificationDate(QDateTime::currentDateTime());
191 }
192
193 qDeleteAll(annotations);
194
195 if (!annotations.isEmpty()) {
196 break;
197 }
198 }
199 }
200
201 if (qrand() % 2 == 0) {
202 QMutexLocker mutexLocker(m_annotationMutex);
203
204 for (int index = 0; index < m_document->numPages(); ++index) {
205 PagePointer page(loadPage(m_document, index));
206
207 QList<Poppler::Annotation *> annotations = page->annotations();
208
209 if (!annotations.isEmpty()) {
210 qDebug() << "remove annotation...";
211
212 page->removeAnnotation(annotations.takeAt(qrand() % annotations.size()));
213 }
214
215 qDeleteAll(annotations);
216
217 if (!annotations.isEmpty()) {
218 break;
219 }
220 }
221 }
222
223 if (qrand() % 2 == 0) {
224 qDebug() << "fonts...";
225
226 m_document->fonts();
227 }
228 }
229 }
230
main(int argc,char ** argv)231 int main(int argc, char **argv)
232 {
233 if (argc < 5) {
234 qDebug() << "usage: stress-threads-qt duration sillyCount crazyCount file(s)";
235
236 return EXIT_FAILURE;
237 }
238
239 const int duration = atoi(argv[1]);
240 const int sillyCount = atoi(argv[2]);
241 const int crazyCount = atoi(argv[3]);
242
243 qsrand(time(nullptr));
244
245 for (int argi = 4; argi < argc; ++argi) {
246 const QString file = QFile::decodeName(argv[argi]);
247 Poppler::Document *document = Poppler::Document::load(file);
248
249 if (document == nullptr) {
250 qDebug() << "Could not load" << file;
251 continue;
252 }
253
254 if (document->isLocked()) {
255 qDebug() << file << "is locked";
256 continue;
257 }
258
259 for (int i = 0; i < sillyCount; ++i) {
260 (new SillyThread(document))->start();
261 }
262
263 QMutex *annotationMutex = new QMutex();
264
265 for (int i = 0; i < crazyCount; ++i) {
266 (new CrazyThread(qrand(), document, annotationMutex))->start();
267 }
268 }
269
270 sleep(duration);
271
272 return EXIT_SUCCESS;
273 }
274
275 #include "stress-threads-qt5.moc"
276