3 Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #define DEBUG_KP_PIXMAP_FX 0
32 #include <kpPixmapFX.h>
36 #include <sys/types.h>
40 #include <qapplication.h>
42 #include <qdatetime.h>
45 #include <qpainterpath.h>
51 #include <KApplication>
53 #include <kconfiggroup.h>
57 #include <kmessagebox.h>
59 #include <kpAbstractSelection.h>
65 #if DEBUG_KP_PIXMAP_FX
66 #define KP_PRINTF if (1) printf
68 #define KP_PRINTF if (0) (void)
73 // Same as QPixmap::defaultDepth(), but returns a meaningful answer when
74 // called before QApplication has been constructed, rather than always 32.
75 // After QApplication has been constructed, you must use QPixmap::defaultDepth()
78 // Returns 0 if it encounters an error.
80 // Internally, this method forks the process. In the child, a KApplication
81 // is constructed, QPixmap::defaultDepth() is called and the result is sent to
82 // the parent. The child is then killed.
83 static int QPixmapCalculateDefaultDepthWithoutQApplication ()
85 KP_PRINTF (("QPixmapCalculateDefaultDepthWithoutQApplication()\n"));
112 KP_PRINTF ("Child: created\n");
117 const int depth
= QPixmap::defaultDepth ();
118 KP_PRINTF (("Child: writing default depth\n"));
119 write (fds
[Write
], &depth
, sizeof (depth
));
120 KP_PRINTF (("Child: wrote default depth\n"));
123 KP_PRINTF ("Child: exit\n");
129 KP_PRINTF ("Parent: in here\n");
133 KP_PRINTF ("Parent: reading default depth\n");
134 read (fds
[Read
], &depth
, sizeof (depth
));
135 KP_PRINTF ("Parent: read default depth %d\n", depth
);
139 // Kill zombie child.
140 KP_PRINTF ("Parent: waiting for child\n");
142 (void) waitpid (pid
, &status
, 0/*options*/);
144 KP_PRINTF ("Parent: complete\n");
152 // (KApplication has not been constructed yet)
153 void kpPixmapFX::initMaskOpsPre ()
156 const int defaultDepth
= QPixmapCalculateDefaultDepthWithoutQApplication ();
158 // This is important for diagnosing KolourPaint bugs so always print it
159 // -- even in release mode.
160 printf ("Starting KolourPaint on a %d-bit screen...\n", defaultDepth
);
162 if (defaultDepth
== 32)
164 KP_PRINTF ("\tCannot handle alpha channel - disabling XRENDER\n");
166 // SYNC: Might break with Qt upgrades.
167 setenv ("QT_X11_NO_XRENDER", "1", 1/*overwrite value*/);
171 #warning "KolourPaint is heavily dependent on the behavior of QPixmap under X11."
172 #warning "Until KolourPaint gets a proper image library, it is unlikely to work under non-X11."
178 void kpPixmapFX::initMaskOpsPost ()
180 #if DEBUG_KP_PIXMAP_FX
181 kDebug () << "kpPixmapFX::initMaskOpsPost():"
182 << "QPixmap().depth()=" << QPixmap ().depth ()
183 << "QPixmap::defaultDepth()=" << QPixmap::defaultDepth ();
186 // Check KolourPaint invariant.
187 KP_PFX_CHECK_NO_ALPHA_CHANNEL (QPixmap ());
188 KP_PFX_CHECK_NO_ALPHA_CHANNEL (QPixmap (1, 1));
189 Q_ASSERT (QPixmap ().depth () == QPixmap::defaultDepth ());
190 Q_ASSERT (QPixmap (1, 1).depth () == QPixmap::defaultDepth ());
192 // initMaskOpsPre() should have ensured this (if it was 32 previously, it
193 // should now be 24 due to the disabling of XRENDER).
194 Q_ASSERT (QPixmap::defaultDepth () < 32);
199 bool kpPixmapFX::hasMask (const QPixmap
&pixmap
)
201 return pixmap
.hasAlpha ();
205 bool kpPixmapFX::hasAlphaChannel (const QPixmap
&pixmap
)
207 return pixmap
.hasAlphaChannel ();
211 bool kpPixmapFX::checkNoAlphaChannelInternal (const QPixmap
&pixmap
)
213 if (!kpPixmapFX::hasAlphaChannel (pixmap
))
217 kError () << "Pixmap has alpha channel. See the .h doc for"
218 " kpPixmapFX::ensureNoAlphaChannel() to fix this.";
219 // Ignore bug rather than crashing the program because I bet developers
220 // will inadvertently trigger this, when changing the code. The bug has
221 // very annoying effects under XRENDER but only causes serious failure
222 // without XRENDER (which is not so common).
225 // Assert-crash the program.
232 void kpPixmapFX::ensureNoAlphaChannel (QPixmap
*destPixmapPtr
)
234 Q_ASSERT (destPixmapPtr
);
236 if (kpPixmapFX::hasAlphaChannel (*destPixmapPtr
))
238 // We need to change <destPixmapPtr> from 32-bit (RGBA
239 // i.e. hasAlphaChannel() returns true -- regardless of whether the
240 // channel has any actual content -- which causes trouble) to 24-bit
241 // (RGB with possible mask).
243 // "destPixmapPtr->setMask (destPixmapPtr->mask())" is not
244 // sufficient so do it a long way:
246 QPixmap oldPixmap
= *destPixmapPtr
;
248 QBitmap oldMask
= oldPixmap
.mask ();
249 // Kill RGB source mask in case it causes alpha channel / composition
250 // operations in the following copy.
251 oldPixmap
.setMask (QBitmap ());
254 *destPixmapPtr
= QPixmap (oldPixmap
.width (), oldPixmap
.height ());
255 QPainter
p (destPixmapPtr
);
256 p
.drawPixmap (QPoint (0, 0), oldPixmap
);
259 // Copy mask layer (if any).
260 destPixmapPtr
->setMask (oldMask
);
263 // Note that we don't check this on function entry as the purpose of
264 // this function is to force the pixmap to satisfy this invariant.
265 KP_PFX_CHECK_NO_ALPHA_CHANNEL (*destPixmapPtr
);
270 QBitmap
kpPixmapFX::getNonNullMask (const QPixmap
&pm
)
272 KP_PFX_CHECK_NO_ALPHA_CHANNEL (pm
);
274 // (a bit slow so we cache it)
275 const QBitmap mask
= pm
.mask ();
281 QBitmap
maskBitmap (pm
.width (), pm
.height ());
282 maskBitmap
.fill (Qt::color1
/*opaque*/);
290 void kpPixmapFX::ensureTransparentAt (QPixmap
*destPixmapPtr
, const QRect
&destRect
)
295 KP_PFX_CHECK_NO_ALPHA_CHANNEL (*destPixmapPtr
);
297 QBitmap maskBitmap
= getNonNullMask (*destPixmapPtr
);
299 QPainter
p (&maskBitmap
);
300 p
.fillRect (destRect
, Qt::color0
/*transparent*/);
303 destPixmapPtr
->setMask (maskBitmap
);
305 KP_PFX_CHECK_NO_ALPHA_CHANNEL (*destPixmapPtr
);
310 void kpPixmapFX::paintMaskTransparentWithBrush (QPixmap
*destPixmapPtr
, const QPoint
&destAt
,
311 const QPixmap
&brushBitmap
)
313 #if DEBUG_KP_PIXMAP_FX
314 kDebug () << "kpPixmapFX::paintMaskTransparentWithBrush(destAt="
315 << destAt
<< ") brushRect=" << brushBitmap
.rect ()
319 Q_ASSERT (destPixmapPtr
);
321 KP_PFX_CHECK_NO_ALPHA_CHANNEL (*destPixmapPtr
);
323 Q_ASSERT (brushBitmap
.depth () == 1);
325 const QRegion brushRegion
= QRegion (brushBitmap
).translated (destAt
);
327 // OPT: Hopelessly inefficent due to function call overhead and
328 // fillRect() changing the mask every single iteration.
330 // kpPixmapFX should have a function that does this with only a
331 // single mask write.
332 foreach (const QRect
&r
, brushRegion
.rects ())
334 #if DEBUG_KP_PIXMAP_FX && 0
335 kDebug () << "\tcopy rect=" << r
;
337 kpPixmapFX::fillRect (destPixmapPtr
,
338 r
.x (), r
.y (), r
.width (), r
.height (),
339 kpColor::Transparent
);
342 KP_PFX_CHECK_NO_ALPHA_CHANNEL (*destPixmapPtr
);
346 void kpPixmapFX::paintMaskTransparentWithBrush (QPixmap
*destPixmapPtr
, int destX
, int destY
,
347 const QPixmap
&brushBitmap
)
349 kpPixmapFX::paintMaskTransparentWithBrush (destPixmapPtr
,
350 QPoint (destX
, destY
),
356 void kpPixmapFX::ensureOpaqueAt (QPixmap
*destPixmapPtr
, const QRect
&destRect
)
361 KP_PFX_CHECK_NO_ALPHA_CHANNEL (*destPixmapPtr
);
363 // (a bit slow so we cache it)
364 QBitmap maskBitmap
= destPixmapPtr
->mask ();
367 if (maskBitmap
.isNull ())
370 QPainter
p (&maskBitmap
);
371 p
.fillRect (destRect
, Qt::color1
/*opaque*/);
374 destPixmapPtr
->setMask (maskBitmap
);
376 KP_PFX_CHECK_NO_ALPHA_CHANNEL (*destPixmapPtr
);