File indexing completed on 2024-04-28 15:23:47

0001 /*
0002  * This file is part of the KDE libraries
0003  *
0004  * Copyright (C) 2007 Germain Garand <germain@ebooksfrance.org>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public License
0017  * along with this library; see the file COPYING.LIB.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020  *
0021  */
0022 
0023 // The PaintBuffer class provides a shared buffer for efficient repetitive painting.
0024 //
0025 // It will grow to encompass the biggest size encountered, in order to avoid
0026 // constantly resizing.
0027 // When it grows over maxPixelBuffering, it periodically checks if such a size
0028 // is still needed.  If not, it shrinks down to the biggest size < maxPixelBuffering
0029 // that was requested during the overflow lapse.
0030 
0031 #ifndef html_paintbuffer_h
0032 #define html_paintbuffer_h
0033 
0034 #include <QPixmap>
0035 #include <QStack>
0036 #include <QPainter>
0037 #include <QPaintEngine>
0038 #include <assert.h>
0039 
0040 namespace khtml
0041 {
0042 
0043 class BufferedPainter;
0044 class BufferSweeper;
0045 
0046 class PaintBuffer: public QObject
0047 {
0048     friend class khtml::BufferSweeper;
0049 
0050     Q_OBJECT
0051 
0052 public:
0053     static const int maxPixelBuffering;
0054     static const int leaseTime;
0055     static const int cleanupTime;
0056     static const int maxBuffers;
0057 
0058     static QPixmap *grab(QSize s = QSize());
0059     static void release(QPixmap *p);
0060 
0061     static void cleanup();
0062 
0063     PaintBuffer();
0064     void reset();
0065     void timerEvent(QTimerEvent *e) override;
0066 
0067 private:
0068     QPixmap *getBuf(QSize S);
0069 
0070     static QStack<PaintBuffer *> *s_avail;
0071     static QStack<PaintBuffer *> *s_grabbed;
0072     static QStack<QPixmap *>     *s_full;
0073     static BufferSweeper        *s_sweeper;
0074 
0075     QPixmap m_buf;
0076     bool m_overflow;
0077     bool m_grabbed;
0078     bool m_renewTimer;
0079     int m_timer;
0080     int m_resetWidth;
0081     int m_resetHeight;
0082 };
0083 
0084 class BufferedPainter
0085 {
0086 public:
0087     BufferedPainter(QPixmap *px, QPainter *&p, const QRegion &rr, bool replacePainter)
0088     {
0089         QRect br = rr.boundingRect();
0090         m_rect = br;
0091         bool doFill = 1 || !px->hasAlphaChannel(); // shared pixmaps aren't properly cleared
0092         // with Qt 4 + NVidia proprietary driver.
0093         // So we can't use this optimization until
0094         // we can detect this defect.
0095         if (doFill) {
0096             px->fill(Qt::transparent);
0097         }
0098         m_painter.begin(px);
0099 
0100         m_off = br.topLeft() + QPoint(static_cast<int>(p->worldTransform().dx()),
0101                                       static_cast<int>(p->worldTransform().dy()));
0102         m_painter.setWorldTransform(p->worldTransform());
0103         m_painter.translate(-m_off);
0104         m_painter.setClipRegion(m_region = rr);
0105         //foreach(QRect rrr, m_region.rects())
0106         //    qCDebug(KHTML_LOG) << rrr;
0107 
0108         if (!doFill) {
0109             m_painter.setCompositionMode(QPainter::CompositionMode_Source);
0110             m_painter.fillRect(br, Qt::transparent);
0111         }
0112 
0113         m_painter.setCompositionMode(p->compositionMode());
0114         m_buf = px;
0115 
0116         m_painter.setFont(p->font());
0117         m_painter.setBrush(p->brush());
0118         m_painter.setPen(p->pen());
0119         m_painter.setBackground(p->background());
0120         m_painter.setRenderHints(p->renderHints());
0121         // ### what else?
0122 
0123         m_origPainter = p;
0124         if (replacePainter) {
0125             p = &m_painter;
0126         }
0127         m_paused = false;
0128     }
0129 
0130     void transfer(float opacity)
0131     {
0132         // ### when using DestinationIn with an alpha above 0.99, the resulting buffer ends up black in Qt 4.5.1
0133         bool constantOpacity = (opacity > 0.99) || (m_origPainter->paintEngine() && m_origPainter->paintEngine()->hasFeature(QPaintEngine::ConstantOpacity));
0134         if (!constantOpacity) {
0135             QColor color;
0136             color.setAlphaF(opacity);
0137             m_painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
0138             m_painter.fillRect(m_rect, color);
0139         }
0140         m_painter.end();
0141         QTransform t = m_origPainter->worldTransform();
0142         QPoint trans(static_cast<int>(t.dx()), static_cast<int>(t.dy()));
0143         m_origPainter->save();
0144         m_origPainter->resetTransform();
0145         m_origPainter->setClipRegion(trans.isNull() ? m_region : m_region.translated(trans));
0146         m_origPainter->setWorldTransform(t);
0147         if (constantOpacity) {
0148             m_origPainter->setOpacity(opacity);
0149         }
0150         m_origPainter->drawPixmap(m_off - trans, *m_buf, QRect(0, 0, m_rect.width(), m_rect.height()));
0151         m_origPainter->restore();
0152     }
0153 
0154     static BufferedPainter *start(QPainter *&, const QRegion &);
0155     static void end(QPainter *&, BufferedPainter *bp, float opacity = 1.0);
0156 
0157     const QPainter *painter() const
0158     {
0159         return &m_painter;
0160     }
0161     QPainter *originalPainter() const
0162     {
0163         return m_origPainter;
0164     }
0165     QPixmap *buffer() const
0166     {
0167         return m_buf;
0168     }
0169 private:
0170     bool m_paused;
0171     QRect m_rect;
0172     QRegion m_region;
0173     QPoint m_off;
0174     QPainter m_painter;
0175     QPixmap *m_buf;
0176     QPainter *m_origPainter;
0177 };
0178 
0179 }
0180 #endif