File indexing completed on 2024-05-12 16:37:09
0001 /* This file is part of the KDE project 0002 * Copyright (C) 2002-2006 David Faure <faure@kde.org> 0003 * Copyright (C) 2005-2006 Thomas Zander <zander@kde.org> 0004 * Copyright (C) 2009 Inge Wallin <inge@lysator.liu.se> 0005 * Copyright (C) 2010-2011 Boudewijn Rempt <boud@kogmbh.com> 0006 * Copyright (C) 2011 Marijn Kruisselbrink <mkruisselbrink@kde.org> 0007 * 0008 * This library is free software; you can redistribute it and/or 0009 * modify it under the terms of the GNU Library General Public 0010 * License as published by the Free Software Foundation; either 0011 * version 2 of the License, or (at your option) any later version. 0012 * 0013 * This library is distributed in the hope that it will be useful, 0014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0016 * Library General Public License for more details. 0017 * 0018 * You should have received a copy of the GNU Library General Public License 0019 * along with this library; see the file COPYING.LIB. If not, write to 0020 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0021 * Boston, MA 02110-1301, USA. 0022 */ 0023 #include "KWCanvasBase.h" 0024 0025 // words includes 0026 #include "KWCanvas.h" 0027 #include "KWGui.h" 0028 #include "KWViewMode.h" 0029 #include "KWPage.h" 0030 #include "KWPageCacheManager.h" 0031 #include "frames/KWFrameLayout.h" 0032 #include "WordsDebug.h" 0033 0034 // calligra libs includes 0035 #include <KoShapeManager.h> 0036 #include <KoPointerEvent.h> 0037 #include <KoCanvasController.h> 0038 #include <KoToolProxy.h> 0039 #include <KoGridData.h> 0040 #include <KoGuidesData.h> 0041 #include <KoShape.h> 0042 #include <KoViewConverter.h> 0043 #include <KoUnit.h> 0044 0045 #include <KoAnnotationLayoutManager.h> 0046 0047 // Qt 0048 #include <QBrush> 0049 #include <QPainter> 0050 #include <QPainterPath> 0051 #include <QThread> 0052 0053 #include <sys/time.h> 0054 0055 //#define DEBUG_REPAINT 0056 0057 0058 KWCanvasBase::KWCanvasBase(KWDocument *document, QObject *parent) 0059 : KoCanvasBase(document), 0060 m_document(document), 0061 m_shapeManager(0), 0062 m_toolProxy(0), 0063 m_viewMode(0), 0064 m_viewConverter(0), 0065 m_showAnnotations(false), 0066 m_cacheEnabled(false), 0067 m_currentZoom(0.0), 0068 m_maxZoom(2.0), 0069 m_pageCacheManager(0) 0070 { 0071 m_shapeManager = new KoShapeManager(this); 0072 m_toolProxy = new KoToolProxy(this, parent); 0073 //setCacheEnabled(true); 0074 } 0075 0076 KWCanvasBase::~KWCanvasBase() 0077 { 0078 delete m_shapeManager; 0079 delete m_viewMode; 0080 delete m_pageCacheManager; 0081 } 0082 0083 void KWCanvasBase::gridSize(qreal *horizontal, qreal *vertical) const 0084 { 0085 *horizontal = m_document->gridData().gridX(); 0086 *vertical = m_document->gridData().gridY(); 0087 } 0088 0089 void KWCanvasBase::addCommand(KUndo2Command *command) 0090 { 0091 m_document->addCommand(command); 0092 } 0093 0094 KoShapeManager *KWCanvasBase::shapeManager() const 0095 { 0096 return m_shapeManager; 0097 } 0098 0099 KoUnit KWCanvasBase::unit() const 0100 { 0101 return m_document->unit(); 0102 } 0103 0104 KoToolProxy *KWCanvasBase::toolProxy() const 0105 { 0106 return m_toolProxy; 0107 } 0108 0109 void KWCanvasBase::clipToDocument(const KoShape *shape, QPointF &move) const 0110 { 0111 Q_ASSERT(shape); 0112 const QPointF absPos = shape->absolutePosition(); 0113 const QPointF destination = absPos + move; 0114 qreal bottomOfPage = 0.0; 0115 KWPage page; 0116 foreach (const KWPage &p, m_document->pageManager()->pages()) { 0117 bottomOfPage += p.height(); 0118 if (bottomOfPage >= absPos.y()) 0119 page = p; 0120 if (bottomOfPage >= destination.y()) { 0121 page = p; 0122 break; 0123 } 0124 } 0125 if (!page.isValid()) { // shape was not in any page to begin with, can't propose anything sane... 0126 move.setX(0); 0127 move.setY(0); 0128 return; 0129 } 0130 QRectF pageRect(page.rect().adjusted(5, 5, -5, -5)); 0131 QPainterPath path(shape->absoluteTransformation(0).map(shape->outline())); 0132 QRectF shapeBounds = path.boundingRect(); 0133 shapeBounds.moveTopLeft(shapeBounds.topLeft() + move); 0134 if (!shapeBounds.intersects(pageRect)) { 0135 if (shapeBounds.left() > pageRect.right()) // need to move to the left some 0136 move.setX(move.x() + (pageRect.right() - shapeBounds.left())); 0137 else if (shapeBounds.right() < pageRect.left()) // need to move to the right some 0138 move.setX(move.x() + pageRect.left() - shapeBounds.right()); 0139 0140 if (shapeBounds.top() > pageRect.bottom()) // need to move up some 0141 move.setY(move.y() + (pageRect.bottom() - shapeBounds.top())); 0142 else if (shapeBounds.bottom() < pageRect.top()) // need to move down some 0143 move.setY(move.y() + pageRect.top() - shapeBounds.bottom()); 0144 } 0145 0146 // Also make sure any anchoring restrictions are adhered to 0147 KWFrameLayout::proposeShapeMove(shape, move, page); 0148 } 0149 0150 KoGuidesData *KWCanvasBase::guidesData() 0151 { 0152 return &m_document->guidesData(); 0153 } 0154 0155 KWDocument *KWCanvasBase::document() const 0156 { 0157 return m_document; 0158 } 0159 0160 KWViewMode *KWCanvasBase::viewMode() const 0161 { 0162 return m_viewMode; 0163 } 0164 0165 void KWCanvasBase::ensureVisible(const QRectF &rect) 0166 { 0167 QRectF viewRect = m_viewMode->documentToView(rect, m_viewConverter); 0168 canvasController()->ensureVisible(viewRect); 0169 } 0170 0171 bool KWCanvasBase::showAnnotations() const 0172 { 0173 return m_showAnnotations; 0174 } 0175 0176 void KWCanvasBase::setShowAnnotations(bool doShow) 0177 { 0178 m_showAnnotations = doShow; 0179 } 0180 0181 void KWCanvasBase::paintBackgrounds(QPainter &painter, KWViewMode::ViewMap &viewMap) 0182 { 0183 // Paint the page. 0184 0185 QColor color = Qt::white; 0186 #ifdef DEBUG_REPAINT 0187 color = QColor(random() % 255, random() % 255, random() % 255); 0188 #endif 0189 painter.fillRect(viewMap.clipRect, QBrush(color)); 0190 0191 // Paint the annotation area if that is turned on. 0192 if (m_showAnnotations) { 0193 color = Qt::cyan; 0194 QRect annotationRect(m_viewMode->contentsSize().width(), 0, 0195 AnnotationAreaWidth, m_viewMode->contentsSize().height()); 0196 QRectF viewRect(m_viewMode->documentToView(annotationRect, m_viewConverter)); 0197 painter.fillRect(viewRect, QBrush(color)); 0198 0199 0200 if (m_document->annotationLayoutManager()) 0201 m_document->annotationLayoutManager()->paintConnections(painter); 0202 } 0203 } 0204 0205 void KWCanvasBase::paintPageDecorations(QPainter &painter, KWViewMode::ViewMap &viewMap) 0206 { 0207 // We have no page shadows yet. 0208 Q_UNUSED(painter); 0209 Q_UNUSED(viewMap); 0210 } 0211 0212 void KWCanvasBase::paintBorder(QPainter &painter, KWViewMode::ViewMap &viewMap) 0213 { 0214 painter.save(); 0215 0216 const QRectF pageRect = viewMap.page.rect(); 0217 const KoPageLayout pageLayout = viewMap.page.pageStyle().pageLayout(); 0218 0219 qreal zoomX, zoomY; 0220 viewConverter()->zoom(&zoomX, &zoomY); 0221 painter.scale(zoomX, zoomY); 0222 0223 QPointF topLeftCorner = QPointF(pageRect.topLeft() + QPointF(pageLayout.leftMargin, 0224 pageLayout.topMargin)); 0225 QPointF bottomRightCorner = QPointF(pageRect.bottomRight() + QPointF(-pageLayout.rightMargin, 0226 -pageLayout.bottomMargin)); 0227 QRectF borderRect = QRectF(topLeftCorner, bottomRightCorner); 0228 pageLayout.border.paint(painter, borderRect); 0229 0230 painter.restore(); 0231 } 0232 0233 void KWCanvasBase::paintGrid(QPainter &painter, KWViewMode::ViewMap &vm) 0234 { 0235 painter.save(); 0236 painter.translate(-vm.distance.x(), -vm.distance.y()); 0237 painter.setRenderHint(QPainter::Antialiasing, false); 0238 const QRectF clipRect = viewConverter()->viewToDocument(vm.clipRect); 0239 document()->gridData().paintGrid(painter, *(viewConverter()), clipRect); 0240 document()->guidesData().paintGuides(painter, *(viewConverter()), clipRect); 0241 painter.restore(); 0242 } 0243 0244 void KWCanvasBase::paint(QPainter &painter, const QRectF &paintRect) 0245 { 0246 painter.translate(-m_documentOffset); 0247 0248 static int iteration = 0; 0249 iteration++; 0250 0251 if (m_viewMode->hasPages()) { 0252 0253 int pageContentArea = 0; 0254 if (!m_cacheEnabled || !m_pageCacheManager) { // no caching, simple case 0255 0256 QVector<KWViewMode::ViewMap> map = 0257 m_viewMode->mapExposedRects(paintRect.translated(m_documentOffset), 0258 viewConverter()); 0259 foreach (KWViewMode::ViewMap vm, map) { 0260 painter.save(); 0261 0262 // Set up the painter to clip the part of the canvas that contains the rect. 0263 // FIXME: The viewmap must also take into account the annotation area 0264 painter.translate(vm.distance.x(), vm.distance.y()); 0265 vm.clipRect = vm.clipRect.adjusted(-1, -1, 1, 1); 0266 painter.setClipRect(vm.clipRect); 0267 0268 // Paint the background of the page. This includes 0269 // the annotation area if that should be shown. 0270 paintBackgrounds(painter, vm); 0271 0272 // Paint the contents of the page (shapes border). 0273 painter.setRenderHint(QPainter::Antialiasing); 0274 m_shapeManager->paint(painter, *(viewConverter()), false); // Paint all shapes 0275 paintBorder(painter, vm); 0276 0277 // Paint the page decorations: shadow, etc. 0278 // FIXME: This will fail because the painter is clipped to the page. 0279 paintPageDecorations(painter, vm); 0280 0281 // Paint the grid 0282 paintGrid(painter, vm); 0283 0284 // Paint whatever the tool wants to paint 0285 m_toolProxy->paint(painter, *(viewConverter())); 0286 painter.restore(); 0287 0288 int contentArea = vm.clipRect.width() * vm.clipRect.height(); 0289 if (contentArea > pageContentArea) { 0290 pageContentArea = contentArea; 0291 } 0292 } 0293 } 0294 else { 0295 0296 #if 0 0297 // at the moment we're always caching at the actual zoomlevel anyway, but if we want to 0298 // re-enable this distinction, the massive code duplication between these two code paths 0299 // should first be removed 0300 if (viewConverter()->zoom() <= m_maxZoom) { // we cache at the actual zoom level 0301 #endif 0302 QVector<KWViewMode::ViewMap> map = 0303 m_viewMode->mapExposedRects(paintRect.translated(m_documentOffset), 0304 viewConverter()); 0305 0306 foreach (KWViewMode::ViewMap vm, map) { 0307 0308 painter.save(); 0309 0310 // Set up the painter to clip the part of the canvas that contains the rect. 0311 painter.translate(vm.distance.x(), vm.distance.y()); 0312 vm.clipRect = vm.clipRect.adjusted(-1, -1, 1, 1); 0313 painter.setClipRect(vm.clipRect); 0314 0315 // Paint the background of the page. 0316 QColor color = Qt::white; 0317 #ifdef DEBUG_REPAINT 0318 color = QColor(random() % 255, random() % 255, random() % 255); 0319 #endif 0320 painter.fillRect(vm.clipRect, QBrush(color)); 0321 0322 // Paint the contents of the page. 0323 painter.setRenderHint(QPainter::Antialiasing); 0324 0325 // clear the cache if the zoom changed 0326 qreal zoom = viewConverter()->zoom(); 0327 if (m_currentZoom != zoom) { 0328 m_pageCacheManager->clear(); 0329 m_currentZoom = zoom; 0330 } 0331 0332 KWPageCache *pageCache = m_pageCacheManager->take(vm.page); 0333 0334 if (!pageCache) { 0335 pageCache = m_pageCacheManager->cache(QSize(viewConverter()->documentToViewX(vm.page.width()), 0336 viewConverter()->documentToViewY(vm.page.height()))); 0337 } 0338 0339 Q_ASSERT(!pageCache->cache.isEmpty()); 0340 0341 // vm.page is in points, not view units 0342 QSizeF pageSizeDocument(vm.page.width(), vm.page.height()); 0343 QSizeF pageSizeView = viewConverter()->documentToView(pageSizeDocument); 0344 0345 qreal pageTopDocument = vm.page.offsetInDocument(); 0346 qreal pageTopView = viewConverter()->documentToViewY(pageTopDocument); 0347 0348 QRectF pageRectDocument = vm.page.rect(); 0349 QRectF pageRectView = viewConverter()->documentToView(pageRectDocument); 0350 0351 // translated from the page topleft to 0,0 for our cache image 0352 QRectF clipRectOnPage = vm.clipRect.translated(-pageRectView.x(), -pageTopView); 0353 0354 // create exposed rects when the page is to be completely repainted. 0355 // we cannot wait for the updateCanvas calls to actually tell us which parts 0356 // need painting, because updateCanvas is not called when a page is done 0357 // layouting. 0358 if (pageCache->allExposed) { 0359 0360 pageCache->exposed.clear(); 0361 QRect rc(QPoint(0,0), pageSizeView.toSize()); 0362 0363 const int UPDATE_WIDTH = 900; 0364 const int UPDATE_HEIGHT = 128; 0365 0366 int row = 0; 0367 int heightLeft = rc.height(); 0368 while (heightLeft > 0) { 0369 int height = qMin(heightLeft, UPDATE_HEIGHT); 0370 int column = 0; 0371 int columnLeft = rc.width(); 0372 while (columnLeft > 0) { 0373 int width = qMin(columnLeft, UPDATE_WIDTH); 0374 QRect rc2(column, row, width, height); 0375 pageCache->exposed << rc2; 0376 columnLeft -= width; 0377 column += width; 0378 } 0379 heightLeft -= height; 0380 row += height; 0381 } 0382 pageCache->allExposed = false; 0383 } 0384 0385 // There is stuff to be repainted, so collect all the repaintable 0386 // rects that are in view and paint them. 0387 if (!pageCache->exposed.isEmpty()) { 0388 QRegion paintRegion; 0389 QVector<QRect> remainingUnExposed; 0390 const QVector<QRect> &exposed = pageCache->exposed; 0391 for (int i = 0; i < exposed.size(); ++i) { 0392 0393 QRect rc = exposed.at(i); 0394 0395 if (rc.intersects(clipRectOnPage.toRect())) { 0396 paintRegion += rc; 0397 int tilex = 0, tiley = 0; 0398 for (int x = 0, i = 0; x < pageCache->m_tilesx; ++x) { 0399 int dx = pageCache->cache[i].width(); 0400 for (int y = 0; y < pageCache->m_tilesy; ++y, ++i) { 0401 QImage& img = pageCache->cache[i]; 0402 QRect tile(tilex, tiley, img.width(), img.height()); 0403 QRect toClear = tile.intersected(rc); 0404 if (!toClear.isEmpty()) { 0405 QPainter gc(&img); 0406 gc.eraseRect(toClear.translated(-tilex, -tiley)); 0407 gc.end(); 0408 } 0409 tiley += img.height(); 0410 } 0411 tilex += dx; 0412 tiley = 0; 0413 } 0414 } 0415 else { 0416 remainingUnExposed << rc; 0417 } 0418 } 0419 pageCache->exposed = remainingUnExposed; 0420 if (!paintRegion.isEmpty()) { 0421 // paint the exposed regions of the page 0422 0423 QRect r = paintRegion.boundingRect(); 0424 QImage img(r.size(), QImage::Format_RGB16); 0425 img.fill(0xffff); 0426 0427 // we paint to a small image as it is much faster the painting to the big image 0428 QPainter tilePainter(&img); 0429 tilePainter.setClipRect(QRect(QPoint(0,0), r.size())); 0430 tilePainter.translate(-r.left(), -pageTopView - r.top()); 0431 tilePainter.setRenderHint(QPainter::Antialiasing); 0432 shapeManager()->paint(tilePainter, *viewConverter(), false); 0433 0434 int tilex = 0, tiley = 0; 0435 for (int x = 0, i = 0; x < pageCache->m_tilesx; ++x) { 0436 int dx = pageCache->cache[i].width(); 0437 for (int y = 0; y < pageCache->m_tilesy; ++y, ++i) { 0438 QImage& tileImg = pageCache->cache[i]; 0439 QRect tile(tilex, tiley, tileImg.width(), tileImg.height()); 0440 QRect toPaint = tile.intersected(r); 0441 if (!toPaint.isEmpty()) { 0442 QPainter imagePainter(&tileImg); 0443 imagePainter.drawImage(r.topLeft() - QPoint(tilex, tiley), img); 0444 } 0445 tiley += tileImg.height(); 0446 } 0447 tilex += dx; 0448 tiley = 0; 0449 } 0450 } 0451 } 0452 // paint from the cached page image on the original painter 0453 0454 int tilex = 0, tiley = 0; 0455 for (int x = 0, i = 0; x < pageCache->m_tilesx; ++x) { 0456 int dx = pageCache->cache[i].width(); 0457 for (int y = 0; y < pageCache->m_tilesy; ++y, ++i) { 0458 const QImage& cacheImage = pageCache->cache[i]; 0459 QRectF tile(tilex, tiley, cacheImage.width(), cacheImage.height()); 0460 QRectF toPaint = tile.intersected(clipRectOnPage); 0461 QRectF dst = toPaint.translated(pageRectView.topLeft()); 0462 QRectF src = toPaint.translated(-tilex, -tiley); 0463 painter.drawImage(dst, cacheImage, src); 0464 tiley += cacheImage.height(); 0465 } 0466 tilex += dx; 0467 tiley = 0; 0468 } 0469 0470 // put the cache back 0471 m_pageCacheManager->insert(vm.page, pageCache); 0472 // Paint the page decorations: border, shadow, etc. 0473 paintPageDecorations(painter, vm); 0474 0475 // Paint the grid 0476 paintGrid(painter, vm); 0477 0478 // paint whatever the tool wants to paint 0479 m_toolProxy->paint(painter, *(viewConverter())); 0480 painter.restore(); 0481 0482 int contentArea = vm.clipRect.width() * vm.clipRect.height(); 0483 if (contentArea > pageContentArea) { 0484 pageContentArea = contentArea; 0485 } 0486 } 0487 #if 0 0488 } 0489 else { // we cache at 100%, but paint at the actual zoom level 0490 0491 KoViewConverter localViewConverter; 0492 localViewConverter.setZoom(1.0); 0493 0494 QVector<KWViewMode::ViewMap> map = 0495 m_viewMode->mapExposedRects(paintRect.translated(m_documentOffset), 0496 viewConverter()); 0497 foreach (KWViewMode::ViewMap vm, map) { 0498 0499 painter.save(); 0500 0501 // Set up the painter to clip the part of the canvas that contains the rect. 0502 painter.translate(vm.distance.x(), vm.distance.y()); 0503 vm.clipRect = vm.clipRect.adjusted(-1, -1, 1, 1); 0504 painter.setClipRect(vm.clipRect); 0505 0506 // Paint the background of the page. 0507 QColor color = Qt::white; 0508 #ifdef DEBUG_REPAINT 0509 color = QColor(random() % 255, random() % 255, random() % 255); 0510 #endif 0511 painter.fillRect(vm.clipRect, QBrush(color)); 0512 0513 // Paint the contents of the page. 0514 painter.setRenderHint(QPainter::Antialiasing); 0515 0516 // clear the cache if the zoom changed 0517 qreal zoom = 1.0; 0518 if (m_currentZoom != zoom) { 0519 m_pageCacheManager->clear(); 0520 m_currentZoom = zoom; 0521 } 0522 0523 KWPageCache *pageCache = m_pageCacheManager->take(vm.page); 0524 if (!pageCache) { 0525 pageCache = m_pageCacheManager->cache(QSize(localViewConverter.documentToViewX(vm.page.width()), 0526 localViewConverter.documentToViewY(vm.page.height()))); 0527 } 0528 Q_ASSERT(pageCache->cache); 0529 0530 // vm.page is in points, not view units 0531 QSizeF pageSizeDocument(vm.page.width(), vm.page.height()); 0532 QSizeF pageSizeView = localViewConverter.documentToView(pageSizeDocument); 0533 0534 qreal pageTopDocument = vm.page.offsetInDocument(); 0535 qreal pageTopView = localViewConverter.documentToViewY(pageTopDocument); 0536 0537 QRectF pageRectDocument = vm.page.rect(); 0538 QRectF pageRectView = localViewConverter.documentToView(pageRectDocument); 0539 0540 // translated from the page topleft to 0,0 for our cache image 0541 QRectF documentClipRect = m_viewMode->viewToDocument(vm.clipRect, viewConverter()); 0542 QRectF clipRectOnPage = localViewConverter.documentToView(documentClipRect); 0543 clipRectOnPage = clipRectOnPage.translated(-pageRectView.x(), -pageTopView); 0544 0545 // create exposed rects when the page is to be completely repainted. 0546 // we cannot wait for the updateCanvas calls to actually tell us which parts 0547 // need painting, because updateCanvas is not called when a page is done 0548 // layouting. 0549 if (pageCache->allExposed) { 0550 0551 pageCache->exposed.clear(); 0552 QRect rc(QPoint(0,0), pageSizeView.toSize()); 0553 0554 const int UPDATE_SIZE = 64; //pixels 0555 0556 if (rc.height() < UPDATE_SIZE) { 0557 pageCache->exposed << rc; 0558 } 0559 else { 0560 int row = 0; 0561 int hleft = rc.height(); 0562 int w = rc.width(); 0563 while (hleft > 0) { 0564 QRect rc2(0, row, w, qMin(hleft, UPDATE_SIZE)); 0565 pageCache->exposed << rc2; 0566 hleft -= UPDATE_SIZE; 0567 row += UPDATE_SIZE; 0568 } 0569 } 0570 pageCache->allExposed = false; 0571 } 0572 0573 // There is stuff to be repainted, so collect all the repaintable 0574 // rects that are in view and paint them. 0575 if (!pageCache->exposed.isEmpty()) { 0576 QRegion paintRegion; 0577 QVector<QRect> remainingUnExposed; 0578 const QVector<QRect> &exposed = pageCache->exposed; 0579 for (int i = 0; i < exposed.size(); ++i) { 0580 0581 QRect rc = exposed.at(i); 0582 0583 if (rc.intersects(clipRectOnPage.toRect())) { 0584 paintRegion += rc; 0585 QPainter gc(pageCache->cache); 0586 gc.eraseRect(rc); 0587 gc.end(); 0588 } 0589 else { 0590 remainingUnExposed << rc; 0591 } 0592 } 0593 0594 pageCache->exposed = remainingUnExposed; 0595 0596 // paint the exposed regions of the page 0597 QPainter gc(pageCache->cache); 0598 gc.translate(0, -pageTopView); 0599 gc.setClipRegion(paintRegion.translated(0, pageTopView)); 0600 0601 // paint into the cache 0602 shapeManager()->paint(gc, localViewConverter, false); 0603 } 0604 QImage copy = pageCache->cache->copy(clipRectOnPage.toRect()); 0605 0606 // Now calculate where to paint pour stuff 0607 pageTopView = viewConverter()->documentToViewY(pageTopDocument); 0608 pageRectView = viewConverter()->documentToView(pageRectDocument); 0609 clipRectOnPage = viewConverter()->documentToView(documentClipRect); 0610 clipRectOnPage = clipRectOnPage.translated(-pageRectView.x(), -pageTopView); 0611 0612 copy = copy.scaled(clipRectOnPage.width(), clipRectOnPage.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); 0613 0614 // paint from the cached page image on the original painter. 0615 QRect dst = QRect(pageRectView.x() + clipRectOnPage.x(), 0616 pageRectView.y() + clipRectOnPage.y(), 0617 clipRectOnPage.width(), 0618 clipRectOnPage.height()); 0619 0620 painter.drawImage(dst.x(), dst.y(), copy, 0, 0, copy.width(), copy.height()); 0621 painter.restore(); 0622 0623 // put the cache back 0624 m_pageCacheManager->insert(vm.page, pageCache); 0625 0626 // Paint the page decorations: border, shadow, etc. 0627 paintPageDecorations(painter, vm); 0628 0629 // Paint the grid 0630 paintGrid(painter, vm); 0631 0632 // paint whatever the tool wants to paint 0633 m_toolProxy->paint(painter, *(viewConverter())); 0634 0635 0636 int contentArea = qRound(vm.clipRect.width() * vm.clipRect.height()); 0637 if (contentArea > pageContentArea) { 0638 pageContentArea = contentArea; 0639 } 0640 } 0641 } 0642 #endif 0643 } 0644 } else { 0645 // TODO paint the main-text-flake directly 0646 warnWordsUI << "Non-page painting not implemented yet!"; 0647 } 0648 } 0649 0650 void KWCanvasBase::updateCanvas(const QRectF &rc) 0651 { 0652 if (!m_cacheEnabled) { // no caching 0653 QRectF zoomedRect = m_viewMode->documentToView(rc, viewConverter()); 0654 QVector<KWViewMode::ViewMap> map = m_viewMode->mapExposedRects(zoomedRect, 0655 viewConverter()); 0656 foreach (KWViewMode::ViewMap vm, map) { 0657 vm.clipRect.adjust(-2, -2, 2, 2); // grow for anti-aliasing 0658 QRect finalClip((int)(vm.clipRect.x() + vm.distance.x() - m_documentOffset.x()), 0659 (int)(vm.clipRect.y() + vm.distance.y() - m_documentOffset.y()), 0660 vm.clipRect.width(), vm.clipRect.height()); 0661 updateCanvasInternal(finalClip); 0662 } 0663 } 0664 else { // Caching at the actual zoom level 0665 if (viewConverter()->zoom() <= m_maxZoom) { 0666 QRectF zoomedRect = m_viewMode->documentToView(rc, viewConverter()); 0667 QVector<KWViewMode::ViewMap> map = m_viewMode->mapExposedRects(zoomedRect, 0668 viewConverter()); 0669 foreach (KWViewMode::ViewMap vm, map) { 0670 vm.clipRect.adjust(-2, -2, 2, 2); // grow for anti-aliasing 0671 QRect finalClip((int)(vm.clipRect.x() + vm.distance.x() - m_documentOffset.x()), 0672 (int)(vm.clipRect.y() + vm.distance.y() - m_documentOffset.y()), 0673 vm.clipRect.width(), vm.clipRect.height()); 0674 0675 if (!m_pageCacheManager) { 0676 // no pageCacheManager, so create one for the current view. This happens only once! 0677 // so on zoom change, we don't re-pre-generate weight/zoom images. 0678 m_pageCacheManager = new KWPageCacheManager(m_cacheSize); 0679 } 0680 0681 if (m_currentZoom != viewConverter()->zoom()) { 0682 m_currentZoom = viewConverter()->zoom(); 0683 m_pageCacheManager->clear(); 0684 } 0685 0686 KWPageCache *pageCache = m_pageCacheManager->take(vm.page); 0687 if (pageCache) { 0688 //if (rc.isNull()) { 0689 pageCache->allExposed = true; 0690 pageCache->exposed.clear(); 0691 #if 0 0692 } 0693 else { 0694 qreal pageTopDocument = vm.page.offsetInDocument(); 0695 qreal pageTopView = viewConverter()->documentToViewY(pageTopDocument); 0696 QRectF pageRectDocument = vm.page.rect(); 0697 QRectF pageRectView = viewConverter()->documentToView(pageRectDocument); 0698 0699 // translated from the page topleft to 0,0 for our cache image 0700 QRect clipRectOnPage = vm.clipRect.translated(-pageRectView.x(), -pageTopView); 0701 0702 pageCache->exposed.append(clipRectOnPage); 0703 } 0704 #endif 0705 m_pageCacheManager->insert(vm.page, pageCache); 0706 } 0707 updateCanvasInternal(finalClip); 0708 } 0709 } 0710 else { // Cache at 100%, but update the canvas at the actual zoom level 0711 0712 KoViewConverter localViewConverter; 0713 localViewConverter.setZoom(1.0); 0714 0715 // Viewmap scaled to 100% for calculating which parts of the cached page image 0716 // are exposed. 0717 QRectF zoomedRect = m_viewMode->documentToView(rc, &localViewConverter); 0718 QVector<KWViewMode::ViewMap> map = m_viewMode->mapExposedRects(zoomedRect, &localViewConverter); 0719 0720 // Viewmap scaled to the actual size of the canvas, so we know which areas to call 0721 // update() for. 0722 zoomedRect = m_viewMode->documentToView(rc, viewConverter()); 0723 QVector<KWViewMode::ViewMap> actualMap = m_viewMode->mapExposedRects(zoomedRect, viewConverter()); 0724 0725 Q_ASSERT(actualMap.size() == map.size()); 0726 0727 for (int index = 0; index < map.size(); ++index) { 0728 0729 Q_ASSERT(index < map.size()); 0730 KWViewMode::ViewMap vm = map.at(index); 0731 vm.clipRect.adjust(-2, -2, 2, 2); // grow for anti-aliasing 0732 0733 Q_ASSERT(index < actualMap.size()); 0734 KWViewMode::ViewMap actualVm = actualMap.at(index); 0735 actualVm.clipRect.adjust(-2, -2, 2, 2); // grow for anti-aliasing 0736 QRect finalClip = QRect((int)(actualVm.clipRect.x() + vm.distance.x() - m_documentOffset.x()), 0737 (int)(actualVm.clipRect.y() + vm.distance.y() - m_documentOffset.y()), 0738 actualVm.clipRect.width(), 0739 actualVm.clipRect.height()); 0740 0741 if (!m_pageCacheManager) { 0742 // no pageCacheManager, so create one for the current view. This happens only once! 0743 // so on zoom change, we don't re-pre-generate weight/zoom images. 0744 m_pageCacheManager = new KWPageCacheManager(m_cacheSize); 0745 } 0746 0747 if (m_currentZoom != 1.0) { 0748 m_pageCacheManager->clear(); 0749 m_currentZoom = 1.0; 0750 } 0751 0752 KWPageCache *pageCache = m_pageCacheManager->take(vm.page); 0753 if (pageCache) { 0754 //if (rc.isNull()) { 0755 pageCache->allExposed = true; 0756 pageCache->exposed.clear(); 0757 #if 0 0758 } 0759 else { 0760 qreal pageTopDocument = vm.page.offsetInDocument(); 0761 qreal pageTopView = localViewConverter.documentToViewY(pageTopDocument); 0762 QRectF pageRectDocument = vm.page.rect(); 0763 QRectF pageRectView = localViewConverter.documentToView(pageRectDocument); 0764 0765 // translated from the page topleft to 0,0 for our cache image 0766 QRect clipRectOnPage = vm.clipRect.translated(-pageRectView.x(), -pageTopView); 0767 0768 pageCache->exposed.append(clipRectOnPage); 0769 } 0770 #endif 0771 m_pageCacheManager->insert(vm.page, pageCache); 0772 } 0773 updateCanvasInternal(finalClip); 0774 } 0775 } 0776 } 0777 } 0778 0779 0780 KoViewConverter *KWCanvasBase::viewConverter() const 0781 { 0782 return m_viewConverter; 0783 } 0784 0785 void KWCanvasBase::setCacheEnabled(bool enabled, int cacheSize, qreal maxZoom) 0786 { 0787 if ((!m_pageCacheManager && enabled) || (m_cacheSize != cacheSize)) { 0788 delete m_pageCacheManager; 0789 m_pageCacheManager = new KWPageCacheManager(cacheSize); 0790 } 0791 m_cacheEnabled = enabled; 0792 m_cacheSize = cacheSize; 0793 m_maxZoom = maxZoom; 0794 } 0795 0796 QPoint KWCanvasBase::documentOffset() const 0797 { 0798 return m_documentOffset; 0799 } 0800 0801 const qreal KWCanvasBase::AnnotationAreaWidth = 200.0; // only static const integral data members can be initialized within a class