Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdirectfbblitter.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
7
8#include <QtGui/private/qpixmap_blitter_p.h>
9
10#include <QDebug>
11#include <QFile>
12
13#include <directfb.h>
14
16
18{
19 return QBlittable::Capabilities(QBlittable::SolidRectCapability
20 |QBlittable::SourcePixmapCapability
21 |QBlittable::SourceOverPixmapCapability
22 |QBlittable::SourceOverScaledPixmapCapability
23 |QBlittable::AlphaFillRectCapability
24 |QBlittable::OpacityPixmapCapability
25 |QBlittable::DrawScaledCachedGlyphsCapability
26 );
27}
28
29QDirectFbBlitter::QDirectFbBlitter(const QSize &rect, IDirectFBSurface *surface)
32 , m_debugPaint(false)
33{
34 m_surface->AddRef(m_surface.data());
35
36 DFBSurfaceCapabilities surfaceCaps;
37 m_surface->GetCapabilities(m_surface.data(), &surfaceCaps);
38 m_premult = (surfaceCaps & DSCAPS_PREMULTIPLIED);
39 if (qEnvironmentVariableIntValue("QT_DIRECTFB_BLITTER_DEBUGPAINT"))
40 m_debugPaint = true;
41}
42
43QDirectFbBlitter::QDirectFbBlitter(const QSize &rect, bool alpha)
45 , m_premult(false)
46 , m_debugPaint(false)
47{
48 DFBSurfaceDescription surfaceDesc;
49 memset(&surfaceDesc,0,sizeof(DFBSurfaceDescription));
50 surfaceDesc.width = rect.width();
51 surfaceDesc.height = rect.height();
52
53 // force alpha format to get AlphaFillRectCapability and ExtendedPixmapCapability support
54 alpha = true;
55
56 if (alpha) {
57 m_premult = true;
58 surfaceDesc.caps = DSCAPS_PREMULTIPLIED;
59 surfaceDesc.pixelformat = QDirectFbBlitter::alphaPixmapFormat();
60 surfaceDesc.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_CAPS | DSDESC_PIXELFORMAT);
61 } else {
62 surfaceDesc.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT);
63 surfaceDesc.pixelformat = QDirectFbBlitter::pixmapFormat();
64 }
65
66 if (qEnvironmentVariableIntValue("QT_DIRECTFB_BLITTER_DEBUGPAINT"))
67 m_debugPaint = true;
68
69 IDirectFB *dfb = QDirectFbConvenience::dfbInterface();
70 dfb->CreateSurface(dfb , &surfaceDesc, m_surface.outPtr());
71 m_surface->Clear(m_surface.data(), 0, 0, 0, 0);
72}
73
75{
76 unlock();
77}
78
79DFBSurfacePixelFormat QDirectFbBlitter::alphaPixmapFormat()
80{
81 return DSPF_ARGB;
82}
83
84DFBSurfacePixelFormat QDirectFbBlitter::pixmapFormat()
85{
86 return DSPF_RGB32;
87}
88
89DFBSurfacePixelFormat QDirectFbBlitter::selectPixmapFormat(bool withAlpha)
90{
91 return withAlpha ? alphaPixmapFormat() : pixmapFormat();
92}
93
94void QDirectFbBlitter::fillRect(const QRectF &rect, const QColor &color)
95{
96 alphaFillRect(rect, color, QPainter::CompositionMode_Source);
97}
98
99void QDirectFbBlitter::drawPixmap(const QRectF &rect, const QPixmap &pixmap, const QRectF &srcRect)
100{
101 drawPixmapOpacity(rect, pixmap, srcRect, QPainter::CompositionMode_SourceOver, 1.0);
102}
103
104void QDirectFbBlitter::alphaFillRect(const QRectF &rect, const QColor &color, QPainter::CompositionMode cmode)
105{
106 int x, y, w, h;
107 DFBResult result;
108
109 // check parameters
110 rect.toRect().getRect(&x, &y ,&w, &h);
111 if ((w <= 0) || (h <= 0)) return;
112
113 if ((cmode == QPainter::CompositionMode_Source) || (color.alpha() == 255)) {
114 // CompositionMode_Source case or CompositionMode_SourceOver with opaque color
115
116 m_surface->SetDrawingFlags(m_surface.data(),
117 DFBSurfaceDrawingFlags(m_premult ? (DSDRAW_NOFX | DSDRAW_SRC_PREMULTIPLY) : DSDRAW_NOFX));
118 m_surface->SetPorterDuff(m_surface.data(), DSPD_SRC);
119
120 } else {
121 // CompositionMode_SourceOver case
122
123 // check if operation is useless
124 if (color.alpha() == 0)
125 return;
126
127 m_surface->SetDrawingFlags(m_surface.data(),
128 DFBSurfaceDrawingFlags(m_premult ? (DSDRAW_BLEND | DSDRAW_SRC_PREMULTIPLY) : DSDRAW_BLEND));
129 m_surface->SetPorterDuff(m_surface.data(), DSPD_SRC_OVER);
130 }
131
132 // set color
133 m_surface->SetColor(m_surface.data(), color.red(), color.green(), color.blue(), color.alpha());
134
135 // perform fill
136 result = m_surface->FillRectangle(m_surface.data(), x, y, w, h);
137 if (result != DFB_OK)
138 DirectFBError("QDirectFBBlitter::alphaFillRect()", result);
139 if (m_debugPaint)
140 drawDebugRect(QRect(x, y, w, h), QColor(Qt::blue));
141}
142
143void QDirectFbBlitter::drawPixmapOpacity(const QRectF &rect, const QPixmap &pixmap, const QRectF &subrect, QPainter::CompositionMode cmode, qreal opacity)
144{
145 QRect sQRect = subrect.toRect();
146 QRect dQRect = rect.toRect();
147 DFBRectangle sRect(sQRect.x(), sQRect.y(), sQRect.width(), sQRect.height());
148 DFBRectangle dRect(dQRect.x(), dQRect.y(), dQRect.width(), dQRect.height());
149 DFBResult result;
150
151 // skip if dst too small
152 if ((dRect.w <= 0) || (dRect.h <= 0)) return;
153
154 // correct roundings if needed
155 if (sRect.w <= 0) sRect.w = 1;
156 if (sRect.h <= 0) sRect.h = 1;
157
158 QDirectFbBlitterPlatformPixmap *blitPm = static_cast<QDirectFbBlitterPlatformPixmap *>(pixmap.handle());
159 QDirectFbBlitter *dfbBlitter = static_cast<QDirectFbBlitter *>(blitPm->blittable());
160 dfbBlitter->unlock();
161
162 IDirectFBSurface *s = dfbBlitter->m_surface.data();
163
164 DFBSurfaceBlittingFlags blittingFlags = DFBSurfaceBlittingFlags(DSBLIT_BLEND_ALPHACHANNEL);
165 DFBSurfacePorterDuffRule porterDuff = (cmode == QPainter::CompositionMode_SourceOver) ? DSPD_SRC_OVER : DSPD_SRC;
166
167 if (opacity != 1.0)
168 {
169 blittingFlags = DFBSurfaceBlittingFlags(blittingFlags | DSBLIT_BLEND_COLORALPHA | (m_premult ? DSBLIT_SRC_PREMULTCOLOR : 0));
170 m_surface->SetColor(m_surface.data(), 0xff, 0xff, 0xff, (u8) (opacity * 255.0));
171 }
172
173 m_surface->SetBlittingFlags(m_surface.data(), DFBSurfaceBlittingFlags(blittingFlags));
174 m_surface->SetPorterDuff(m_surface.data(), porterDuff);
175
176 if (cmode == QPainter::CompositionMode_SourceOver)
177 m_surface->SetDstBlendFunction(m_surface.data(), DSBF_INVSRCALPHA);
178
179 if ((sRect.w == dRect.w) && (sRect.h == dRect.h)) {
180 result = m_surface->Blit(m_surface.data(), s, &sRect, dRect.x, dRect.y);
181 if (result != DFB_OK)
182 DirectFBError("QDirectFBBlitter::drawPixmapOpacity()", result);
183 if (m_debugPaint)
184 drawDebugRect(QRect(dRect.x, dRect.y, sRect.w, sRect.h), QColor(Qt::green));
185 } else {
186 result = m_surface->StretchBlit(m_surface.data(), s, &sRect, &dRect);
187 if (result != DFB_OK)
188 DirectFBError("QDirectFBBlitter::drawPixmapOpacity()", result);
189 if (m_debugPaint)
190 drawDebugRect(QRect(dRect.x, dRect.y, dRect.w, dRect.h), QColor(Qt::red));
191 }
192}
193
194bool QDirectFbBlitter::drawCachedGlyphs(const QPaintEngineState *state, QFontEngine::GlyphFormat glyphFormat, int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, QFontEngine *fontEngine)
195{
196 void *cacheKey = QDirectFbConvenience::dfbInterface();
197
199 static_cast<QDirectFbTextureGlyphCache *>(fontEngine->glyphCache(cacheKey, glyphFormat, state->transform()));
200 if (!cache) {
201 cache = new QDirectFbTextureGlyphCache(glyphFormat, state->transform());
202 fontEngine->setGlyphCache(cacheKey, cache);
203 }
204
205 cache->populate(fontEngine, numGlyphs, glyphs, positions);
206 cache->fillInPendingGlyphs();
207
208 if (cache->image().width() == 0 || cache->image().height() == 0)
209 return false;
210
211 const int margin = fontEngine->glyphMargin(glyphFormat);
212
213 QVarLengthArray<DFBRectangle, 64> sourceRects(numGlyphs);
214 QVarLengthArray<DFBPoint, 64> destPoints(numGlyphs);
215 int nGlyphs = 0;
216
217 for (int i=0; i<numGlyphs; ++i) {
218
219 QFixed subPixelPosition = fontEngine->subPixelPositionForX(positions[i].x);
220 QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], QFixedPoint(subPixelPosition, 0));
221 const QTextureGlyphCache::Coord &c = cache->coords[glyph];
222 if (c.isNull())
223 continue;
224
225 int x = qFloor(positions[i].x) + c.baseLineX - margin;
226 int y = qRound(positions[i].y) - c.baseLineY - margin;
227
228 // printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n",
229 // c.x, c.y,
230 // c.w, c.h,
231 // c.baseLineX, c.baseLineY,
232 // glyphs[i],
233 // x, y,
234 // positions[i].x.toInt(), positions[i].y.toInt());
235
236 sourceRects[nGlyphs].x = c.x;
237 sourceRects[nGlyphs].y = c.y;
238 sourceRects[nGlyphs].w = c.w;
239 sourceRects[nGlyphs].h = c.h;
240 destPoints[nGlyphs].x = x;
241 destPoints[nGlyphs].y = y;
242 ++nGlyphs;
243 }
244
245 const QColor color = state->pen().color();
246 m_surface->SetColor(m_surface.data(), color.red(), color.green(), color.blue(), color.alpha());
247
248 m_surface->SetSrcBlendFunction(m_surface.data(), DSBF_SRCALPHA);
249 m_surface->SetDstBlendFunction(m_surface.data(), DSBF_INVSRCALPHA);
250
251 int flags = DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_COLORIZE;
252 if (color.alpha() != 0xff)
253 flags |= DSBLIT_BLEND_COLORALPHA;
254 m_surface->SetBlittingFlags(m_surface.data(), DFBSurfaceBlittingFlags(flags));
255
256 const QRasterPaintEngineState *rs = static_cast<const QRasterPaintEngineState*>(state);
257 if (rs->clip && rs->clip->enabled) {
258 Q_ASSERT(rs->clip->hasRectClip);
259 DFBRegion dfbClip;
260 dfbClip.x1 = rs->clip->clipRect.x();
261 dfbClip.y1 = rs->clip->clipRect.y();
262 dfbClip.x2 = rs->clip->clipRect.right();
263 dfbClip.y2 = rs->clip->clipRect.bottom();
264 m_surface->SetClip(m_surface.data(), &dfbClip);
265 }
266
267 m_surface->BatchBlit(m_surface.data(), cache->sourceSurface(), sourceRects.constData(), destPoints.constData(), nGlyphs);
268
269 if (m_debugPaint) {
270 for (int i = 0; i < nGlyphs; ++i) {
271 drawDebugRect(QRect(destPoints[i].x, destPoints[i].y, sourceRects[i].w, sourceRects[i].h), QColor(Qt::yellow));
272 }
273 }
274
275 if (rs->clip && rs->clip->enabled)
276 m_surface->SetClip(m_surface.data(), 0);
277 return true;
278}
279
281{
282 Q_ASSERT(m_surface);
283 Q_ASSERT(size().isValid());
284
285 void *mem;
286 int bpl;
287 const DFBResult result = m_surface->Lock(m_surface.data(), DFBSurfaceLockFlags(DSLF_WRITE|DSLF_READ), static_cast<void**>(&mem), &bpl);
288 if (result == DFB_OK) {
289 DFBSurfacePixelFormat dfbFormat;
290 DFBSurfaceCapabilities dfbCaps;
291 m_surface->GetPixelFormat(m_surface.data(), &dfbFormat);
292 m_surface->GetCapabilities(m_surface.data(), &dfbCaps);
293 QImage::Format format = QDirectFbConvenience::imageFormatFromSurfaceFormat(dfbFormat, dfbCaps);
294 int w, h;
295 m_surface->GetSize(m_surface.data(), &w, &h);
296 m_image = QImage(static_cast<uchar *>(mem),w,h,bpl,format);
297 } else {
298 DirectFBError("Failed to lock image", result);
299 }
300
301 return &m_image;
302}
303
304bool QDirectFbBlitterPlatformPixmap::fromDataBufferDescription(const DFBDataBufferDescription &dataBufferDescription)
305{
306 DFBResult result;
307 IDirectFB *dfb = QDirectFbConvenience::dfbInterface();
308
309 // Create a data buffer
310 QDirectFBPointer<IDirectFBDataBuffer> dataBuffer;
311 result = dfb->CreateDataBuffer(dfb, &dataBufferDescription, dataBuffer.outPtr());
312 if (result != DFB_OK) {
313 DirectFBError(QDFB_PRETTY, result);
314 return false;
315 }
316
317 // Create the image provider
318 QDirectFBPointer<IDirectFBImageProvider> provider;
319 result = dataBuffer->CreateImageProvider(dataBuffer.data(), provider.outPtr());
320 if (result != DFB_OK) {
321 DirectFBError(QDFB_PRETTY, result);
322 return false;
323 }
324
325 // Extract image information
326 DFBImageDescription imageDescription;
327 result = provider->GetImageDescription(provider.data(), &imageDescription);
328 if (result != DFB_OK) {
329 DirectFBError(QDFB_PRETTY, result);
330 return false;
331 }
332
333 // Can we handle this directlu?
334 if (imageDescription.caps & DICAPS_COLORKEY)
335 return false;
336
337 DFBSurfaceDescription surfaceDescription;
338 result = provider->GetSurfaceDescription(provider.data(), &surfaceDescription);
339 if (result != DFB_OK) {
340 DirectFBError(QDFB_PRETTY, result);
341 return false;
342 }
343
344 m_alpha = imageDescription.caps & DICAPS_ALPHACHANNEL;
345 resize(surfaceDescription.width, surfaceDescription.height);
346 // TODO: FIXME; update d
347
348
349 result = provider->RenderTo(provider.data(), dfbBlitter()->dfbSurface(), 0);
350 if (result != DFB_OK) {
351 DirectFBError(QDFB_PRETTY, result);
352 return false;
353 }
354
355 return true;
356}
357
358bool QDirectFbBlitterPlatformPixmap::fromFile(const QString &filename, const char *format,
359 Qt::ImageConversionFlags flags)
360{
361 // If we can't find the file, pass it on to the base class as it is
362 // trying harder by appending various extensions to the path.
363 if (!QFile::exists(filename))
364 return QBlittablePlatformPixmap::fromFile(filename, format, flags);
365
366 // Stop if there is a requirement for colors
367 if (flags != Qt::AutoColor)
368 return QBlittablePlatformPixmap::fromFile(filename, format, flags);
369
370 // Deal with resources
371 if (filename.startsWith(u':'))
372 return QBlittablePlatformPixmap::fromFile(filename, format, flags);
373
374 // Try to use directfb to load it.
375 DFBDataBufferDescription description;
376 description.flags = DBDESC_FILE;
377 const QByteArray fileNameData = filename.toLocal8Bit();
378 description.file = fileNameData.constData();
379 if (fromDataBufferDescription(description))
380 return true;
381
382 // Fallback
383 return QBlittablePlatformPixmap::fromFile(filename, format, flags);
384}
385
387{
388 m_surface->Unlock(m_surface.data());
389}
390
391void QDirectFbBlitter::drawDebugRect(const QRect &rect, const QColor &color)
392{
393 int x, y, w, h;
394 DFBResult result;
395
396 // check parameters
397 rect.getRect(&x, &y ,&w, &h);
398 if ((w <= 0) || (h <= 0)) return;
399
400 m_surface->SetDrawingFlags(m_surface.data(),
401 DFBSurfaceDrawingFlags(m_premult ? (DSDRAW_BLEND | DSDRAW_SRC_PREMULTIPLY) : DSDRAW_BLEND));
402 m_surface->SetPorterDuff(m_surface.data(), DSPD_SRC_OVER);
403
404 // set color
405 m_surface->SetColor(m_surface.data(), color.red(), color.green(), color.blue(), 120);
406
407 result = m_surface->DrawLine(m_surface.data(), x, y, x + w-1, y);
408 if (result != DFB_OK)
409 DirectFBError("QDirectFBBlitter::drawDebugRect()", result);
410 result = m_surface->DrawLine(m_surface.data(), x + w-1, y, x + w-1, y + h-1);
411 if (result != DFB_OK)
412 DirectFBError("QDirectFBBlitter::drawDebugRect()", result);
413 result = m_surface->DrawLine(m_surface.data(), x + w-1, y + h-1, x, y + h-1);
414 if (result != DFB_OK)
415 DirectFBError("QDirectFBBlitter::drawDebugRect()", result);
416 result = m_surface->DrawLine(m_surface.data(), x, y + h-1, x, y);
417 if (result != DFB_OK)
418 DirectFBError("QDirectFBBlitter::drawDebugRect()", result);
419
420 m_surface->SetColor(m_surface.data(), color.red(), color.green(), color.blue(), 10);
421 result = m_surface->FillRectangle(m_surface.data(), x, y, w, h);
422 if (result != DFB_OK)
423 DirectFBError("QDirectFBBlitter::drawDebugRect()", result);
424}
425
427{
428 m_surface.reset();
429 QImageTextureGlyphCache::resizeTextureData(width, height);
430}
431
433{
434 if (m_surface.isNull()) {
435 const QImage &source = image();
436 DFBSurfaceDescription desc;
437 memset(&desc, 0, sizeof(desc));
438 desc.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT | DSDESC_PREALLOCATED | DSDESC_CAPS);
439 desc.width = source.width();
440 desc.height = source.height();
441 desc.caps = DSCAPS_SYSTEMONLY;
442
443 switch (source.format()) {
444 case QImage::Format_Mono:
445 desc.pixelformat = DSPF_A1;
446 break;
447 case QImage::Format_Alpha8:
448 desc.pixelformat = DSPF_A8;
449 break;
450 default:
451 qFatal("QDirectFBTextureGlyphCache: Unsupported source texture image format.");
452 break;
453 }
454
455 desc.preallocated[0].data = const_cast<void*>(static_cast<const void*>(source.bits()));
456 desc.preallocated[0].pitch = source.bytesPerLine();
457 desc.preallocated[1].data = 0;
458 desc.preallocated[1].pitch = 0;
459
460 IDirectFB *dfb = QDirectFbConvenience::dfbInterface();
461 dfb->CreateSurface(dfb , &desc, m_surface.outPtr());
462 }
463 return m_surface.data();
464}
465
466QT_END_NAMESPACE
bool fromFile(const QString &filename, const char *format, Qt::ImageConversionFlags flags) override
QDirectFbBlitter * dfbBlitter() const
bool drawCachedGlyphs(const QPaintEngineState *state, QFontEngine::GlyphFormat glyphFormat, int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, QFontEngine *fontEngine) override
void alphaFillRect(const QRectF &rect, const QColor &color, QPainter::CompositionMode cmode) override
QDirectFbBlitter(const QSize &size, bool alpha)
QDirectFbBlitter(const QSize &size, IDirectFBSurface *surface)
QImage * doLock() override
void drawPixmapOpacity(const QRectF &rect, const QPixmap &pixmap, const QRectF &subrect, QPainter::CompositionMode cmode, qreal opacity) override
void doUnlock() override
void fillRect(const QRectF &rect, const QColor &color) override
void drawPixmap(const QRectF &rect, const QPixmap &pixmap, const QRectF &subrect) override
void resizeTextureData(int width, int height) override
IDirectFBSurface * sourceSurface()
static QT_BEGIN_NAMESPACE QBlittable::Capabilities dfb_blitter_capabilities()
#define QDFB_PRETTY