File indexing completed on 2024-04-28 04:32:43
0001 /* 0002 SPDX-FileCopyrightText: 2005 Piotr Szymanski <niedakh@gmail.com> 0003 SPDX-FileCopyrightText: 2008 Albert Astals Cid <aacid@kde.org> 0004 0005 Work sponsored by the LiMux project of the city of Munich: 0006 SPDX-FileCopyrightText: 2017 Klarälvdalens Datakonsult AB a KDAB Group company <info@kdab.com> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "config-okular.h" 0012 0013 #include "generator.h" 0014 #include "generator_p.h" 0015 #include "observer.h" 0016 0017 #include <QApplication> 0018 #include <QEventLoop> 0019 #include <QPrinter> 0020 0021 #include <KLocalizedString> 0022 #include <QDebug> 0023 #include <QIcon> 0024 #include <QMimeDatabase> 0025 #include <QTimer> 0026 0027 #if HAVE_KWALLET 0028 #include <KWallet> 0029 #endif 0030 0031 #include "document_p.h" 0032 #include "page.h" 0033 #include "page_p.h" 0034 #include "textpage.h" 0035 #include "utils.h" 0036 0037 using namespace Okular; 0038 0039 GeneratorPrivate::GeneratorPrivate() 0040 : m_document(nullptr) 0041 , mPixmapGenerationThread(nullptr) 0042 , mTextPageGenerationThread(nullptr) 0043 , mPixmapReady(true) 0044 , mTextPageReady(true) 0045 , m_closing(false) 0046 , m_closingLoop(nullptr) 0047 , m_dpi(72.0, 72.0) 0048 { 0049 qRegisterMetaType<Okular::Page *>(); 0050 } 0051 0052 GeneratorPrivate::~GeneratorPrivate() 0053 { 0054 if (mPixmapGenerationThread) { 0055 mPixmapGenerationThread->wait(); 0056 } 0057 0058 delete mPixmapGenerationThread; 0059 0060 if (mTextPageGenerationThread) { 0061 mTextPageGenerationThread->wait(); 0062 } 0063 0064 delete mTextPageGenerationThread; 0065 } 0066 0067 PixmapGenerationThread *GeneratorPrivate::pixmapGenerationThread() 0068 { 0069 if (mPixmapGenerationThread) { 0070 return mPixmapGenerationThread; 0071 } 0072 0073 Q_Q(Generator); 0074 mPixmapGenerationThread = new PixmapGenerationThread(q); 0075 QObject::connect( 0076 mPixmapGenerationThread, &PixmapGenerationThread::finished, q, [this] { pixmapGenerationFinished(); }, Qt::QueuedConnection); 0077 0078 return mPixmapGenerationThread; 0079 } 0080 0081 TextPageGenerationThread *GeneratorPrivate::textPageGenerationThread() 0082 { 0083 if (mTextPageGenerationThread) { 0084 return mTextPageGenerationThread; 0085 } 0086 0087 Q_Q(Generator); 0088 mTextPageGenerationThread = new TextPageGenerationThread(q); 0089 QObject::connect( 0090 mTextPageGenerationThread, &TextPageGenerationThread::finished, q, [this] { textpageGenerationFinished(); }, Qt::QueuedConnection); 0091 0092 return mTextPageGenerationThread; 0093 } 0094 0095 void GeneratorPrivate::pixmapGenerationFinished() 0096 { 0097 Q_Q(Generator); 0098 PixmapRequest *request = mPixmapGenerationThread->request(); 0099 const QImage &img = mPixmapGenerationThread->image(); 0100 mPixmapGenerationThread->endGeneration(); 0101 0102 QMutexLocker locker(threadsLock()); 0103 0104 if (m_closing) { 0105 mPixmapReady = true; 0106 delete request; 0107 if (mTextPageReady) { 0108 locker.unlock(); 0109 m_closingLoop->quit(); 0110 } 0111 return; 0112 } 0113 0114 if (!request->shouldAbortRender()) { 0115 request->page()->setPixmap(request->observer(), new QPixmap(QPixmap::fromImage(img)), request->normalizedRect()); 0116 const int pageNumber = request->page()->number(); 0117 0118 if (mPixmapGenerationThread->calcBoundingBox()) { 0119 q->updatePageBoundingBox(pageNumber, mPixmapGenerationThread->boundingBox()); 0120 } 0121 } else { 0122 // Cancel the text page generation too if it's still running 0123 if (mTextPageGenerationThread && mTextPageGenerationThread->isRunning()) { 0124 mTextPageGenerationThread->abortExtraction(); 0125 mTextPageGenerationThread->wait(); 0126 } 0127 } 0128 0129 mPixmapReady = true; 0130 q->signalPixmapRequestDone(request); 0131 } 0132 0133 void GeneratorPrivate::textpageGenerationFinished() 0134 { 0135 Q_Q(Generator); 0136 Page *page = mTextPageGenerationThread->page(); 0137 mTextPageGenerationThread->endGeneration(); 0138 0139 QMutexLocker locker(threadsLock()); 0140 mTextPageReady = true; 0141 0142 if (m_closing) { 0143 delete mTextPageGenerationThread->textPage(); 0144 if (mPixmapReady) { 0145 locker.unlock(); 0146 m_closingLoop->quit(); 0147 } 0148 return; 0149 } 0150 0151 if (mTextPageGenerationThread->textPage()) { 0152 TextPage *tp = mTextPageGenerationThread->textPage(); 0153 page->setTextPage(tp); 0154 q->signalTextGenerationDone(page, tp); 0155 } 0156 } 0157 0158 QMutex *GeneratorPrivate::threadsLock() 0159 { 0160 return &m_threadsMutex; 0161 } 0162 0163 QVariant GeneratorPrivate::metaData(const QString &, const QVariant &) const 0164 { 0165 return QVariant(); 0166 } 0167 0168 QImage GeneratorPrivate::image(PixmapRequest *) 0169 { 0170 return QImage(); 0171 } 0172 0173 Generator::Generator(QObject *parent, const QVariantList &args) 0174 : Generator(*new GeneratorPrivate(), parent, args) 0175 { 0176 // the delegated constructor does it all 0177 } 0178 0179 Generator::Generator(GeneratorPrivate &dd, QObject *parent, const QVariantList &args) 0180 : QObject(parent) 0181 , d_ptr(&dd) 0182 { 0183 d_ptr->q_ptr = this; 0184 Q_UNUSED(args) 0185 } 0186 0187 Generator::~Generator() 0188 { 0189 delete d_ptr; 0190 } 0191 0192 bool Generator::loadDocument(const QString &fileName, QVector<Page *> &pagesVector) 0193 { 0194 Q_UNUSED(fileName); 0195 Q_UNUSED(pagesVector); 0196 0197 return false; 0198 } 0199 0200 bool Generator::loadDocumentFromData(const QByteArray &, QVector<Page *> &) 0201 { 0202 return false; 0203 } 0204 0205 Document::OpenResult Generator::loadDocumentWithPassword(const QString &fileName, QVector<Page *> &pagesVector, const QString &) 0206 { 0207 return loadDocument(fileName, pagesVector) ? Document::OpenSuccess : Document::OpenError; 0208 } 0209 0210 Document::OpenResult Generator::loadDocumentFromDataWithPassword(const QByteArray &fileData, QVector<Page *> &pagesVector, const QString &) 0211 { 0212 return loadDocumentFromData(fileData, pagesVector) ? Document::OpenSuccess : Document::OpenError; 0213 } 0214 0215 Generator::SwapBackingFileResult Generator::swapBackingFile(QString const & /*newFileName */, QVector<Okular::Page *> & /*newPagesVector*/) 0216 { 0217 return SwapBackingFileError; 0218 } 0219 0220 bool Generator::closeDocument() 0221 { 0222 Q_D(Generator); 0223 0224 d->m_closing = true; 0225 0226 d->threadsLock()->lock(); 0227 if (!(d->mPixmapReady && d->mTextPageReady)) { 0228 QEventLoop loop; 0229 d->m_closingLoop = &loop; 0230 0231 d->threadsLock()->unlock(); 0232 0233 loop.exec(); 0234 0235 d->m_closingLoop = nullptr; 0236 } else { 0237 d->threadsLock()->unlock(); 0238 } 0239 0240 bool ret = doCloseDocument(); 0241 0242 d->m_closing = false; 0243 0244 return ret; 0245 } 0246 0247 bool Generator::canGeneratePixmap() const 0248 { 0249 Q_D(const Generator); 0250 return d->mPixmapReady; 0251 } 0252 0253 bool Generator::canSign() const 0254 { 0255 return false; 0256 } 0257 0258 bool Generator::sign(const NewSignatureData &, const QString &) 0259 { 0260 return false; 0261 } 0262 0263 CertificateStore *Generator::certificateStore() const 0264 { 0265 return nullptr; 0266 } 0267 0268 void Generator::generatePixmap(PixmapRequest *request) 0269 { 0270 Q_D(Generator); 0271 d->mPixmapReady = false; 0272 0273 const bool calcBoundingBox = !request->isTile() && !request->page()->isBoundingBoxKnown(); 0274 0275 if (request->asynchronous() && hasFeature(Threaded)) { 0276 if (d->textPageGenerationThread()->isFinished() && !canGenerateTextPage()) { 0277 // It can happen that the text generation has already finished but 0278 // mTextPageReady is still false because textpageGenerationFinished 0279 // didn't have time to run, if so queue ourselves 0280 QTimer::singleShot(0, this, [this, request] { generatePixmap(request); }); 0281 return; 0282 } 0283 0284 /** 0285 * We create the text page for every page that is visible to the 0286 * user, so he can use the text extraction tools without a delay. 0287 */ 0288 if (hasFeature(TextExtraction) && !request->page()->hasTextPage() && canGenerateTextPage() && !d->m_closing) { 0289 d->mTextPageReady = false; 0290 d->textPageGenerationThread()->setPage(request->page()); 0291 0292 // dummy is used as a way to make sure the lambda gets disconnected each time it is executed 0293 // since not all the times the pixmap generation thread starts we want the text generation thread to also start 0294 QObject *dummy = new QObject(); 0295 connect(d_ptr->pixmapGenerationThread(), &QThread::started, dummy, [this, dummy] { 0296 delete dummy; 0297 d_ptr->textPageGenerationThread()->startGeneration(); 0298 }); 0299 } 0300 // pixmap generation thread must be started *after* connect(), else we may miss the start signal and get lock-ups (see bug 396137) 0301 d->pixmapGenerationThread()->startGeneration(request, calcBoundingBox); 0302 0303 return; 0304 } 0305 0306 const QImage &img = image(request); 0307 request->page()->setPixmap(request->observer(), new QPixmap(QPixmap::fromImage(img)), request->normalizedRect()); 0308 const int pageNumber = request->page()->number(); 0309 0310 d->mPixmapReady = true; 0311 0312 signalPixmapRequestDone(request); 0313 if (calcBoundingBox) { 0314 updatePageBoundingBox(pageNumber, Utils::imageBoundingBox(&img)); 0315 } 0316 } 0317 0318 bool Generator::canGenerateTextPage() const 0319 { 0320 Q_D(const Generator); 0321 return d->mTextPageReady; 0322 } 0323 0324 void Generator::generateTextPage(Page *page) 0325 { 0326 TextRequest treq(page); 0327 TextPage *tp = textPage(&treq); 0328 page->setTextPage(tp); 0329 signalTextGenerationDone(page, tp); 0330 } 0331 0332 QImage Generator::image(PixmapRequest *request) 0333 { 0334 Q_D(Generator); 0335 return d->image(request); 0336 } 0337 0338 TextPage *Generator::textPage(TextRequest *) 0339 { 0340 return nullptr; 0341 } 0342 0343 DocumentInfo Generator::generateDocumentInfo(const QSet<DocumentInfo::Key> &keys) const 0344 { 0345 Q_UNUSED(keys); 0346 0347 return DocumentInfo(); 0348 } 0349 0350 const DocumentSynopsis *Generator::generateDocumentSynopsis() 0351 { 0352 return nullptr; 0353 } 0354 0355 FontInfo::List Generator::fontsForPage(int) 0356 { 0357 return FontInfo::List(); 0358 } 0359 0360 const QList<EmbeddedFile *> *Generator::embeddedFiles() const 0361 { 0362 return nullptr; 0363 } 0364 0365 Generator::PageSizeMetric Generator::pagesSizeMetric() const 0366 { 0367 return None; 0368 } 0369 0370 bool Generator::isAllowed(Permission) const 0371 { 0372 return true; 0373 } 0374 0375 void Generator::rotationChanged(Rotation, Rotation) 0376 { 0377 } 0378 0379 PageSize::List Generator::pageSizes() const 0380 { 0381 return PageSize::List(); 0382 } 0383 0384 void Generator::pageSizeChanged(const PageSize &, const PageSize &) 0385 { 0386 } 0387 0388 Document::PrintError Generator::print(QPrinter &) 0389 { 0390 return Document::UnknownPrintError; 0391 } 0392 0393 void Generator::opaqueAction(const BackendOpaqueAction * /*action*/) 0394 { 0395 } 0396 0397 void Generator::freeOpaqueActionContents(const BackendOpaqueAction & /*action*/) 0398 { 0399 } 0400 0401 QVariant Generator::metaData(const QString &key, const QVariant &option) const 0402 { 0403 Q_D(const Generator); 0404 return d->metaData(key, option); 0405 } 0406 0407 ExportFormat::List Generator::exportFormats() const 0408 { 0409 return ExportFormat::List(); 0410 } 0411 0412 bool Generator::exportTo(const QString &, const ExportFormat &) 0413 { 0414 return false; 0415 } 0416 0417 void Generator::walletDataForFile(const QString &fileName, QString *walletName, QString *walletFolder, QString *walletKey) const 0418 { 0419 #if HAVE_KWALLET 0420 *walletKey = fileName.section(QLatin1Char('/'), -1, -1); 0421 *walletName = KWallet::Wallet::NetworkWallet(); 0422 *walletFolder = QStringLiteral("KPdf"); 0423 #endif 0424 } 0425 0426 bool Generator::hasFeature(GeneratorFeature feature) const 0427 { 0428 Q_D(const Generator); 0429 return d->m_features.contains(feature); 0430 } 0431 0432 void Generator::signalPixmapRequestDone(PixmapRequest *request) 0433 { 0434 Q_D(Generator); 0435 if (d->m_document) { 0436 d->m_document->requestDone(request); 0437 } else { 0438 delete request; 0439 } 0440 } 0441 0442 void Generator::signalTextGenerationDone(Page *page, TextPage *textPage) 0443 { 0444 Q_D(Generator); 0445 if (d->m_document) { 0446 d->m_document->textGenerationDone(page); 0447 } else { 0448 delete textPage; 0449 } 0450 } 0451 0452 void Generator::signalPartialPixmapRequest(PixmapRequest *request, const QImage &image) 0453 { 0454 if (request->shouldAbortRender()) { 0455 return; 0456 } 0457 0458 PagePrivate *pagePrivate = PagePrivate::get(request->page()); 0459 pagePrivate->setPixmap(request->observer(), new QPixmap(QPixmap::fromImage(image)), request->normalizedRect(), true /* isPartialPixmap */); 0460 0461 const int pageNumber = request->page()->number(); 0462 request->observer()->notifyPageChanged(pageNumber, Okular::DocumentObserver::Pixmap); 0463 } 0464 0465 const Document *Generator::document() const 0466 { 0467 Q_D(const Generator); 0468 if (d->m_document) { 0469 return d->m_document->m_parent; 0470 } 0471 return nullptr; 0472 } 0473 0474 void Generator::setFeature(GeneratorFeature feature, bool on) 0475 { 0476 Q_D(Generator); 0477 if (on) { 0478 d->m_features.insert(feature); 0479 } else { 0480 d->m_features.remove(feature); 0481 } 0482 } 0483 0484 QVariant Generator::documentMetaData(const DocumentMetaDataKey key, const QVariant &option) const 0485 { 0486 Q_D(const Generator); 0487 if (!d->m_document) { 0488 return QVariant(); 0489 } 0490 0491 return d->m_document->documentMetaData(key, option); 0492 } 0493 0494 QMutex *Generator::userMutex() const 0495 { 0496 Q_D(const Generator); 0497 return &d->m_mutex; 0498 } 0499 0500 void Generator::updatePageBoundingBox(int page, const NormalizedRect &boundingBox) 0501 { 0502 Q_D(Generator); 0503 if (d->m_document) { // still connected to document? 0504 d->m_document->setPageBoundingBox(page, boundingBox); 0505 } 0506 } 0507 0508 QByteArray Generator::requestFontData(const Okular::FontInfo & /*font*/) 0509 { 0510 return {}; 0511 } 0512 0513 void Generator::setDPI(const QSizeF dpi) 0514 { 0515 Q_D(Generator); 0516 d->m_dpi = dpi; 0517 } 0518 0519 QSizeF Generator::dpi() const 0520 { 0521 Q_D(const Generator); 0522 return d->m_dpi; 0523 } 0524 0525 QAbstractItemModel *Generator::layersModel() const 0526 { 0527 return nullptr; 0528 } 0529 0530 TextRequest::TextRequest() 0531 : d(new TextRequestPrivate) 0532 { 0533 d->mPage = nullptr; 0534 d->mShouldAbortExtraction = 0; 0535 } 0536 0537 TextRequest::TextRequest(Page *page) 0538 : d(new TextRequestPrivate) 0539 { 0540 d->mPage = page; 0541 d->mShouldAbortExtraction = 0; 0542 } 0543 0544 TextRequest::~TextRequest() 0545 { 0546 delete d; 0547 } 0548 0549 Page *TextRequest::page() const 0550 { 0551 return d->mPage; 0552 } 0553 0554 bool TextRequest::shouldAbortExtraction() const 0555 { 0556 return d->mShouldAbortExtraction != 0; 0557 } 0558 0559 TextRequestPrivate *TextRequestPrivate::get(const TextRequest *req) 0560 { 0561 return req->d; 0562 } 0563 0564 PixmapRequest::PixmapRequest(DocumentObserver *observer, int pageNumber, int width, int height, qreal dpr, int priority, PixmapRequestFeatures features) 0565 : d(new PixmapRequestPrivate) 0566 { 0567 d->mObserver = observer; 0568 d->mPageNumber = pageNumber; 0569 d->mWidth = ceil(width * dpr); 0570 d->mHeight = ceil(height * dpr); 0571 d->mPriority = priority; 0572 d->mFeatures = features; 0573 d->mForce = false; 0574 d->mTile = false; 0575 d->mNormalizedRect = NormalizedRect(); 0576 d->mPartialUpdatesWanted = false; 0577 d->mShouldAbortRender = 0; 0578 } 0579 0580 PixmapRequest::~PixmapRequest() 0581 { 0582 delete d; 0583 } 0584 0585 DocumentObserver *PixmapRequest::observer() const 0586 { 0587 return d->mObserver; 0588 } 0589 0590 int PixmapRequest::pageNumber() const 0591 { 0592 return d->mPageNumber; 0593 } 0594 0595 int PixmapRequest::width() const 0596 { 0597 return d->mWidth; 0598 } 0599 0600 int PixmapRequest::height() const 0601 { 0602 return d->mHeight; 0603 } 0604 0605 int PixmapRequest::priority() const 0606 { 0607 return d->mPriority; 0608 } 0609 0610 bool PixmapRequest::asynchronous() const 0611 { 0612 return d->mFeatures & Asynchronous; 0613 } 0614 0615 bool PixmapRequest::preload() const 0616 { 0617 return d->mFeatures & Preload; 0618 } 0619 0620 Page *PixmapRequest::page() const 0621 { 0622 return d->mPage; 0623 } 0624 0625 void PixmapRequest::setTile(bool tile) 0626 { 0627 d->mTile = tile; 0628 } 0629 0630 bool PixmapRequest::isTile() const 0631 { 0632 return d->mTile; 0633 } 0634 0635 void PixmapRequest::setNormalizedRect(const NormalizedRect &rect) 0636 { 0637 if (d->mNormalizedRect == rect) { 0638 return; 0639 } 0640 0641 d->mNormalizedRect = rect; 0642 } 0643 0644 const NormalizedRect &PixmapRequest::normalizedRect() const 0645 { 0646 return d->mNormalizedRect; 0647 } 0648 0649 void PixmapRequest::setPartialUpdatesWanted(bool partialUpdatesWanted) 0650 { 0651 d->mPartialUpdatesWanted = partialUpdatesWanted; 0652 } 0653 0654 bool PixmapRequest::partialUpdatesWanted() const 0655 { 0656 return d->mPartialUpdatesWanted; 0657 } 0658 0659 bool PixmapRequest::shouldAbortRender() const 0660 { 0661 return d->mShouldAbortRender != 0; 0662 } 0663 0664 Okular::TilesManager *PixmapRequestPrivate::tilesManager() const 0665 { 0666 return mPage->d->tilesManager(mObserver); 0667 } 0668 0669 PixmapRequestPrivate *PixmapRequestPrivate::get(const PixmapRequest *req) 0670 { 0671 return req->d; 0672 } 0673 0674 void PixmapRequestPrivate::swap() 0675 { 0676 std::swap(mWidth, mHeight); 0677 } 0678 0679 class Okular::ExportFormatPrivate : public QSharedData 0680 { 0681 public: 0682 ExportFormatPrivate(const QString &description, const QMimeType &mimeType, const QIcon &icon = QIcon()) 0683 : QSharedData() 0684 , mDescription(description) 0685 , mMimeType(mimeType) 0686 , mIcon(icon) 0687 { 0688 } 0689 ~ExportFormatPrivate() 0690 { 0691 } 0692 0693 QString mDescription; 0694 QMimeType mMimeType; 0695 QIcon mIcon; 0696 }; 0697 0698 ExportFormat::ExportFormat() 0699 : d(new ExportFormatPrivate(QString(), QMimeType())) 0700 { 0701 } 0702 0703 ExportFormat::ExportFormat(const QString &description, const QMimeType &mimeType) 0704 : d(new ExportFormatPrivate(description, mimeType)) 0705 { 0706 } 0707 0708 ExportFormat::ExportFormat(const QIcon &icon, const QString &description, const QMimeType &mimeType) 0709 : d(new ExportFormatPrivate(description, mimeType, icon)) 0710 { 0711 } 0712 0713 ExportFormat::~ExportFormat() 0714 { 0715 } 0716 0717 ExportFormat::ExportFormat(const ExportFormat &other) 0718 : d(other.d) 0719 { 0720 } 0721 0722 ExportFormat &ExportFormat::operator=(const ExportFormat &other) 0723 { 0724 if (this == &other) { 0725 return *this; 0726 } 0727 0728 d = other.d; 0729 0730 return *this; 0731 } 0732 0733 QString ExportFormat::description() const 0734 { 0735 return d->mDescription; 0736 } 0737 0738 QMimeType ExportFormat::mimeType() const 0739 { 0740 return d->mMimeType; 0741 } 0742 0743 QIcon ExportFormat::icon() const 0744 { 0745 return d->mIcon; 0746 } 0747 0748 bool ExportFormat::isNull() const 0749 { 0750 return !d->mMimeType.isValid() || d->mDescription.isNull(); 0751 } 0752 0753 ExportFormat ExportFormat::standardFormat(StandardExportFormat type) 0754 { 0755 QMimeDatabase db; 0756 switch (type) { 0757 case PlainText: 0758 return ExportFormat(QIcon::fromTheme(QStringLiteral("text-x-generic")), i18n("Plain &Text..."), db.mimeTypeForName(QStringLiteral("text/plain"))); 0759 break; 0760 case PDF: 0761 return ExportFormat(QIcon::fromTheme(QStringLiteral("application-pdf")), i18n("PDF"), db.mimeTypeForName(QStringLiteral("application/pdf"))); 0762 break; 0763 case OpenDocumentText: 0764 return ExportFormat( 0765 QIcon::fromTheme(QStringLiteral("application-vnd.oasis.opendocument.text")), i18nc("This is the document format", "OpenDocument Text"), db.mimeTypeForName(QStringLiteral("application/vnd.oasis.opendocument.text"))); 0766 break; 0767 case HTML: 0768 return ExportFormat(QIcon::fromTheme(QStringLiteral("text-html")), i18nc("This is the document format", "HTML"), db.mimeTypeForName(QStringLiteral("text/html"))); 0769 break; 0770 } 0771 return ExportFormat(); 0772 } 0773 0774 bool ExportFormat::operator==(const ExportFormat &other) const 0775 { 0776 return d == other.d; 0777 } 0778 0779 bool ExportFormat::operator!=(const ExportFormat &other) const 0780 { 0781 return d != other.d; 0782 } 0783 0784 QDebug operator<<(QDebug str, const Okular::PixmapRequest &req) 0785 { 0786 PixmapRequestPrivate *reqPriv = PixmapRequestPrivate::get(&req); 0787 0788 str << "PixmapRequest:" << &req; 0789 str << "- observer:" << (qulonglong)req.observer(); 0790 str << "- page:" << req.pageNumber(); 0791 str << "- width:" << req.width(); 0792 str << "- height:" << req.height(); 0793 str << "- priority:" << req.priority(); 0794 str << "- async:" << (req.asynchronous() ? "true" : "false"); 0795 str << "- tile:" << (req.isTile() ? "true" : "false"); 0796 str << "- rect:" << req.normalizedRect(); 0797 str << "- preload:" << (req.preload() ? "true" : "false"); 0798 str << "- partialUpdates:" << (req.partialUpdatesWanted() ? "true" : "false"); 0799 str << "- shouldAbort:" << (req.shouldAbortRender() ? "true" : "false"); 0800 str << "- force:" << (reqPriv->mForce ? "true" : "false"); 0801 return str; 0802 } 0803 0804 /* kate: replace-tabs on; indent-width 4; */