1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qdirectfbblitter.h"
43 #include "qdirectfbconvenience.h"
44 
45 #include <QtGui/private/qpixmap_blitter_p.h>
46 
47 #include <QDebug>
48 #include <QFile>
49 
50 #include <directfb.h>
51 
52 QT_BEGIN_NAMESPACE
53 
dfb_blitter_capabilities()54 static QBlittable::Capabilities dfb_blitter_capabilities()
55 {
56     return QBlittable::Capabilities(QBlittable::SolidRectCapability
57                                     |QBlittable::SourcePixmapCapability
58                                     |QBlittable::SourceOverPixmapCapability
59                                     |QBlittable::SourceOverScaledPixmapCapability
60                                     |QBlittable::AlphaFillRectCapability
61                                     |QBlittable::OpacityPixmapCapability);
62 }
63 
QDirectFbBlitter(const QSize & rect,IDirectFBSurface * surface)64 QDirectFbBlitter::QDirectFbBlitter(const QSize &rect, IDirectFBSurface *surface)
65     : QBlittable(rect, dfb_blitter_capabilities())
66         , m_surface(surface)
67 {
68     m_surface->AddRef(m_surface.data());
69 
70     DFBSurfaceCapabilities surfaceCaps;
71     m_surface->GetCapabilities(m_surface.data(), &surfaceCaps);
72     m_premult = (surfaceCaps & DSCAPS_PREMULTIPLIED);
73 }
74 
QDirectFbBlitter(const QSize & rect,bool alpha)75 QDirectFbBlitter::QDirectFbBlitter(const QSize &rect, bool alpha)
76     : QBlittable(rect, dfb_blitter_capabilities()), m_premult(false)
77 {
78     DFBSurfaceDescription surfaceDesc;
79     memset(&surfaceDesc,0,sizeof(DFBSurfaceDescription));
80     surfaceDesc.width = rect.width();
81     surfaceDesc.height = rect.height();
82 
83     // force alpha format to get AlphaFillRectCapability and ExtendedPixmapCapability support
84     alpha = true;
85 
86     if (alpha) {
87         m_premult = true;
88         surfaceDesc.caps = DSCAPS_PREMULTIPLIED;
89         surfaceDesc.pixelformat = QDirectFbBlitter::alphaPixmapFormat();
90         surfaceDesc.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_CAPS | DSDESC_PIXELFORMAT);
91     } else {
92         surfaceDesc.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT);
93         surfaceDesc.pixelformat = QDirectFbBlitter::pixmapFormat();
94     }
95 
96     IDirectFB *dfb = QDirectFbConvenience::dfbInterface();
97     dfb->CreateSurface(dfb , &surfaceDesc, m_surface.outPtr());
98     m_surface->Clear(m_surface.data(), 0, 0, 0, 0);
99 }
100 
~QDirectFbBlitter()101 QDirectFbBlitter::~QDirectFbBlitter()
102 {
103     unlock();
104 }
105 
alphaPixmapFormat()106 DFBSurfacePixelFormat QDirectFbBlitter::alphaPixmapFormat()
107 {
108     return DSPF_ARGB;
109 }
110 
pixmapFormat()111 DFBSurfacePixelFormat QDirectFbBlitter::pixmapFormat()
112 {
113     return DSPF_RGB32;
114 }
115 
selectPixmapFormat(bool withAlpha)116 DFBSurfacePixelFormat QDirectFbBlitter::selectPixmapFormat(bool withAlpha)
117 {
118     return withAlpha ? alphaPixmapFormat() : pixmapFormat();
119 }
120 
fillRect(const QRectF & rect,const QColor & color)121 void QDirectFbBlitter::fillRect(const QRectF &rect, const QColor &color)
122 {
123     alphaFillRect(rect, color, QPainter::CompositionMode_Source);
124 }
125 
drawPixmap(const QRectF & rect,const QPixmap & pixmap,const QRectF & srcRect)126 void QDirectFbBlitter::drawPixmap(const QRectF &rect, const QPixmap &pixmap, const QRectF &srcRect)
127 {
128     drawPixmapOpacity(rect, pixmap, srcRect, QPainter::CompositionMode_SourceOver, 1.0);
129 }
130 
alphaFillRect(const QRectF & rect,const QColor & color,QPainter::CompositionMode cmode)131 void QDirectFbBlitter::alphaFillRect(const QRectF &rect, const QColor &color, QPainter::CompositionMode cmode)
132 {
133     int x, y, w, h;
134     DFBResult result;
135 
136     // check paramters
137     rect.toRect().getRect(&x, &y ,&w, &h);
138     if ((w <= 0) || (h <= 0)) return;
139 
140     if ((cmode == QPainter::CompositionMode_Source) || (color.alpha() == 255)) {
141         // CompositionMode_Source case or CompositionMode_SourceOver with opaque color
142 
143         m_surface->SetDrawingFlags(m_surface.data(),
144             DFBSurfaceDrawingFlags(m_premult ? (DSDRAW_NOFX | DSDRAW_SRC_PREMULTIPLY) : DSDRAW_NOFX));
145         m_surface->SetPorterDuff(m_surface.data(), DSPD_SRC);
146 
147     } else {
148         // CompositionMode_SourceOver case
149 
150         // check if operation is useless
151         if (color.alpha() == 0)
152             return;
153 
154         m_surface->SetDrawingFlags(m_surface.data(),
155             DFBSurfaceDrawingFlags(m_premult ? (DSDRAW_BLEND | DSDRAW_SRC_PREMULTIPLY) : DSDRAW_BLEND));
156         m_surface->SetPorterDuff(m_surface.data(), DSPD_SRC_OVER);
157     }
158 
159     // set color
160     m_surface->SetColor(m_surface.data(), color.red(), color.green(), color.blue(), color.alpha());
161 
162     // perform fill
163     result = m_surface->FillRectangle(m_surface.data(), x, y, w, h);
164     if (result != DFB_OK)
165         DirectFBError("QDirectFBBlitter::alphaFillRect()", result);
166 }
167 
drawPixmapOpacity(const QRectF & rect,const QPixmap & pixmap,const QRectF & subrect,QPainter::CompositionMode cmode,qreal opacity)168 void QDirectFbBlitter::drawPixmapOpacity(const QRectF &rect, const QPixmap &pixmap, const QRectF &subrect, QPainter::CompositionMode cmode, qreal opacity)
169 {
170     QRect sQRect = subrect.toRect();
171     QRect dQRect = rect.toRect();
172     DFBRectangle sRect = { sQRect.x(), sQRect.y(), sQRect.width(), sQRect.height() };
173     DFBRectangle dRect = { dQRect.x(), dQRect.y(), dQRect.width(), dQRect.height() };
174     DFBResult result;
175 
176     // skip if dst too small
177     if ((dRect.w <= 0) || (dRect.h <= 0)) return;
178 
179     // correct roundings if needed
180     if (sRect.w <= 0) sRect.w = 1;
181     if (sRect.h <= 0) sRect.h = 1;
182 
183     QBlittablePixmapData *blitPm = static_cast<QBlittablePixmapData*>(pixmap.pixmapData());
184     QDirectFbBlitter *dfbBlitter = static_cast<QDirectFbBlitter *>(blitPm->blittable());
185     dfbBlitter->unlock();
186 
187     IDirectFBSurface *s = dfbBlitter->m_surface.data();
188 
189     DFBSurfaceBlittingFlags blittingFlags = DFBSurfaceBlittingFlags(DSBLIT_BLEND_ALPHACHANNEL);
190     DFBSurfacePorterDuffRule porterDuff = (cmode == QPainter::CompositionMode_SourceOver) ? DSPD_SRC_OVER : DSPD_SRC;
191 
192     if (opacity != 1.0)
193     {
194         blittingFlags = DFBSurfaceBlittingFlags(blittingFlags | DSBLIT_BLEND_COLORALPHA | (m_premult ? DSBLIT_SRC_PREMULTCOLOR : 0));
195         m_surface->SetColor(m_surface.data(), 0xff, 0xff, 0xff, (u8) (opacity * 255.0));
196     }
197 
198     m_surface->SetBlittingFlags(m_surface.data(), DFBSurfaceBlittingFlags(blittingFlags));
199     m_surface->SetPorterDuff(m_surface.data(), porterDuff);
200 
201     if (cmode == QPainter::CompositionMode_SourceOver)
202         m_surface->SetDstBlendFunction(m_surface.data(), DSBF_INVSRCALPHA);
203 
204     if ((sRect.w == dRect.w) && (sRect.h == dRect.h))
205         result = m_surface->Blit(m_surface.data(), s, &sRect, dRect.x, dRect.y);
206     else
207         result = m_surface->StretchBlit(m_surface.data(), s, &sRect, &dRect);
208 
209     if (result != DFB_OK)
210         DirectFBError("QDirectFBBlitter::drawPixmapExtended()", result);
211 }
212 
doLock()213 QImage *QDirectFbBlitter::doLock()
214 {
215     Q_ASSERT(m_surface);
216     Q_ASSERT(size().isValid());
217 
218     void *mem;
219     int bpl;
220     const DFBResult result = m_surface->Lock(m_surface.data(), DFBSurfaceLockFlags(DSLF_WRITE|DSLF_READ), static_cast<void**>(&mem), &bpl);
221     if (result == DFB_OK) {
222         DFBSurfacePixelFormat dfbFormat;
223         DFBSurfaceCapabilities dfbCaps;
224         m_surface->GetPixelFormat(m_surface.data(), &dfbFormat);
225         m_surface->GetCapabilities(m_surface.data(), &dfbCaps);
226         QImage::Format format = QDirectFbConvenience::imageFormatFromSurfaceFormat(dfbFormat, dfbCaps);
227         int w, h;
228         m_surface->GetSize(m_surface.data(), &w, &h);
229         m_image = QImage(static_cast<uchar *>(mem),w,h,bpl,format);
230     } else {
231         DirectFBError("Failed to lock image", result);
232     }
233 
234     return &m_image;
235 }
236 
fromDataBufferDescription(const DFBDataBufferDescription & dataBufferDescription)237 bool QDirectFbBlitterPlatformPixmap::fromDataBufferDescription(const DFBDataBufferDescription &dataBufferDescription)
238 {
239     DFBResult result;
240     IDirectFB *dfb = QDirectFbConvenience::dfbInterface();
241 
242     // Create a data buffer
243     QDirectFBPointer<IDirectFBDataBuffer> dataBuffer;
244     result = dfb->CreateDataBuffer(dfb, &dataBufferDescription, dataBuffer.outPtr());
245     if (result != DFB_OK) {
246         DirectFBError(QDFB_PRETTY, result);
247         return false;
248     }
249 
250     // Create the image provider
251     QDirectFBPointer<IDirectFBImageProvider> provider;
252     result = dataBuffer->CreateImageProvider(dataBuffer.data(), provider.outPtr());
253     if (result != DFB_OK) {
254         DirectFBError(QDFB_PRETTY, result);
255         return false;
256     }
257 
258     // Extract image information
259     DFBImageDescription imageDescription;
260     result = provider->GetImageDescription(provider.data(), &imageDescription);
261     if (result != DFB_OK) {
262         DirectFBError(QDFB_PRETTY, result);
263         return false;
264     }
265 
266     // Can we handle this directlu?
267     if (imageDescription.caps & DICAPS_COLORKEY)
268         return false;
269 
270     DFBSurfaceDescription surfaceDescription;
271     result = provider->GetSurfaceDescription(provider.data(), &surfaceDescription);
272     if (result != DFB_OK) {
273         DirectFBError(QDFB_PRETTY, result);
274         return false;
275     }
276 
277     m_alpha = imageDescription.caps & DICAPS_ALPHACHANNEL;
278     resize(surfaceDescription.width, surfaceDescription.height);
279     // TODO: FIXME; update d
280 
281 
282     result = provider->RenderTo(provider.data(), dfbBlitter()->dfbSurface(), 0);
283     if (result != DFB_OK) {
284         DirectFBError(QDFB_PRETTY, result);
285         return false;
286     }
287 
288     return true;
289 }
290 
fromFile(const QString & filename,const char * format,Qt::ImageConversionFlags flags)291 bool QDirectFbBlitterPlatformPixmap::fromFile(const QString &filename, const char *format,
292                                               Qt::ImageConversionFlags flags)
293 {
294     // If we can't find the file, pass it on to the base class as it is
295     // trying harder by appending various extensions to the path.
296     if (!QFile::exists(filename))
297         return QBlittablePixmapData::fromFile(filename, format, flags);
298 
299     // Stop if there is a requirement for colors
300     if (flags != Qt::AutoColor)
301         return QBlittablePixmapData::fromFile(filename, format, flags);
302 
303     // Deal with resources
304     if (filename.startsWith(QLatin1Char(':')))
305         return QBlittablePixmapData::fromFile(filename, format, flags);
306 
307     // Try to use directfb to load it.
308     DFBDataBufferDescription description;
309     description.flags = DBDESC_FILE;
310     const QByteArray fileNameData = filename.toLocal8Bit();
311     description.file = fileNameData.constData();
312     if (fromDataBufferDescription(description))
313         return true;
314 
315     // Fallback
316     return QBlittablePixmapData::fromFile(filename, format, flags);
317 }
318 
doUnlock()319 void QDirectFbBlitter::doUnlock()
320 {
321     m_surface->Unlock(m_surface.data());
322 }
323 
324 QT_END_NAMESPACE
325