Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qpaintengine_x11.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 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
4#include <QtCore/qrandom.h>
5
6#include <private/qpixmapcache_p.h>
7#include <private/qpaintengine_p.h>
8#include <private/qpainterpath_p.h>
9#include <private/qdrawhelper_p.h>
10#include <private/qfontengineglyphcache_p.h>
11
12#if QT_CONFIG(fontconfig)
13#include <private/qfontengine_ft_p.h>
14#endif
15
16#include "qpaintengine_x11_p.h"
17#include "qpolygonclipper_p.h"
18#include "qtessellator_p.h"
19#include "qpixmap_x11_p.h"
20#include "qcolormap_x11_p.h"
21#include "qt_x11_p.h"
22#include "qxcbexport.h"
23#include "qxcbnativepainting.h"
24
26
27using namespace Qt::StringLiterals;
28
29#if QT_CONFIG(xrender)
30
31class QXRenderTessellator : public QTessellator
32{
33public:
34 QXRenderTessellator() : traps(0), allocated(0), size(0) {}
35 ~QXRenderTessellator() { free(traps); }
36 XTrapezoid *traps;
37 int allocated;
38 int size;
39 void addTrap(const Trapezoid &trap) override;
40 QRect tessellate(const QPointF *points, int nPoints, bool winding) {
41 size = 0;
42 setWinding(winding);
43 return QTessellator::tessellate(points, nPoints).toRect();
44 }
45 void done() {
46 if (allocated > 64) {
47 free(traps);
48 traps = 0;
49 allocated = 0;
50 }
51 }
52};
53
54void QXRenderTessellator::addTrap(const Trapezoid &trap)
55{
56 if (size == allocated) {
57 allocated = qMax(2*allocated, 64);
58 traps = q_check_ptr((XTrapezoid *)realloc(traps, allocated * sizeof(XTrapezoid)));
59 }
60 traps[size].top = Q27Dot5ToXFixed(trap.top);
61 traps[size].bottom = Q27Dot5ToXFixed(trap.bottom);
62 traps[size].left.p1.x = Q27Dot5ToXFixed(trap.topLeft->x);
63 traps[size].left.p1.y = Q27Dot5ToXFixed(trap.topLeft->y);
64 traps[size].left.p2.x = Q27Dot5ToXFixed(trap.bottomLeft->x);
65 traps[size].left.p2.y = Q27Dot5ToXFixed(trap.bottomLeft->y);
66 traps[size].right.p1.x = Q27Dot5ToXFixed(trap.topRight->x);
67 traps[size].right.p1.y = Q27Dot5ToXFixed(trap.topRight->y);
68 traps[size].right.p2.x = Q27Dot5ToXFixed(trap.bottomRight->x);
69 traps[size].right.p2.y = Q27Dot5ToXFixed(trap.bottomRight->y);
70 ++size;
71}
72
73#endif // QT_CONFIG(xrender)
74
76{
77 Q_DECLARE_PUBLIC(QX11PaintEngine)
78public:
80 {
81 opacity = 1.0;
82 scrn = -1;
83 hd = 0;
84 picture = 0;
85 gc = gc_brush = 0;
86 dpy = 0;
87 xinfo = 0;
88 txop = QTransform::TxNone;
89 has_clipping = false;
90 render_hints = 0;
91 xform_scale = 1;
92#if QT_CONFIG(xrender)
93 tessellator = 0;
94#endif
95 }
96 enum GCMode {
98 BrushGC
99 };
100
101 void init();
102 void fillPolygon_translated(const QPointF *points, int pointCount, GCMode gcMode,
104 void fillPolygon_dev(const QPointF *points, int pointCount, GCMode gcMode,
106 void fillPath(const QPainterPath &path, GCMode gcmode, bool transform);
107 void strokePolygon_dev(const QPointF *points, int pointCount, bool close);
108 void strokePolygon_translated(const QPointF *points, int pointCount, bool close);
109 void setupAdaptedOrigin(const QPoint &p);
110 void resetAdaptedOrigin();
112 use_path_fallback = has_alpha_brush
113 || has_alpha_pen
114 || has_custom_pen
115 || has_complex_xform
116 || (render_hints & QPainter::Antialiasing);
117 }
119 adjust_coords = false;
120 }
121 void clipPolygon_dev(const QPolygonF &poly, QPolygonF *clipped_poly);
122 void systemStateChanged() override;
123 inline bool isCosmeticPen() const {
124 return cpen.isCosmetic();
125 }
126
128 int scrn;
130 unsigned long hd;
132#if QT_CONFIG(xrender)
133 unsigned long picture;
134 unsigned long current_brush;
135 QPixmap bitmap_texture;
136 int composition_mode;
137#else
138 unsigned long picture;
139#endif
142
148
167
172
174 {
176 };
177 QPolygonClipper<qt_float_point, qt_float_point, float> polygonClipper;
178
180#if QT_CONFIG(xrender)
181 QXRenderTessellator *tessellator;
182#endif
183};
184
185#if QT_CONFIG(xrender)
186class QXRenderGlyphCache : public QFontEngineGlyphCache
187{
188public:
189 QXRenderGlyphCache(QXcbX11Info x, QFontEngine::GlyphFormat format, const QTransform &matrix);
190 ~QXRenderGlyphCache();
191
192 bool addGlyphs(const QTextItemInt &ti,
193 const QVarLengthArray<glyph_t> &glyphs,
194 const QVarLengthArray<QFixedPoint> &positions);
195 bool draw(Drawable src, Drawable dst, const QTransform &matrix, const QTextItemInt &ti);
196
197 inline GlyphSet glyphSet();
198 inline int glyphBufferSize(const QFontEngineFT::Glyph &glyph) const;
199
200 inline QImage::Format imageFormat() const;
201 inline const XRenderPictFormat *renderPictFormat() const;
202
203 static inline QFontEngine::GlyphFormat glyphFormatForDepth(QFontEngine *fontEngine, int depth);
204 static inline Glyph glyphId(glyph_t glyph, QFixed subPixelPosition);
205
206 static inline bool isValidCoordinate(const QFixedPoint &fp);
207
208private:
209 QXcbX11Info xinfo;
210 GlyphSet gset;
211 QSet<Glyph> cachedGlyphs;
212};
213#endif // QT_CONFIG(xrender)
214
215extern QPixmap qt_pixmapForBrush(int brushStyle, bool invert); //in qbrush.cpp
216extern QPixmap qt_toX11Pixmap(const QPixmap &pixmap);
217
218extern "C" {
220{
221 if (!pd)
222 return 0;
223
224// if (pd->devType() == QInternal::Widget)
225// return static_cast<const QWidget *>(pd)->handle();
226
227 if (pd->devType() == QInternal::Pixmap)
228 return qt_x11PixmapHandle(*static_cast<const QPixmap *>(pd));
229
230 return 0;
231}
232}
233
234static const QXcbX11Info *qt_x11Info(const QPaintDevice *pd)
235{
236 if (!pd)
237 return 0;
238
239// if (pd->devType() == QInternal::Widget)
240// return &static_cast<const QWidget *>(pd)->x11Info();
241
242 if (pd->devType() == QInternal::Pixmap)
243 return &qt_x11Info(*static_cast<const QPixmap *>(pd));
244
245 return 0;
246}
247
248// use the same rounding as in qrasterizer.cpp (6 bit fixed point)
249static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
250
251#undef X11 // defined in qt_x11_p.h
252extern "C" {
259{
260 if (p && p->paintEngine()
261 && p->paintEngine()->isActive()
262 && p->paintEngine()->type() == QPaintEngine::X11) {
263 return static_cast<QX11PaintEngine *>(p->paintEngine())->d_func()->gc;
264 }
265 return 0;
266}
267
274{
275 if (p && p->paintEngine()
276 && p->paintEngine()->isActive()
277 && p->paintEngine()->type() == QPaintEngine::X11) {
278 return static_cast<QX11PaintEngine *>(p->paintEngine())->d_func()->gc_brush;
279 }
280 return 0;
281}
282}
283#define X11 qt_x11Data
284
285// internal helper. Converts an integer value to an unique string token
286template <typename T>
287 struct HexString
288{
289 inline HexString(const T t)
290 : val(t)
291 {}
292
293 inline void write(QChar *&dest) const
294 {
295 const ushort hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
296 const char *c = reinterpret_cast<const char *>(&val);
297 for (uint i = 0; i < sizeof(T); ++i) {
298 *dest++ = hexChars[*c & 0xf];
299 *dest++ = hexChars[(*c & 0xf0) >> 4];
300 ++c;
301 }
302 }
303 const T val;
304};
305
306// specialization to enable fast concatenating of our string tokens to a string
307template <typename T>
308 struct QConcatenable<HexString<T> >
309{
310 typedef HexString<T> type;
311 enum { ExactSize = true };
312 static int size(const HexString<T> &) { return sizeof(T) * 2; }
313 static inline void appendTo(const HexString<T> &str, QChar *&out) { str.write(out); }
315};
316
317#if QT_CONFIG(xrender)
318static const int compositionModeToRenderOp[QPainter::CompositionMode_Xor + 1] = {
319 PictOpOver, //CompositionMode_SourceOver,
320 PictOpOverReverse, //CompositionMode_DestinationOver,
321 PictOpClear, //CompositionMode_Clear,
322 PictOpSrc, //CompositionMode_Source,
323 PictOpDst, //CompositionMode_Destination,
324 PictOpIn, //CompositionMode_SourceIn,
325 PictOpInReverse, //CompositionMode_DestinationIn,
326 PictOpOut, //CompositionMode_SourceOut,
327 PictOpOutReverse, //CompositionMode_DestinationOut,
328 PictOpAtop, //CompositionMode_SourceAtop,
329 PictOpAtopReverse, //CompositionMode_DestinationAtop,
330 PictOpXor //CompositionMode_Xor
331};
332
333static inline int qpainterOpToXrender(QPainter::CompositionMode mode)
334{
336 return compositionModeToRenderOp[mode];
337}
338
339static inline bool complexPictOp(int op)
340{
341 return op != PictOpOver && op != PictOpSrc;
342}
343#endif
344
345static inline void x11SetClipRegion(Display *dpy, GC gc, GC gc2,
346#if QT_CONFIG(xrender)
348#else
350#endif
351 const QRegion &r)
352{
353// int num;
354// XRectangle *rects = (XRectangle *)qt_getClipRects(r, num);
355 QList<XRectangle> rects = qt_region_to_xrectangles(r);
356 int num = rects.size();
357
358 if (gc)
359 XSetClipRectangles( dpy, gc, 0, 0, rects.data(), num, Unsorted );
360 if (gc2)
361 XSetClipRectangles( dpy, gc2, 0, 0, rects.data(), num, Unsorted );
362
363#if QT_CONFIG(xrender)
364 if (picture)
365 XRenderSetPictureClipRectangles(dpy, picture, 0, 0, rects.data(), num);
366#else
368#endif // QT_CONFIG(xrender)
369}
370
371
372static inline void x11ClearClipRegion(Display *dpy, GC gc, GC gc2,
373#if QT_CONFIG(xrender)
375#else
377#endif
378 )
379{
380 if (gc)
381 XSetClipMask(dpy, gc, XNone);
382 if (gc2)
383 XSetClipMask(dpy, gc2, XNone);
384
385#if QT_CONFIG(xrender)
386 if (picture) {
387 XRenderPictureAttributes attrs;
388 attrs.clip_mask = XNone;
389 XRenderChangePicture (dpy, picture, CPClipMask, &attrs);
390 }
391#else
393#endif // QT_CONFIG(xrender)
394}
395
396
397#define DITHER_SIZE 16
399 { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 },
400 { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
401 { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
402 { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
403 { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 },
404 { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
405 { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
406 { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
407 { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 },
408 { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
409 { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
410 { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
411 { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 },
412 { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
413 { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
414 { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
415};
416
418{
419 QPixmap pm;
420 QString key = "$qt-alpha-brush$"_L1
421 % HexString<uchar>(alpha)
422 % HexString<int>(screen);
423
424 if (!QPixmapCache::find(key, &pm)) {
425 // #### why not use a mono image here????
427 pattern.fill(0xffffffff);
428 for (int y = 0; y < DITHER_SIZE; ++y) {
429 for (int x = 0; x < DITHER_SIZE; ++x) {
430 if (base_dither_matrix[x][y] <= alpha)
431 pattern.setPixel(x, y, 0x00000000);
432 }
433 }
436 //pm.x11SetScreen(screen);
438 }
439 return pm;
440}
441
442
443#if QT_CONFIG(xrender)
444static Picture getPatternFill(int screen, const QBrush &b)
445{
446 if (!X11->use_xrender)
447 return XNone;
448
449 XRenderColor color = X11->preMultiply(b.color());
450 XRenderColor bg_color;
451
452 bg_color = X11->preMultiply(QColor(0, 0, 0, 0));
453
454 for (int i = 0; i < X11->pattern_fill_count; ++i) {
455 if (X11->pattern_fills[i].screen == screen
456 && X11->pattern_fills[i].opaque == false
457 && X11->pattern_fills[i].style == b.style()
458 && X11->pattern_fills[i].color.alpha == color.alpha
459 && X11->pattern_fills[i].color.red == color.red
460 && X11->pattern_fills[i].color.green == color.green
461 && X11->pattern_fills[i].color.blue == color.blue
462 && X11->pattern_fills[i].bg_color.alpha == bg_color.alpha
463 && X11->pattern_fills[i].bg_color.red == bg_color.red
464 && X11->pattern_fills[i].bg_color.green == bg_color.green
465 && X11->pattern_fills[i].bg_color.blue == bg_color.blue)
466 return X11->pattern_fills[i].picture;
467 }
468 // none found, replace one
469 int i = QRandomGenerator::global()->generate() % 16;
470
471 if (X11->pattern_fills[i].screen != screen && X11->pattern_fills[i].picture) {
472 XRenderFreePicture (QXcbX11Info::display(), X11->pattern_fills[i].picture);
473 X11->pattern_fills[i].picture = 0;
474 }
475
476 if (!X11->pattern_fills[i].picture) {
477 Pixmap pixmap = XCreatePixmap (QXcbX11Info::display(), RootWindow (QXcbX11Info::display(), screen), 8, 8, 32);
478 XRenderPictureAttributes attrs;
479 attrs.repeat = True;
480 X11->pattern_fills[i].picture = XRenderCreatePicture (QXcbX11Info::display(), pixmap,
481 XRenderFindStandardFormat(QXcbX11Info::display(), PictStandardARGB32),
482 CPRepeat, &attrs);
483 XFreePixmap (QXcbX11Info::display(), pixmap);
484 }
485
486 X11->pattern_fills[i].screen = screen;
487 X11->pattern_fills[i].color = color;
488 X11->pattern_fills[i].bg_color = bg_color;
489 X11->pattern_fills[i].opaque = false;
490 X11->pattern_fills[i].style = b.style();
491
492 XRenderFillRectangle(QXcbX11Info::display(), PictOpSrc, X11->pattern_fills[i].picture, &bg_color, 0, 0, 8, 8);
493
494 QPixmap pattern(qt_pixmapForBrush(b.style(), true));
495 XRenderPictureAttributes attrs;
496 attrs.repeat = true;
497 XRenderChangePicture(QXcbX11Info::display(), qt_x11PictureHandle(pattern), CPRepeat, &attrs);
498
499 Picture fill_fg = X11->getSolidFill(screen, b.color());
500 XRenderComposite(QXcbX11Info::display(), PictOpOver, fill_fg, qt_x11PictureHandle(pattern),
501 X11->pattern_fills[i].picture,
502 0, 0, 0, 0, 0, 0, 8, 8);
503
504 return X11->pattern_fills[i].picture;
505}
506
507static void qt_render_bitmap(Display *dpy, int scrn, Picture src, Picture dst,
508 int sx, int sy, int x, int y, int sw, int sh,
509 const QPen &pen)
510{
511 Picture fill_fg = X11->getSolidFill(scrn, pen.color());
512 XRenderComposite(dpy, PictOpOver,
513 fill_fg, src, dst, sx, sy, sx, sy, x, y, sw, sh);
514}
515#endif
516
518{
519 dpy = 0;
520 scrn = 0;
521 hd = 0;
522 picture = 0;
523 xinfo = 0;
524#if QT_CONFIG(xrender)
525 current_brush = 0;
526 composition_mode = PictOpOver;
527 tessellator = new QXRenderTessellator;
528#endif
529}
530
532{
533 if (adapted_pen_origin)
534 XSetTSOrigin(dpy, gc, p.x(), p.y());
535 if (adapted_brush_origin)
536 XSetTSOrigin(dpy, gc_brush, p.x(), p.y());
537}
538
540{
541 if (adapted_pen_origin)
542 XSetTSOrigin(dpy, gc, 0, 0);
543 if (adapted_brush_origin)
544 XSetTSOrigin(dpy, gc_brush, 0, 0);
545}
546
548{
549 int clipped_count = 0;
550 qt_float_point *clipped_points = 0;
551 polygonClipper.clipPolygon((qt_float_point *) poly.data(), poly.size(),
552 &clipped_points, &clipped_count);
553 clipped_poly->resize(clipped_count);
554 for (int i=0; i<clipped_count; ++i)
555 (*clipped_poly)[i] = *((QPointF *)(&clipped_points[i]));
556}
557
559{
560 Q_Q(QX11PaintEngine);
561 QPainter *painter = q->state ? q->state->painter() : nullptr;
562 if (painter && painter->hasClipping()) {
563 if (q->testDirty(QPaintEngine::DirtyTransform))
564 q->updateMatrix(q->state->transform());
565 QPolygonF clip_poly_dev(matrix.map(painter->clipPath().toFillPolygon()));
566 QPolygonF clipped_poly_dev;
567 clipPolygon_dev(clip_poly_dev, &clipped_poly_dev);
568 q->updateClipRegion_dev(QRegion(clipped_poly_dev.toPolygon()), Qt::ReplaceClip);
569 } else {
570 q->updateClipRegion_dev(QRegion(), Qt::NoClip);
571 }
572}
573
574static QPaintEngine::PaintEngineFeatures qt_decide_features()
575{
576 QPaintEngine::PaintEngineFeatures features =
582
583 if (X11->use_xrender) {
584 features |= QPaintEngine::Antialiasing;
585 features |= QPaintEngine::PorterDuff;
586 features |= QPaintEngine::MaskedBrush;
587#if 0
588 if (X11->xrender_version > 10) {
590 // ###
591 }
592#endif
593 }
594
595 return features;
596}
597
598/*
599 * QX11PaintEngine members
600 */
601
608
615
617{
618#if QT_CONFIG(xrender)
619 Q_D(QX11PaintEngine);
620 delete d->tessellator;
621#endif
622}
623
625{
626 Q_D(QX11PaintEngine);
627 d->xinfo = qt_x11Info(pdev);
628#if QT_CONFIG(xrender)
629 if (pdev->devType() == QInternal::Pixmap) {
630 const QPixmap *pm = static_cast<const QPixmap *>(pdev);
631 QX11PlatformPixmap *data = static_cast<QX11PlatformPixmap*>(pm->handle());
632 if (X11->use_xrender && data->depth() != 32 && data->x11_mask)
633 data->convertToARGB32();
634 d->picture = qt_x11PictureHandle(*static_cast<const QPixmap *>(pdev));
635 }
636#else
637 d->picture = 0;
638#endif
639 d->hd = qt_x11Handle(pdev);
640
641 Q_ASSERT(d->xinfo != 0);
642 d->dpy = d->xinfo->display(); // get display variable
643 d->scrn = d->xinfo->screen(); // get screen variable
644
645 d->crgn = QRegion();
646 d->gc = XCreateGC(d->dpy, d->hd, 0, 0);
647 d->gc_brush = XCreateGC(d->dpy, d->hd, 0, 0);
648 d->has_alpha_brush = false;
649 d->has_alpha_pen = false;
650 d->has_clipping = false;
651 d->has_complex_xform = false;
652 d->has_scaling_xform = false;
653 d->has_non_scaling_xform = true;
654 d->xform_scale = 1;
655 d->has_custom_pen = false;
656 d->matrix = QTransform();
657 d->pdev_depth = d->pdev->depth();
658 d->render_hints = 0;
659 d->txop = QTransform::TxNone;
660 d->use_path_fallback = false;
661#if QT_CONFIG(xrender)
662 d->composition_mode = PictOpOver;
663#endif
664 d->xlibMaxLinePoints = 32762; // a safe number used to avoid, call to XMaxRequestSize(d->dpy) - 3;
665 d->opacity = 1;
666
667 QX11PlatformPixmap *x11pm = paintDevice()->devType() == QInternal::Pixmap ? qt_x11Pixmap(*static_cast<QPixmap *>(paintDevice())) : nullptr;
668 d->use_sysclip = paintDevice()->devType() == QInternal::Widget || (x11pm ? x11pm->isBackingStore() : false);
669
670 // Set up the polygon clipper. Note: This will only work in
671 // polyline mode as long as we have a buffer zone, since a
672 // polyline may be clipped into several non-connected polylines.
673 const int BUFFERZONE = 1000;
674 QRect devClipRect(-BUFFERZONE, -BUFFERZONE,
675 pdev->width() + 2*BUFFERZONE, pdev->height() + 2*BUFFERZONE);
676 d->polygonClipper.setBoundingRect(devClipRect);
677
679 d->systemStateChanged();
680
681 qt_x11SetDefaultScreen(d->xinfo->screen());
682
685
690
691 setActive(true);
692 return true;
693}
694
696{
697 Q_D(QX11PaintEngine);
698
699#if QT_CONFIG(xrender)
700 if (d->picture) {
701 // reset clipping/subwindow mode on our render picture
702 XRenderPictureAttributes attrs;
703 attrs.subwindow_mode = ClipByChildren;
704 attrs.clip_mask = XNone;
705 XRenderChangePicture(d->dpy, d->picture, CPClipMask|CPSubwindowMode, &attrs);
706 }
707#endif
708
709 if (d->gc_brush && d->pdev->painters < 2) {
710 XFreeGC(d->dpy, d->gc_brush);
711 d->gc_brush = 0;
712 }
713
714 if (d->gc && d->pdev->painters < 2) {
715 XFreeGC(d->dpy, d->gc);
716 d->gc = 0;
717 }
718
719 // Restore system clip for alien widgets painting outside the paint event.
720// if (d->pdev->devType() == QInternal::Widget && !static_cast<QWidget *>(d->pdev)->internalWinId())
721 d->currentClipDevice = nullptr;
723
724 setActive(false);
725 return true;
726}
727
728static bool clipLine(QLineF *line, const QRect &rect)
729{
730 qreal x1 = line->x1();
731 qreal x2 = line->x2();
732 qreal y1 = line->y1();
733 qreal y2 = line->y2();
734
735 qreal left = rect.x();
736 qreal right = rect.x() + rect.width() - 1;
737 qreal top = rect.y();
738 qreal bottom = rect.y() + rect.height() - 1;
739
740 enum { Left, Right, Top, Bottom };
741 // clip the lines, after cohen-sutherland, see e.g. http://www.nondot.org/~sabre/graphpro/line6.html
742 int p1 = ((x1 < left) << Left)
743 | ((x1 > right) << Right)
744 | ((y1 < top) << Top)
745 | ((y1 > bottom) << Bottom);
746 int p2 = ((x2 < left) << Left)
747 | ((x2 > right) << Right)
748 | ((y2 < top) << Top)
749 | ((y2 > bottom) << Bottom);
750
751 if (p1 & p2)
752 // completely outside
753 return false;
754
755 if (p1 | p2) {
756 qreal dx = x2 - x1;
757 qreal dy = y2 - y1;
758
759 // clip x coordinates
760 if (x1 < left) {
761 y1 += dy/dx * (left - x1);
762 x1 = left;
763 } else if (x1 > right) {
764 y1 -= dy/dx * (x1 - right);
765 x1 = right;
766 }
767 if (x2 < left) {
768 y2 += dy/dx * (left - x2);
769 x2 = left;
770 } else if (x2 > right) {
771 y2 -= dy/dx * (x2 - right);
772 x2 = right;
773 }
774 p1 = ((y1 < top) << Top)
775 | ((y1 > bottom) << Bottom);
776 p2 = ((y2 < top) << Top)
777 | ((y2 > bottom) << Bottom);
778 if (p1 & p2)
779 return false;
780 // clip y coordinates
781 if (y1 < top) {
782 x1 += dx/dy * (top - y1);
783 y1 = top;
784 } else if (y1 > bottom) {
785 x1 -= dx/dy * (y1 - bottom);
786 y1 = bottom;
787 }
788 if (y2 < top) {
789 x2 += dx/dy * (top - y2);
790 y2 = top;
791 } else if (y2 > bottom) {
792 x2 -= dx/dy * (y2 - bottom);
793 y2 = bottom;
794 }
795 *line = QLineF(QPointF(x1, y1), QPointF(x2, y2));
796 }
797 return true;
798}
799
800void QX11PaintEngine::drawLines(const QLine *lines, int lineCount)
801{
802 Q_ASSERT(lines);
803 Q_ASSERT(lineCount);
804 Q_D(QX11PaintEngine);
805
806 if (d->has_alpha_brush
807 || d->has_alpha_pen
808 || d->has_custom_pen
809 || (d->cpen.widthF() > 0 && d->has_complex_xform
810 && !d->has_non_scaling_xform)
811 || (d->render_hints & QPainter::Antialiasing)) {
812 for (int i = 0; i < lineCount; ++i) {
813 QPainterPath path(lines[i].p1());
814 path.lineTo(lines[i].p2());
815 drawPath(path);
816 }
817 return;
818 }
819
820 if (d->has_pen) {
821 for (int i = 0; i < lineCount; ++i) {
822 QLineF linef;
823 if (d->txop == QTransform::TxNone) {
824 linef = lines[i];
825 } else {
826 linef = d->matrix.map(QLineF(lines[i]));
827 }
828 if (clipLine(&linef, d->polygonClipper.boundingRect())) {
829 int x1 = qRound(linef.x1() + aliasedCoordinateDelta);
830 int y1 = qRound(linef.y1() + aliasedCoordinateDelta);
831 int x2 = qRound(linef.x2() + aliasedCoordinateDelta);
832 int y2 = qRound(linef.y2() + aliasedCoordinateDelta);
833
834 XDrawLine(d->dpy, d->hd, d->gc, x1, y1, x2, y2);
835 }
836 }
837 }
838}
839
840void QX11PaintEngine::drawLines(const QLineF *lines, int lineCount)
841{
842 Q_ASSERT(lines);
843 Q_ASSERT(lineCount);
844 Q_D(QX11PaintEngine);
845
846 if (d->has_alpha_brush
847 || d->has_alpha_pen
848 || d->has_custom_pen
849 || (d->cpen.widthF() > 0 && d->has_complex_xform
850 && !d->has_non_scaling_xform)
851 || (d->render_hints & QPainter::Antialiasing)) {
852 for (int i = 0; i < lineCount; ++i) {
853 QPainterPath path(lines[i].p1());
854 path.lineTo(lines[i].p2());
855 drawPath(path);
856 }
857 return;
858 }
859
860 if (d->has_pen) {
861 for (int i = 0; i < lineCount; ++i) {
862 QLineF linef = d->matrix.map(lines[i]);
863 if (clipLine(&linef, d->polygonClipper.boundingRect())) {
864 int x1 = qRound(linef.x1() + aliasedCoordinateDelta);
865 int y1 = qRound(linef.y1() + aliasedCoordinateDelta);
866 int x2 = qRound(linef.x2() + aliasedCoordinateDelta);
867 int y2 = qRound(linef.y2() + aliasedCoordinateDelta);
868
869 XDrawLine(d->dpy, d->hd, d->gc, x1, y1, x2, y2);
870 }
871 }
872 }
873}
874
875static inline QLine clipStraightLine(const QRect &clip, const QLine &l)
876{
877 if (l.p1().x() == l.p2().x()) {
878 int x = qBound(clip.left(), l.p1().x(), clip.right());
879 int y1 = qBound(clip.top(), l.p1().y(), clip.bottom());
880 int y2 = qBound(clip.top(), l.p2().y(), clip.bottom());
881
882 return QLine(x, y1, x, y2);
883 } else {
884 Q_ASSERT(l.p1().y() == l.p2().y());
885
886 int x1 = qBound(clip.left(), l.p1().x(), clip.right());
887 int x2 = qBound(clip.left(), l.p2().x(), clip.right());
888 int y = qBound(clip.top(), l.p1().y(), clip.bottom());
889
890 return QLine(x1, y, x2, y);
891 }
892}
893
894void QX11PaintEngine::drawRects(const QRectF *rects, int rectCount)
895{
896 Q_D(QX11PaintEngine);
897 Q_ASSERT(rects);
898 Q_ASSERT(rectCount);
899
900 if (rectCount != 1
901 || d->has_pen
902 || d->has_alpha_brush
903 || d->has_complex_xform
904 || d->has_custom_pen
905 || d->cbrush.style() != Qt::SolidPattern
906#if QT_CONFIG(xrender)
907 || complexPictOp(d->composition_mode)
908#endif
909 )
910 {
911 QPaintEngine::drawRects(rects, rectCount);
912 return;
913 }
914
915 QPoint alignedOffset;
916 if (d->txop == QTransform::TxTranslate) {
917 QPointF offset(d->matrix.dx(), d->matrix.dy());
918 alignedOffset = offset.toPoint();
919 if (offset != QPointF(alignedOffset)) {
920 QPaintEngine::drawRects(rects, rectCount);
921 return;
922 }
923 }
924
925 const QRectF& r = rects[0];
926 QRect alignedRect = r.toAlignedRect();
927 if (r != QRectF(alignedRect)) {
928 QPaintEngine::drawRects(rects, rectCount);
929 return;
930 }
931 alignedRect.translate(alignedOffset);
932
933 QRect clip(d->polygonClipper.boundingRect());
934 alignedRect = alignedRect.intersected(clip);
935 if (alignedRect.isEmpty())
936 return;
937
938 // simple-case:
939 // the rectangle is pixel-aligned
940 // the fill brush is just a solid non-alpha color
941 // the painter transform is only integer translation
942 // ignore: antialiasing and just XFillRectangles directly
943 XRectangle xrect;
944 xrect.x = short(alignedRect.x());
945 xrect.y = short(alignedRect.y());
946 xrect.width = ushort(alignedRect.width());
947 xrect.height = ushort(alignedRect.height());
948 XFillRectangles(d->dpy, d->hd, d->gc_brush, &xrect, 1);
949}
950
951void QX11PaintEngine::drawRects(const QRect *rects, int rectCount)
952{
953 Q_D(QX11PaintEngine);
954 Q_ASSERT(rects);
955 Q_ASSERT(rectCount);
956
957 if (d->has_alpha_pen
958 || d->has_complex_xform
959 || d->has_custom_pen
960 || (d->render_hints & QPainter::Antialiasing))
961 {
962 for (int i = 0; i < rectCount; ++i) {
964 path.addRect(rects[i]);
965 drawPath(path);
966 }
967 return;
968 }
969
970 QRect clip(d->polygonClipper.boundingRect());
971 QPoint offset(qRound(d->matrix.dx()), qRound(d->matrix.dy()));
972#if QT_CONFIG(xrender)
973 ::Picture pict = d->picture;
974
975 if (X11->use_xrender && pict && d->has_brush && d->pdev_depth != 1
976 && (d->has_texture || d->has_alpha_brush || complexPictOp(d->composition_mode)))
977 {
978 XRenderColor xc;
979 if (!d->has_texture && !d->has_pattern)
980 xc = X11->preMultiply(d->cbrush.color());
981
982 for (int i = 0; i < rectCount; ++i) {
983 QRect r(rects[i]);
984 if (d->txop == QTransform::TxTranslate)
985 r.translate(offset);
986
987 if (r.width() == 0 || r.height() == 0) {
988 if (d->has_pen) {
989 const QLine l = clipStraightLine(clip, QLine(r.left(), r.top(), r.left() + r.width(), r.top() + r.height()));
990 XDrawLine(d->dpy, d->hd, d->gc, l.p1().x(), l.p1().y(), l.p2().x(), l.p2().y());
991 }
992 continue;
993 }
994
995 r = r.intersected(clip);
996 if (r.isEmpty())
997 continue;
998 if (d->has_texture || d->has_pattern) {
999 XRenderComposite(d->dpy, d->composition_mode, d->current_brush, 0, pict,
1000 qRound(r.x() - d->bg_origin.x()), qRound(r.y() - d->bg_origin.y()),
1001 0, 0, r.x(), r.y(), r.width(), r.height());
1002 } else {
1003 XRenderFillRectangle(d->dpy, d->composition_mode, pict, &xc, r.x(), r.y(), r.width(), r.height());
1004 }
1005 if (d->has_pen)
1006 XDrawRectangle(d->dpy, d->hd, d->gc, r.x(), r.y(), r.width(), r.height());
1007 }
1008 } else
1009#endif // QT_CONFIG(xrender)
1010 {
1011 if (d->has_brush && d->has_pen) {
1012 for (int i = 0; i < rectCount; ++i) {
1013 QRect r(rects[i]);
1014 if (d->txop == QTransform::TxTranslate)
1015 r.translate(offset);
1016
1017 if (r.width() == 0 || r.height() == 0) {
1018 const QLine l = clipStraightLine(clip, QLine(r.left(), r.top(), r.left() + r.width(), r.top() + r.height()));
1019 XDrawLine(d->dpy, d->hd, d->gc, l.p1().x(), l.p1().y(), l.p2().x(), l.p2().y());
1020 continue;
1021 }
1022
1023 r = r.intersected(clip);
1024 if (r.isEmpty())
1025 continue;
1026 d->setupAdaptedOrigin(r.topLeft());
1027 XFillRectangle(d->dpy, d->hd, d->gc_brush, r.x(), r.y(), r.width(), r.height());
1028 XDrawRectangle(d->dpy, d->hd, d->gc, r.x(), r.y(), r.width(), r.height());
1029 }
1030 d->resetAdaptedOrigin();
1031 } else {
1032 QVarLengthArray<XRectangle> xrects(rectCount);
1033 int numClipped = rectCount;
1034 for (int i = 0; i < rectCount; ++i) {
1035 QRect r(rects[i]);
1036 if (d->txop == QTransform::TxTranslate)
1037 r.translate(offset);
1038
1039 if (r.width() == 0 || r.height() == 0) {
1040 --numClipped;
1041 if (d->has_pen) {
1042 const QLine l = clipStraightLine(clip, QLine(r.left(), r.top(), r.left() + r.width(), r.top() + r.height()));
1043 XDrawLine(d->dpy, d->hd, d->gc, l.p1().x(), l.p1().y(), l.p2().x(), l.p2().y());
1044 }
1045 continue;
1046 }
1047
1048 r = r.intersected(clip);
1049 if (r.isEmpty()) {
1050 --numClipped;
1051 continue;
1052 }
1053 xrects[i].x = short(r.x());
1054 xrects[i].y = short(r.y());
1055 xrects[i].width = ushort(r.width());
1056 xrects[i].height = ushort(r.height());
1057 }
1058 if (numClipped) {
1059 d->setupAdaptedOrigin(rects[0].topLeft());
1060 if (d->has_brush)
1061 XFillRectangles(d->dpy, d->hd, d->gc_brush, xrects.data(), numClipped);
1062 else if (d->has_pen)
1063 XDrawRectangles(d->dpy, d->hd, d->gc, xrects.data(), numClipped);
1064 d->resetAdaptedOrigin();
1065 }
1066 }
1067 }
1068}
1069
1070static inline void setCapStyle(int cap_style, GC gc)
1071{
1072 ulong mask = GCCapStyle;
1073 XGCValues vals;
1074 vals.cap_style = cap_style;
1075 XChangeGC(QXcbX11Info::display(), gc, mask, &vals);
1076}
1077
1078void QX11PaintEngine::drawPoints(const QPoint *points, int pointCount)
1079{
1081 Q_ASSERT(pointCount);
1082 Q_D(QX11PaintEngine);
1083
1084 if (!d->has_pen)
1085 return;
1086
1087 // use the same test here as in drawPath to ensure that we don't use the path fallback
1088 // and end up in XDrawLines for pens with width <= 1
1089 if (d->cpen.widthF() > 1.0f
1090 || (X11->use_xrender && (d->has_alpha_pen || (d->render_hints & QPainter::Antialiasing)))
1091 || (!d->isCosmeticPen() && d->txop > QTransform::TxTranslate))
1092 {
1093 Qt::PenCapStyle capStyle = d->cpen.capStyle();
1094 if (capStyle == Qt::FlatCap) {
1095 setCapStyle(CapProjecting, d->gc);
1096 d->cpen.setCapStyle(Qt::SquareCap);
1097 }
1098 const QPoint *end = points + pointCount;
1099 while (points < end) {
1101 path.moveTo(*points);
1102 path.lineTo(points->x()+.005, points->y());
1103 drawPath(path);
1104 ++points;
1105 }
1106
1107 if (capStyle == Qt::FlatCap) {
1108 setCapStyle(CapButt, d->gc);
1109 d->cpen.setCapStyle(capStyle);
1110 }
1111 return;
1112 }
1113
1114 static const int BUF_SIZE = 1024;
1115 XPoint xPoints[BUF_SIZE];
1116 int i = 0, j = 0;
1117 while (i < pointCount) {
1118 while (i < pointCount && j < BUF_SIZE) {
1119 const QPoint &xformed = d->matrix.map(points[i]);
1120 int x = xformed.x();
1121 int y = xformed.y();
1122 if (x >= SHRT_MIN && y >= SHRT_MIN && x < SHRT_MAX && y < SHRT_MAX) {
1123 xPoints[j].x = x;
1124 xPoints[j].y = y;
1125 ++j;
1126 }
1127 ++i;
1128 }
1129 if (j)
1130 XDrawPoints(d->dpy, d->hd, d->gc, xPoints, j, CoordModeOrigin);
1131
1132 j = 0;
1133 }
1134}
1135
1136void QX11PaintEngine::drawPoints(const QPointF *points, int pointCount)
1137{
1139 Q_ASSERT(pointCount);
1140 Q_D(QX11PaintEngine);
1141
1142 if (!d->has_pen)
1143 return;
1144
1145 // use the same test here as in drawPath to ensure that we don't use the path fallback
1146 // and end up in XDrawLines for pens with width <= 1
1147 if (d->cpen.widthF() > 1.0f
1148 || (X11->use_xrender && (d->has_alpha_pen || (d->render_hints & QPainter::Antialiasing)))
1149 || (!d->isCosmeticPen() && d->txop > QTransform::TxTranslate))
1150 {
1151 Qt::PenCapStyle capStyle = d->cpen.capStyle();
1152 if (capStyle == Qt::FlatCap) {
1153 setCapStyle(CapProjecting, d->gc);
1154 d->cpen.setCapStyle(Qt::SquareCap);
1155 }
1156
1157 const QPointF *end = points + pointCount;
1158 while (points < end) {
1160 path.moveTo(*points);
1161 path.lineTo(points->x() + 0.005, points->y());
1162 drawPath(path);
1163 ++points;
1164 }
1165 if (capStyle == Qt::FlatCap) {
1166 setCapStyle(CapButt, d->gc);
1167 d->cpen.setCapStyle(capStyle);
1168 }
1169 return;
1170 }
1171
1172 static const int BUF_SIZE = 1024;
1173 XPoint xPoints[BUF_SIZE];
1174 int i = 0, j = 0;
1175 while (i < pointCount) {
1176 while (i < pointCount && j < BUF_SIZE) {
1177 const QPointF &xformed = d->matrix.map(points[i]);
1178 int x = qFloor(xformed.x());
1179 int y = qFloor(xformed.y());
1180
1181 if (x >= SHRT_MIN && y >= SHRT_MIN && x < SHRT_MAX && y < SHRT_MAX) {
1182 xPoints[j].x = x;
1183 xPoints[j].y = y;
1184 ++j;
1185 }
1186 ++i;
1187 }
1188 if (j)
1189 XDrawPoints(d->dpy, d->hd, d->gc, xPoints, j, CoordModeOrigin);
1190
1191 j = 0;
1192 }
1193}
1194
1195QPainter::RenderHints QX11PaintEngine::supportedRenderHints() const
1196{
1197#if QT_CONFIG(xrender)
1198 if (X11->use_xrender)
1200#endif
1201 return QFlag(0);
1202}
1203
1205{
1206 Q_D(QX11PaintEngine);
1207 QPaintEngine::DirtyFlags flags = state.state();
1208
1209
1210 if (flags & DirtyOpacity) {
1211 d->opacity = state.opacity();
1212 // Force update pen/brush as to get proper alpha colors propagated
1213 flags |= DirtyPen;
1214 flags |= DirtyBrush;
1215 }
1216
1218 if (flags & DirtyPen) updatePen(state.pen());
1221
1222 if (state.state() & DirtyClipEnabled) {
1223 if (state.isClipEnabled()) {
1224 QPolygonF clip_poly_dev(d->matrix.map(painter()->clipPath().toFillPolygon()));
1225 QPolygonF clipped_poly_dev;
1226 d->clipPolygon_dev(clip_poly_dev, &clipped_poly_dev);
1227 updateClipRegion_dev(QRegion(clipped_poly_dev.toPolygon()), Qt::ReplaceClip);
1228 } else {
1230 }
1231 }
1232
1233 if (flags & DirtyClipPath) {
1234 QPolygonF clip_poly_dev(d->matrix.map(state.clipPath().toFillPolygon()));
1235 QPolygonF clipped_poly_dev;
1236 d->clipPolygon_dev(clip_poly_dev, &clipped_poly_dev);
1237 updateClipRegion_dev(QRegion(clipped_poly_dev.toPolygon(), state.clipPath().fillRule()),
1239 } else if (flags & DirtyClipRegion) {
1240 extern QPainterPath qt_regionToPath(const QRegion &region);
1242 QPolygonF clip_poly_dev(d->matrix.map(clip_path.toFillPolygon()));
1243 QPolygonF clipped_poly_dev;
1244 d->clipPolygon_dev(clip_poly_dev, &clipped_poly_dev);
1245 updateClipRegion_dev(QRegion(clipped_poly_dev.toPolygon()), state.clipOperation());
1246 }
1249 int function = GXcopy;
1251 switch (state.compositionMode()) {
1253 function = GXor;
1254 break;
1256 function = GXand;
1257 break;
1259 function = GXxor;
1260 break;
1262 function = GXnor;
1263 break;
1265 function = GXnand;
1266 break;
1268 function = GXequiv;
1269 break;
1271 function = GXcopyInverted;
1272 break;
1274 function = GXandReverse;
1275 break;
1277 function = GXandInverted;
1278 break;
1279 default:
1280 function = GXcopy;
1281 }
1282 }
1283#if QT_CONFIG(xrender)
1284 else {
1285 d->composition_mode =
1286 qpainterOpToXrender(state.compositionMode());
1287 }
1288#endif
1289 XSetFunction(X11->display, d->gc, function);
1290 XSetFunction(X11->display, d->gc_brush, function);
1291 }
1292 d->decidePathFallback();
1293 d->decideCoordAdjust();
1294}
1295
1296void QX11PaintEngine::updateRenderHints(QPainter::RenderHints hints)
1297{
1298 Q_D(QX11PaintEngine);
1299 d->render_hints = hints;
1300
1301#if QT_CONFIG(xrender)
1302 if (X11->use_xrender && d->picture) {
1303 XRenderPictureAttributes attrs;
1304 attrs.poly_edge = (hints & QPainter::Antialiasing) ? PolyEdgeSmooth : PolyEdgeSharp;
1305 XRenderChangePicture(d->dpy, d->picture, CPPolyEdge, &attrs);
1306 }
1307#endif
1308}
1309
1311{
1312 Q_D(QX11PaintEngine);
1313 d->cpen = pen;
1314 int cp = CapButt;
1315 int jn = JoinMiter;
1316 int ps = pen.style();
1317
1318 if (d->opacity < 1.0) {
1319 QColor c = d->cpen.color();
1320 c.setAlpha(qRound(c.alpha()*d->opacity));
1321 d->cpen.setColor(c);
1322 }
1323
1324 d->has_pen = (ps != Qt::NoPen);
1325 d->has_alpha_pen = (pen.color().alpha() != 255);
1326
1327 switch (pen.capStyle()) {
1328 case Qt::SquareCap:
1329 cp = CapProjecting;
1330 break;
1331 case Qt::RoundCap:
1332 cp = CapRound;
1333 break;
1334 case Qt::FlatCap:
1335 default:
1336 cp = CapButt;
1337 break;
1338 }
1339 switch (pen.joinStyle()) {
1340 case Qt::BevelJoin:
1341 jn = JoinBevel;
1342 break;
1343 case Qt::RoundJoin:
1344 jn = JoinRound;
1345 break;
1346 case Qt::MiterJoin:
1347 default:
1348 jn = JoinMiter;
1349 break;
1350 }
1351
1352 d->adapted_pen_origin = false;
1353
1354 char dashes[10]; // custom pen dashes
1355 int dash_len = 0; // length of dash list
1356 int xStyle = LineSolid;
1357
1358 /*
1359 We are emulating Windows here. Windows treats cpen.width() == 1
1360 (or 0) as a very special case. The fudge variable unifies this
1361 case with the general case.
1362 */
1363 qreal pen_width = pen.widthF();
1364 int scale = qRound(pen_width < 1 ? 1 : pen_width);
1365 int space = (pen_width < 1 && pen_width > 0 ? 1 : (2 * scale));
1366 int dot = 1 * scale;
1367 int dash = 4 * scale;
1368
1369 d->has_custom_pen = false;
1370
1371 switch (ps) {
1372 case Qt::NoPen:
1373 case Qt::SolidLine:
1374 xStyle = LineSolid;
1375 break;
1376 case Qt::DashLine:
1377 dashes[0] = dash;
1378 dashes[1] = space;
1379 dash_len = 2;
1380 xStyle = LineOnOffDash;
1381 break;
1382 case Qt::DotLine:
1383 dashes[0] = dot;
1384 dashes[1] = space;
1385 dash_len = 2;
1386 xStyle = LineOnOffDash;
1387 break;
1388 case Qt::DashDotLine:
1389 dashes[0] = dash;
1390 dashes[1] = space;
1391 dashes[2] = dot;
1392 dashes[3] = space;
1393 dash_len = 4;
1394 xStyle = LineOnOffDash;
1395 break;
1396 case Qt::DashDotDotLine:
1397 dashes[0] = dash;
1398 dashes[1] = space;
1399 dashes[2] = dot;
1400 dashes[3] = space;
1401 dashes[4] = dot;
1402 dashes[5] = space;
1403 dash_len = 6;
1404 xStyle = LineOnOffDash;
1405 break;
1406 case Qt::CustomDashLine:
1407 d->has_custom_pen = true;
1408 break;
1409 }
1410
1411 ulong mask = GCForeground | GCBackground | GCGraphicsExposures | GCLineWidth
1412 | GCCapStyle | GCJoinStyle | GCLineStyle;
1413 XGCValues vals;
1414 vals.graphics_exposures = false;
1415 if (d->pdev_depth == 1) {
1416 vals.foreground = qGray(pen.color().rgb()) > 127 ? 0 : 1;
1417 vals.background = qGray(QColor(Qt::transparent).rgb()) > 127 ? 0 : 1;
1418 } else if (d->pdev->devType() == QInternal::Pixmap && d->pdev_depth == 32
1419 && X11->use_xrender) {
1420 vals.foreground = pen.color().rgba();
1421 vals.background = QColor(Qt::transparent).rgba();
1422 } else {
1424 vals.foreground = cmap.pixel(pen.color());
1425 vals.background = cmap.pixel(QColor(Qt::transparent));
1426 }
1427
1428
1429 vals.line_width = qRound(pen.widthF());
1430 vals.cap_style = cp;
1431 vals.join_style = jn;
1432 vals.line_style = xStyle;
1433
1434 XChangeGC(d->dpy, d->gc, mask, &vals);
1435
1436 if (dash_len) { // make dash list
1437 XSetDashes(d->dpy, d->gc, 0, dashes, dash_len);
1438 }
1439
1440 if (!d->has_clipping) { // if clipping is set the paintevent clip region is merged with the clip region
1441 QRegion sysClip = d->use_sysclip ? systemClip() : QRegion();
1442 if (!sysClip.isEmpty())
1443 x11SetClipRegion(d->dpy, d->gc, 0, d->picture, sysClip);
1444 else
1445 x11ClearClipRegion(d->dpy, d->gc, 0, d->picture);
1446 }
1447}
1448
1450{
1451 Q_D(QX11PaintEngine);
1452 d->cbrush = brush;
1453 d->bg_origin = origin;
1454 d->adapted_brush_origin = false;
1455#if QT_CONFIG(xrender)
1456 d->current_brush = 0;
1457#endif
1458 if (d->opacity < 1.0) {
1459 QColor c = d->cbrush.color();
1460 c.setAlpha(qRound(c.alpha()*d->opacity));
1461 d->cbrush.setColor(c);
1462 }
1463
1464 int s = FillSolid;
1465 int bs = d->cbrush.style();
1466 d->has_brush = (bs != Qt::NoBrush);
1467 d->has_pattern = bs >= Qt::Dense1Pattern && bs <= Qt::DiagCrossPattern;
1468 d->has_texture = bs == Qt::TexturePattern;
1469 d->has_alpha_brush = brush.color().alpha() != 255;
1470 d->has_alpha_texture = d->has_texture && d->cbrush.texture().hasAlphaChannel();
1471
1472 ulong mask = GCForeground | GCBackground | GCGraphicsExposures
1473 | GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle;
1474 XGCValues vals;
1475 vals.graphics_exposures = false;
1476 if (d->pdev_depth == 1) {
1477 vals.foreground = qGray(d->cbrush.color().rgb()) > 127 ? 0 : 1;
1478 vals.background = qGray(QColor(Qt::transparent).rgb()) > 127 ? 0 : 1;
1479 } else if (X11->use_xrender && d->pdev->devType() == QInternal::Pixmap
1480 && d->pdev_depth == 32) {
1481 vals.foreground = d->cbrush.color().rgba();
1482 vals.background = QColor(Qt::transparent).rgba();
1483 } else {
1485 vals.foreground = cmap.pixel(d->cbrush.color());
1486 vals.background = cmap.pixel(QColor(Qt::transparent));
1487
1488 if (!X11->use_xrender && d->has_brush && !d->has_pattern && !brush.isOpaque()) {
1489 QPixmap pattern = qt_patternForAlpha(brush.color().alpha(), d->scrn);
1490 mask |= GCStipple;
1491 vals.stipple = qt_x11PixmapHandle(pattern);
1492 s = FillStippled;
1493 d->adapted_brush_origin = true;
1494 }
1495 }
1496 vals.cap_style = CapButt;
1497 vals.join_style = JoinMiter;
1498 vals.line_style = LineSolid;
1499
1500 if (d->has_pattern || d->has_texture) {
1501 if (bs == Qt::TexturePattern) {
1502 d->brush_pm = qt_toX11Pixmap(d->cbrush.texture());
1503#if QT_CONFIG(xrender)
1504 if (X11->use_xrender) {
1505 XRenderPictureAttributes attrs;
1506 attrs.repeat = true;
1507 XRenderChangePicture(d->dpy, qt_x11PictureHandle(d->brush_pm), CPRepeat, &attrs);
1508 QX11PlatformPixmap *data = static_cast<QX11PlatformPixmap*>(d->brush_pm.handle());
1509 if (data->mask_picture)
1510 XRenderChangePicture(d->dpy, data->mask_picture, CPRepeat, &attrs);
1511 }
1512#endif
1513 } else {
1514 d->brush_pm = qt_toX11Pixmap(qt_pixmapForBrush(bs, true));
1515 }
1516 qt_x11SetScreen(d->brush_pm, d->scrn);
1517 if (d->brush_pm.depth() == 1) {
1518 mask |= GCStipple;
1519 vals.stipple = qt_x11PixmapHandle(d->brush_pm);
1520 s = FillStippled;
1521#if QT_CONFIG(xrender)
1522 if (X11->use_xrender) {
1523 d->bitmap_texture = QPixmap(d->brush_pm.size());
1524 d->bitmap_texture.fill(Qt::transparent);
1525 d->bitmap_texture = qt_toX11Pixmap(d->bitmap_texture);
1526 qt_x11SetScreen(d->bitmap_texture, d->scrn);
1527
1528 ::Picture src = X11->getSolidFill(d->scrn, d->cbrush.color());
1529 XRenderComposite(d->dpy, PictOpSrc, src, qt_x11PictureHandle(d->brush_pm),
1530 qt_x11PictureHandle(d->bitmap_texture),
1531 0, 0, d->brush_pm.width(), d->brush_pm.height(),
1532 0, 0, d->brush_pm.width(), d->brush_pm.height());
1533
1534 XRenderPictureAttributes attrs;
1535 attrs.repeat = true;
1536 XRenderChangePicture(d->dpy, qt_x11PictureHandle(d->bitmap_texture), CPRepeat, &attrs);
1537
1538 d->current_brush = qt_x11PictureHandle(d->bitmap_texture);
1539 }
1540#endif
1541 } else {
1542 mask |= GCTile;
1543#if QT_CONFIG(xrender)
1544 if (d->pdev_depth == 32 && d->brush_pm.depth() != 32) {
1545 d->brush_pm.detach();
1546 QX11PlatformPixmap *brushData = static_cast<QX11PlatformPixmap*>(d->brush_pm.handle());
1547 brushData->convertToARGB32();
1548 }
1549#endif
1550 vals.tile = (d->brush_pm.depth() == d->pdev_depth
1551 ? qt_x11PixmapHandle(d->brush_pm)
1552 : static_cast<QX11PlatformPixmap*>(d->brush_pm.handle())->x11ConvertToDefaultDepth());
1553 s = FillTiled;
1554#if QT_CONFIG(xrender)
1555 d->current_brush = qt_x11PictureHandle(d->cbrush.texture());
1556#endif
1557 }
1558
1559 mask |= GCTileStipXOrigin | GCTileStipYOrigin;
1560 vals.ts_x_origin = qRound(origin.x());
1561 vals.ts_y_origin = qRound(origin.y());
1562 }
1563#if QT_CONFIG(xrender)
1564 else if (d->has_alpha_brush) {
1565 d->current_brush = X11->getSolidFill(d->scrn, d->cbrush.color());
1566 }
1567#endif
1568
1569 vals.fill_style = s;
1570 XChangeGC(d->dpy, d->gc_brush, mask, &vals);
1571 if (!d->has_clipping) {
1572 QRegion sysClip = d->use_sysclip ? systemClip() : QRegion();
1573 if (!sysClip.isEmpty())
1574 x11SetClipRegion(d->dpy, d->gc_brush, 0, d->picture, sysClip);
1575 else
1576 x11ClearClipRegion(d->dpy, d->gc_brush, 0, d->picture);
1577 }
1578}
1579
1581{
1582 QRect aligned = rect.toAlignedRect();
1583 if (aligned == rect)
1585 else
1587}
1588
1590{
1591 if (rect.isEmpty()) {
1592 drawRects(&rect, 1);
1593 return;
1594 }
1595
1596 Q_D(QX11PaintEngine);
1597 QRect devclip(SHRT_MIN, SHRT_MIN, SHRT_MAX*2 - 1, SHRT_MAX*2 - 1);
1598 QRect r(rect);
1599 if (d->txop < QTransform::TxRotate) {
1600 r = d->matrix.mapRect(rect);
1601 } else if (d->txop == QTransform::TxRotate && rect.width() == rect.height()) {
1603 path.addEllipse(rect);
1604 r = d->matrix.map(path).boundingRect().toRect();
1605 }
1606
1607 if (d->has_alpha_brush || d->has_alpha_pen || d->has_custom_pen || (d->render_hints & QPainter::Antialiasing)
1608 || d->has_alpha_texture || devclip.intersected(r) != r
1609 || (d->has_complex_xform
1610 && !(d->has_non_scaling_xform && rect.width() == rect.height())))
1611 {
1613 path.addEllipse(rect);
1614 drawPath(path);
1615 return;
1616 }
1617
1618 int x = r.x();
1619 int y = r.y();
1620 int w = r.width();
1621 int h = r.height();
1622 if (w < 1 || h < 1)
1623 return;
1624 if (w == 1 && h == 1) {
1625 XDrawPoint(d->dpy, d->hd, d->has_pen ? d->gc : d->gc_brush, x, y);
1626 return;
1627 }
1628 d->setupAdaptedOrigin(rect.topLeft());
1629 if (d->has_brush) { // draw filled ellipse
1630 XFillArc(d->dpy, d->hd, d->gc_brush, x, y, w, h, 0, 360*64);
1631 if (!d->has_pen) // make smoother outline
1632 XDrawArc(d->dpy, d->hd, d->gc_brush, x, y, w-1, h-1, 0, 360*64);
1633 }
1634 if (d->has_pen) // draw outline
1635 XDrawArc(d->dpy, d->hd, d->gc, x, y, w, h, 0, 360*64);
1636 d->resetAdaptedOrigin();
1637}
1638
1639
1640
1641void QX11PaintEnginePrivate::fillPolygon_translated(const QPointF *polygonPoints, int pointCount,
1644{
1645
1646 QVarLengthArray<QPointF> translated_points(pointCount);
1647 QPointF offset(matrix.dx(), matrix.dy());
1648
1650 if (!X11->use_xrender || !(render_hints & QPainter::Antialiasing))
1652
1653 for (int i = 0; i < pointCount; ++i) {
1654 translated_points[i] = polygonPoints[i] + offset;
1655
1656 translated_points[i].rx() = qRound(translated_points[i].x()) + offs;
1657 translated_points[i].ry() = qRound(translated_points[i].y()) + offs;
1658 }
1659
1660 fillPolygon_dev(translated_points.data(), pointCount, gcMode, mode);
1661}
1662
1663#if QT_CONFIG(xrender)
1664static void qt_XRenderCompositeTrapezoids(Display *dpy,
1665 int op,
1666 Picture src,
1667 Picture dst,
1668 _Xconst XRenderPictFormat *maskFormat,
1669 int xSrc,
1670 int ySrc,
1671 const XTrapezoid *traps, int size)
1672{
1673 const int MAX_TRAPS = 50000;
1674 while (size) {
1675 int to_draw = size;
1676 if (to_draw > MAX_TRAPS)
1677 to_draw = MAX_TRAPS;
1678 XRenderCompositeTrapezoids(dpy, op, src, dst,
1679 maskFormat,
1680 xSrc, ySrc,
1681 traps, to_draw);
1682 size -= to_draw;
1683 traps += to_draw;
1684 }
1685}
1686#endif
1687
1688void QX11PaintEnginePrivate::fillPolygon_dev(const QPointF *polygonPoints, int pointCount,
1691{
1692 Q_Q(QX11PaintEngine);
1693
1694 int clippedCount = 0;
1695 qt_float_point *clippedPoints = 0;
1696
1697#if QT_CONFIG(xrender)
1698 //can change if we switch to pen if gcMode != BrushGC
1699 bool has_fill_texture = has_texture;
1700 bool has_fill_pattern = has_pattern;
1701 ::Picture src;
1702#endif
1703 QBrush fill;
1704 GC fill_gc;
1705 if (gcMode == BrushGC) {
1706 fill = cbrush;
1707 fill_gc = gc_brush;
1708#if QT_CONFIG(xrender)
1709 if (current_brush)
1710 src = current_brush;
1711 else
1712 src = X11->getSolidFill(scrn, fill.color());
1713#endif
1714 } else {
1715 fill = QBrush(cpen.brush());
1716 fill_gc = gc;
1717#if QT_CONFIG(xrender)
1718 //we use the pens brush
1719 has_fill_texture = (fill.style() == Qt::TexturePattern);
1720 has_fill_pattern = (fill.style() >= Qt::Dense1Pattern && fill.style() <= Qt::DiagCrossPattern);
1721 if (has_fill_texture)
1722 src = qt_x11PictureHandle(fill.texture());
1723 else if (has_fill_pattern)
1724 src = getPatternFill(scrn, fill);
1725 else
1726 src = X11->getSolidFill(scrn, fill.color());
1727#endif
1728 }
1729
1730 polygonClipper.clipPolygon((qt_float_point *) polygonPoints, pointCount,
1731 &clippedPoints, &clippedCount);
1732
1733#if QT_CONFIG(xrender)
1734 bool solid_fill = fill.color().alpha() == 255;
1735 if (has_fill_texture && fill.texture().depth() == 1 && solid_fill) {
1736 has_fill_texture = false;
1737 has_fill_pattern = true;
1738 }
1739
1740 bool antialias = render_hints & QPainter::Antialiasing;
1741
1742 if (X11->use_xrender
1743 && picture
1744 && !has_fill_pattern
1745 && (clippedCount > 0)
1746 && (fill.style() != Qt::NoBrush)
1747 && ((has_fill_texture && fill.texture().hasAlpha()) || antialias || !solid_fill || has_alpha_pen != has_alpha_brush))
1748 {
1749 tessellator->tessellate((QPointF *)clippedPoints, clippedCount,
1751 if (tessellator->size > 0) {
1752 XRenderPictureAttributes attrs;
1753 attrs.poly_edge = antialias ? PolyEdgeSmooth : PolyEdgeSharp;
1754 XRenderChangePicture(dpy, picture, CPPolyEdge, &attrs);
1755 int x_offset = int(XFixedToDouble(tessellator->traps[0].left.p1.x) - bg_origin.x());
1756 int y_offset = int(XFixedToDouble(tessellator->traps[0].left.p1.y) - bg_origin.y());
1757 qt_XRenderCompositeTrapezoids(dpy, composition_mode, src, picture,
1758 antialias
1759 ? XRenderFindStandardFormat(dpy, PictStandardA8)
1760 : XRenderFindStandardFormat(dpy, PictStandardA1),
1761 x_offset, y_offset,
1762 tessellator->traps, tessellator->size);
1763 tessellator->done();
1764 }
1765 } else
1766#endif
1767 if (fill.style() != Qt::NoBrush) {
1768 if (clippedCount > 200000) {
1769 QPolygon poly;
1770 for (int i = 0; i < clippedCount; ++i)
1771 poly << QPoint(qFloor(clippedPoints[i].x), qFloor(clippedPoints[i].y));
1772
1773 const QRect bounds = poly.boundingRect();
1774 const QRect aligned = bounds
1775 & QRect(QPoint(), QSize(pdev->width(), pdev->height()));
1776
1778 img.fill(0);
1779
1781 painter.translate(-aligned.x(), -aligned.y());
1784 if (gcMode == BrushGC)
1785 painter.setBrushOrigin(q->painter()->brushOrigin());
1786 painter.drawPolygon(poly);
1787 painter.end();
1788
1789 q->drawImage(aligned, img, img.rect(), Qt::AutoColor);
1790 } else if (clippedCount > 0) {
1791 QVarLengthArray<XPoint> xpoints(clippedCount);
1792 for (int i = 0; i < clippedCount; ++i) {
1793 xpoints[i].x = qFloor(clippedPoints[i].x);
1794 xpoints[i].y = qFloor(clippedPoints[i].y);
1795 }
1797 XSetFillRule(dpy, fill_gc, WindingRule);
1798 setupAdaptedOrigin(QPoint(xpoints[0].x, xpoints[0].y));
1799 XFillPolygon(dpy, hd, fill_gc,
1800 xpoints.data(), clippedCount,
1801 mode == QPaintEngine::ConvexMode ? Convex : Complex, CoordModeOrigin);
1804 XSetFillRule(dpy, fill_gc, EvenOddRule);
1805 }
1806 }
1807}
1808
1809void QX11PaintEnginePrivate::strokePolygon_translated(const QPointF *polygonPoints, int pointCount, bool close)
1810{
1811 QVarLengthArray<QPointF> translated_points(pointCount);
1812 QPointF offset(matrix.dx(), matrix.dy());
1813 for (int i = 0; i < pointCount; ++i)
1814 translated_points[i] = polygonPoints[i] + offset;
1815 strokePolygon_dev(translated_points.data(), pointCount, close);
1816}
1817
1818void QX11PaintEnginePrivate::strokePolygon_dev(const QPointF *polygonPoints, int pointCount, bool close)
1819{
1820 int clippedCount = 0;
1821 qt_float_point *clippedPoints = 0;
1822 polygonClipper.clipPolygon((qt_float_point *) polygonPoints, pointCount,
1823 &clippedPoints, &clippedCount, close);
1824
1825 if (clippedCount > 0) {
1826 QVarLengthArray<XPoint> xpoints(clippedCount);
1827 for (int i = 0; i < clippedCount; ++i) {
1828 xpoints[i].x = qRound(clippedPoints[i].x + aliasedCoordinateDelta);
1829 xpoints[i].y = qRound(clippedPoints[i].y + aliasedCoordinateDelta);
1830 }
1831 uint numberPoints = qMin(clippedCount, xlibMaxLinePoints);
1832 XPoint *pts = xpoints.data();
1833 XDrawLines(dpy, hd, gc, pts, numberPoints, CoordModeOrigin);
1834 pts += numberPoints;
1835 clippedCount -= numberPoints;
1836 numberPoints = qMin(clippedCount, xlibMaxLinePoints-1);
1837 while (clippedCount) {
1838 XDrawLines(dpy, hd, gc, pts-1, numberPoints+1, CoordModeOrigin);
1839 pts += numberPoints;
1840 clippedCount -= numberPoints;
1841 numberPoints = qMin(clippedCount, xlibMaxLinePoints-1);
1842 }
1843 }
1844}
1845
1846void QX11PaintEngine::drawPolygon(const QPointF *polygonPoints, int pointCount, PolygonDrawMode mode)
1847{
1848 Q_D(QX11PaintEngine);
1849
1850 if (d->use_path_fallback) {
1851 QPainterPath path(polygonPoints[0]);
1852 for (int i = 1; i < pointCount; ++i)
1853 path.lineTo(polygonPoints[i]);
1854 if (mode == PolylineMode) {
1855 QBrush oldBrush = d->cbrush;
1856 d->cbrush = QBrush(Qt::NoBrush);
1857 path.setFillRule(Qt::WindingFill);
1858 drawPath(path);
1859 d->cbrush = oldBrush;
1860 } else {
1862 path.closeSubpath();
1863 drawPath(path);
1864 }
1865 return;
1866 }
1867 if (mode != PolylineMode && d->has_brush)
1868 d->fillPolygon_translated(polygonPoints, pointCount, QX11PaintEnginePrivate::BrushGC, mode);
1869
1870 if (d->has_pen)
1871 d->strokePolygon_translated(polygonPoints, pointCount, mode != PolylineMode);
1872}
1873
1874
1876{
1878
1879 QPainterPath clippedPath;
1880 QPainterPath clipPath;
1881 clipPath.addRect(polygonClipper.boundingRect());
1882
1883 if (transform)
1884 clippedPath = (path*matrix).intersected(clipPath);
1885 else
1886 clippedPath = path.intersected(clipPath);
1887
1888 QList<QPolygonF> polys = clippedPath.toFillPolygons();
1889 for (int i = 0; i < polys.size(); ++i) {
1890 QVarLengthArray<QPointF> translated_points(polys.at(i).size());
1891
1892 for (int j = 0; j < polys.at(i).size(); ++j) {
1893 translated_points[j] = polys.at(i).at(j);
1894 if (!X11->use_xrender || !(render_hints & QPainter::Antialiasing)) {
1895 translated_points[j].rx() = qRound(translated_points[j].rx() + aliasedCoordinateDelta) + offs;
1896 translated_points[j].ry() = qRound(translated_points[j].ry() + aliasedCoordinateDelta) + offs;
1897 }
1898 }
1899
1900 fillPolygon_dev(translated_points.data(), polys.at(i).size(), gc_mode,
1902 }
1903}
1904
1906{
1907 Q_D(QX11PaintEngine);
1908 if (path.isEmpty())
1909 return;
1910
1911 if (d->has_brush)
1912 d->fillPath(path, QX11PaintEnginePrivate::BrushGC, true);
1913 if (d->has_pen
1914 && ((X11->use_xrender && (d->has_alpha_pen || (d->render_hints & QPainter::Antialiasing)))
1915 || (!d->isCosmeticPen() && d->txop > QTransform::TxTranslate
1916 && !d->has_non_scaling_xform)
1917 || (d->cpen.style() == Qt::CustomDashLine))) {
1918 QPainterPathStroker stroker;
1919 if (d->cpen.style() == Qt::CustomDashLine) {
1920 stroker.setDashPattern(d->cpen.dashPattern());
1921 stroker.setDashOffset(d->cpen.dashOffset());
1922 } else {
1923 stroker.setDashPattern(d->cpen.style());
1924 }
1925 stroker.setCapStyle(d->cpen.capStyle());
1926 stroker.setJoinStyle(d->cpen.joinStyle());
1927 QPainterPath stroke;
1928 qreal width = d->cpen.widthF();
1929 QPolygonF poly;
1930 QRectF deviceRect(0, 0, d->pdev->width(), d->pdev->height());
1931 // necessary to get aliased alphablended primitives to be drawn correctly
1932 if (d->isCosmeticPen() || d->has_scaling_xform) {
1933 if (d->isCosmeticPen())
1934 stroker.setWidth(width == 0 ? 1 : width);
1935 else
1936 stroker.setWidth(width * d->xform_scale);
1937 stroker.d_ptr->stroker.setClipRect(deviceRect);
1938 stroke = stroker.createStroke(path * d->matrix);
1939 if (stroke.isEmpty())
1940 return;
1942 d->fillPath(stroke, QX11PaintEnginePrivate::PenGC, false);
1943 } else {
1944 stroker.setWidth(width);
1945 stroker.d_ptr->stroker.setClipRect(d->matrix.inverted().mapRect(deviceRect));
1946 stroke = stroker.createStroke(path);
1947 if (stroke.isEmpty())
1948 return;
1950 d->fillPath(stroke, QX11PaintEnginePrivate::PenGC, true);
1951 }
1952 } else if (d->has_pen) {
1953 // if we have a cosmetic pen - use XDrawLine() for speed
1954 QList<QPolygonF> polys = path.toSubpathPolygons(d->matrix);
1955 for (int i = 0; i < polys.size(); ++i)
1956 d->strokePolygon_dev(polys.at(i).data(), polys.at(i).size(), false);
1957 }
1958}
1959
1960Q_GUI_EXPORT void qt_x11_drawImage(const QRect &rect, const QPoint &pos, const QImage &image,
1961 Drawable hd, GC gc, Display *dpy, Visual *visual, int depth)
1962{
1963 Q_ASSERT(image.format() == QImage::Format_RGB32);
1964 Q_ASSERT(image.depth() == 32);
1965
1966 XImage *xi;
1967 // Note: this code assumes either RGB or BGR, 8 bpc server layouts
1968 const uint red_mask = (uint) visual->red_mask;
1969 bool bgr_layout = (red_mask == 0xff);
1970
1971 const int w = rect.width();
1972 const int h = rect.height();
1973
1974 QImage im;
1975 int image_byte_order = ImageByteOrder(QXcbX11Info::display());
1976 if ((QSysInfo::ByteOrder == QSysInfo::BigEndian && ((image_byte_order == LSBFirst) || bgr_layout))
1977 || (image_byte_order == MSBFirst && QSysInfo::ByteOrder == QSysInfo::LittleEndian)
1978 || (image_byte_order == LSBFirst && bgr_layout))
1979 {
1980 im = image.copy(rect);
1981 const qsizetype iw = im.bytesPerLine() / 4;
1982 uint *data = (uint *)im.bits();
1983 for (int i=0; i < h; i++) {
1984 uint *p = data;
1985 uint *end = p + w;
1986 if (bgr_layout && image_byte_order == MSBFirst && QSysInfo::ByteOrder == QSysInfo::LittleEndian) {
1987 while (p < end) {
1988 *p = ((*p << 8) & 0xffffff00) | ((*p >> 24) & 0x000000ff);
1989 p++;
1990 }
1991 } else if ((image_byte_order == LSBFirst && QSysInfo::ByteOrder == QSysInfo::BigEndian)
1992 || (image_byte_order == MSBFirst && QSysInfo::ByteOrder == QSysInfo::LittleEndian)) {
1993 while (p < end) {
1994 *p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000)
1995 | ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff);
1996 p++;
1997 }
1998 } else if ((image_byte_order == MSBFirst && QSysInfo::ByteOrder == QSysInfo::BigEndian)
1999 || (image_byte_order == LSBFirst && bgr_layout))
2000 {
2001 while (p < end) {
2002 *p = ((*p << 16) & 0x00ff0000) | ((*p >> 16) & 0x000000ff)
2003 | ((*p ) & 0xff00ff00);
2004 p++;
2005 }
2006 }
2007 data += iw;
2008 }
2009 xi = XCreateImage(dpy, visual, depth, ZPixmap,
2010 0, (char *) im.bits(), w, h, 32, im.bytesPerLine());
2011 } else {
2012 xi = XCreateImage(dpy, visual, depth, ZPixmap,
2013 0, (char *) image.scanLine(rect.y())+rect.x()*sizeof(uint), w, h, 32, image.bytesPerLine());
2014 }
2015 XPutImage(dpy, hd, gc, xi, 0, 0, pos.x(), pos.y(), w, h);
2016 xi->data = 0; // QImage owns these bits
2017 XDestroyImage(xi);
2018}
2019
2020void QX11PaintEngine::drawImage(const QRectF &r, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags flags)
2021{
2022 Q_D(QX11PaintEngine);
2023
2024 if (image.format() == QImage::Format_RGB32
2025 && d->pdev_depth >= 24 && image.depth() == 32
2026 && r.size() == sr.size())
2027 {
2028 int sx = qRound(sr.x());
2029 int sy = qRound(sr.y());
2030 int x = qRound(r.x());
2031 int y = qRound(r.y());
2032 int w = qRound(r.width());
2033 int h = qRound(r.height());
2034
2035 qt_x11_drawImage(QRect(sx, sy, w, h), QPoint(x, y), image, d->hd, d->gc, d->dpy,
2036 (Visual *)d->xinfo->visual(), d->pdev_depth);
2037 } else {
2039 }
2040}
2041
2042void QX11PaintEngine::drawPixmap(const QRectF &r, const QPixmap &px, const QRectF &_sr)
2043{
2044 Q_D(QX11PaintEngine);
2045 QRectF sr = _sr;
2046 int x = qRound(r.x());
2047 int y = qRound(r.y());
2048 int sx = qRound(sr.x());
2049 int sy = qRound(sr.y());
2050 int sw = qRound(sr.width());
2051 int sh = qRound(sr.height());
2052
2054 if (pixmap.isNull())
2055 return;
2056
2057 if ((d->xinfo && d->xinfo->screen() != qt_x11Info(pixmap).screen())
2058 || (qt_x11Info(pixmap).screen() != DefaultScreen(QXcbX11Info::display()))) {
2059 qt_x11SetScreen(pixmap, d->xinfo ? d->xinfo->screen() : DefaultScreen(X11->display));
2060 }
2061
2063
2064#if QT_CONFIG(xrender)
2066 if (src_pict && d->picture) {
2067 const int pDepth = pixmap.depth();
2068 if (pDepth == 1 && (d->has_alpha_pen)) {
2069 qt_render_bitmap(d->dpy, d->scrn, src_pict, d->picture,
2070 sx, sy, x, y, sw, sh, d->cpen);
2071 return;
2072 } else if (pDepth != 1 && (pDepth == 32 || pDepth != d->pdev_depth)) {
2073 XRenderComposite(d->dpy, d->composition_mode,
2074 src_pict, 0, d->picture, sx, sy, 0, 0, x, y, sw, sh);
2075 return;
2076 }
2077 }
2078#endif
2079
2080 bool mono_src = pixmap.depth() == 1;
2081 bool mono_dst = d->pdev_depth == 1;
2082 bool restore_clip = false;
2083
2084 if (static_cast<QX11PlatformPixmap*>(pixmap.handle())->x11_mask) { // pixmap has a mask
2085 QBitmap comb(sw, sh);
2086 GC cgc = XCreateGC(d->dpy, qt_x11PixmapHandle(comb), 0, 0);
2087 XSetForeground(d->dpy, cgc, 0);
2088 XFillRectangle(d->dpy, qt_x11PixmapHandle(comb), cgc, 0, 0, sw, sh);
2089 XSetBackground(d->dpy, cgc, 0);
2090 XSetForeground(d->dpy, cgc, 1);
2091 if (!d->crgn.isEmpty()) {
2092 QList<XRectangle> rects = qt_region_to_xrectangles(d->crgn);
2093 XSetClipRectangles(d->dpy, cgc, -x, -y, rects.data(), rects.size(), Unsorted);
2094 } else if (d->has_clipping) {
2095 XSetClipRectangles(d->dpy, cgc, 0, 0, 0, 0, Unsorted);
2096 }
2097 XSetFillStyle(d->dpy, cgc, FillOpaqueStippled);
2098 XSetTSOrigin(d->dpy, cgc, -sx, -sy);
2099 XSetStipple(d->dpy, cgc,
2100 static_cast<QX11PlatformPixmap*>(pixmap.handle())->x11_mask);
2101 XFillRectangle(d->dpy, qt_x11PixmapHandle(comb), cgc, 0, 0, sw, sh);
2102 XFreeGC(d->dpy, cgc);
2103
2104 XSetClipOrigin(d->dpy, d->gc, x, y);
2105 XSetClipMask(d->dpy, d->gc, qt_x11PixmapHandle(comb));
2106 restore_clip = true;
2107 }
2108
2109 if (mono_src) {
2110 if (!d->crgn.isEmpty()) {
2111 Pixmap comb = XCreatePixmap(d->dpy, d->hd, sw, sh, 1);
2112 GC cgc = XCreateGC(d->dpy, comb, 0, 0);
2113 XSetForeground(d->dpy, cgc, 0);
2114 XFillRectangle(d->dpy, comb, cgc, 0, 0, sw, sh);
2115 QList<XRectangle> rects = qt_region_to_xrectangles(d->crgn);
2116 XSetClipRectangles(d->dpy, cgc, -x, -y, rects.data(), rects.size(), Unsorted);
2117 XCopyArea(d->dpy, qt_x11PixmapHandle(pixmap), comb, cgc, sx, sy, sw, sh, 0, 0);
2118 XFreeGC(d->dpy, cgc);
2119
2120 XSetClipMask(d->dpy, d->gc, comb);
2121 XSetClipOrigin(d->dpy, d->gc, x, y);
2122 XFreePixmap(d->dpy, comb);
2123 } else {
2124 XSetClipMask(d->dpy, d->gc, qt_x11PixmapHandle(pixmap));
2125 XSetClipOrigin(d->dpy, d->gc, x - sx, y - sy);
2126 }
2127
2128 if (mono_dst) {
2129 XSetForeground(d->dpy, d->gc, qGray(d->cpen.color().rgb()) > 127 ? 0 : 1);
2130 } else {
2132 XSetForeground(d->dpy, d->gc, cmap.pixel(d->cpen.color()));
2133 }
2134 XFillRectangle(d->dpy, d->hd, d->gc, x, y, sw, sh);
2135 restore_clip = true;
2136 } else if (mono_dst && !mono_src) {
2138 XCopyArea(d->dpy, qt_x11PixmapHandle(bitmap), d->hd, d->gc, sx, sy, sw, sh, x, y);
2139 } else {
2140 XCopyArea(d->dpy, qt_x11PixmapHandle(pixmap), d->hd, d->gc, sx, sy, sw, sh, x, y);
2141 }
2142
2143 if (d->pdev->devType() == QInternal::Pixmap) {
2144 const QPixmap *px = static_cast<const QPixmap*>(d->pdev);
2145 Pixmap src_mask = static_cast<QX11PlatformPixmap*>(pixmap.handle())->x11_mask;
2146 Pixmap dst_mask = static_cast<QX11PlatformPixmap*>(px->handle())->x11_mask;
2147 if (dst_mask) {
2148 GC cgc = XCreateGC(d->dpy, dst_mask, 0, 0);
2149 XSetClipOrigin(d->dpy, cgc, x, y);
2150 XSetClipMask(d->dpy, cgc, src_mask);
2151 if (src_mask) { // copy src mask into dst mask
2152 XCopyArea(d->dpy, src_mask, dst_mask, cgc, sx, sy, sw, sh, x, y);
2153 } else { // no src mask, but make sure the area copied is opaque in dest
2154 XSetBackground(d->dpy, cgc, 0);
2155 XSetForeground(d->dpy, cgc, 1);
2156 XFillRectangle(d->dpy, dst_mask, cgc, x, y, sw, sh);
2157 }
2158 XFreeGC(d->dpy, cgc);
2159 }
2160 }
2161
2162 if (restore_clip) {
2163 XSetClipOrigin(d->dpy, d->gc, 0, 0);
2164 QList<XRectangle> rects = qt_region_to_xrectangles(d->crgn);
2165 if (rects.isEmpty())
2166 XSetClipMask(d->dpy, d->gc, XNone);
2167 else
2168 XSetClipRectangles(d->dpy, d->gc, 0, 0, rects.data(), rects.size(), Unsorted);
2169 }
2170}
2171
2173{
2174 Q_D(QX11PaintEngine);
2175 d->txop = mtx.type();
2176 d->matrix = mtx;
2177
2178 d->has_complex_xform = (d->txop > QTransform::TxTranslate);
2179
2180 extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
2181 bool scaling = qt_scaleForTransform(d->matrix, &d->xform_scale);
2182 d->has_scaling_xform = scaling && d->xform_scale != 1.0;
2183 d->has_non_scaling_xform = scaling && d->xform_scale == 1.0;
2184}
2185
2186/*
2187 NB! the clip region is expected to be in dev coordinates
2188*/
2190{
2191 Q_D(QX11PaintEngine);
2192 QRegion sysClip = d->use_sysclip ? systemClip() : QRegion();
2193 if (op == Qt::NoClip) {
2194 d->has_clipping = false;
2195 d->crgn = sysClip;
2196 if (!sysClip.isEmpty()) {
2197 x11SetClipRegion(d->dpy, d->gc, d->gc_brush, d->picture, sysClip);
2198 } else {
2199 x11ClearClipRegion(d->dpy, d->gc, d->gc_brush, d->picture);
2200 }
2201 return;
2202 }
2203
2204 switch (op) {
2205 case Qt::IntersectClip:
2206 if (d->has_clipping) {
2207 d->crgn &= clipRegion;
2208 break;
2209 }
2210 // fall through
2211 case Qt::ReplaceClip:
2212 if (!sysClip.isEmpty())
2213 d->crgn = clipRegion.intersected(sysClip);
2214 else
2215 d->crgn = clipRegion;
2216 break;
2217// case Qt::UniteClip:
2218// d->crgn |= clipRegion;
2219// if (!sysClip.isEmpty())
2220// d->crgn = d->crgn.intersected(sysClip);
2221// break;
2222 default:
2223 break;
2224 }
2225 d->has_clipping = true;
2226 x11SetClipRegion(d->dpy, d->gc, d->gc_brush, d->picture, d->crgn);
2227}
2228
2230{
2231}
2232
2234{
2235 Q_D(const QX11PaintEngine);
2236 Q_ASSERT(isActive());
2237 Q_ASSERT(d->hd);
2238 return d->hd;
2239}
2240
2241extern void qt_draw_tile(QPaintEngine *, qreal, qreal, qreal, qreal, const QPixmap &,
2242 qreal, qreal);
2243
2245{
2246 int x = qRound(r.x());
2247 int y = qRound(r.y());
2248 int w = qRound(r.width());
2249 int h = qRound(r.height());
2250 int sx = qRound(p.x());
2251 int sy = qRound(p.y());
2252
2253 bool mono_src = pixmap.depth() == 1;
2254 Q_D(QX11PaintEngine);
2255
2256 if ((d->xinfo && d->xinfo->screen() != qt_x11Info(pixmap).screen())
2257 || (qt_x11Info(pixmap).screen() != DefaultScreen(QXcbX11Info::display()))) {
2258 QPixmap* p = const_cast<QPixmap *>(&pixmap);
2259 qt_x11SetScreen(*p, d->xinfo ? d->xinfo->screen() : DefaultScreen(QXcbX11Info::display()));
2260 }
2261
2263
2264#if QT_CONFIG(xrender)
2265 if (X11->use_xrender && d->picture && qt_x11PictureHandle(pixmap)) {
2266 const int numTiles = (w / pixmap.width()) * (h / pixmap.height());
2267 if (numTiles < 100) {
2268 // this is essentially qt_draw_tile(), inlined for
2269 // the XRenderComposite call
2270 int yPos, xPos, drawH, drawW, yOff, xOff;
2271 yPos = y;
2272 yOff = sy;
2273 while (yPos < y + h) {
2274 drawH = pixmap.height() - yOff; // Cropping first row
2275 if (yPos + drawH > y + h) // Cropping last row
2276 drawH = y + h - yPos;
2277 xPos = x;
2278 xOff = sx;
2279 while (xPos < x + w) {
2280 drawW = pixmap.width() - xOff; // Cropping first column
2281 if (xPos + drawW > x + w) // Cropping last column
2282 drawW = x + w - xPos;
2283 if (mono_src) {
2284 qt_render_bitmap(d->dpy, d->scrn, qt_x11PictureHandle(pixmap), d->picture,
2285 xOff, yOff, xPos, yPos, drawW, drawH, d->cpen);
2286 } else {
2287 XRenderComposite(d->dpy, d->composition_mode,
2288 qt_x11PictureHandle(pixmap), XNone, d->picture,
2289 xOff, yOff, 0, 0, xPos, yPos, drawW, drawH);
2290 }
2291 xPos += drawW;
2292 xOff = 0;
2293 }
2294 yPos += drawH;
2295 yOff = 0;
2296 }
2297 } else {
2298 w = qMin(w, d->pdev->width() - x);
2299 h = qMin(h, d->pdev->height() - y);
2300 if (w <= 0 || h <= 0)
2301 return;
2302
2303 const int pw = w + sx;
2304 const int ph = h + sy;
2305 QPixmap pm(pw, ph);
2306 if (pixmap.hasAlpha() || mono_src)
2308
2309 const int mode = pixmap.hasAlpha() ? PictOpOver : PictOpSrc;
2310 const ::Picture pmPicture = qt_x11PictureHandle(pm);
2311
2312 // first tile
2313 XRenderComposite(d->dpy, mode,
2314 qt_x11PictureHandle(pixmap), XNone, pmPicture,
2315 0, 0, 0, 0, 0, 0, qMin(pw, pixmap.width()), qMin(ph, pixmap.height()));
2316
2317 // first row of tiles
2318 int xPos = pixmap.width();
2319 const int sh = qMin(ph, pixmap.height());
2320 while (xPos < pw) {
2321 const int sw = qMin(xPos, pw - xPos);
2322 XRenderComposite(d->dpy, mode,
2323 pmPicture, XNone, pmPicture,
2324 0, 0, 0, 0, xPos, 0, sw, sh);
2325 xPos *= 2;
2326 }
2327
2328 // remaining rows
2329 int yPos = pixmap.height();
2330 const int sw = pw;
2331 while (yPos < ph) {
2332 const int sh = qMin(yPos, ph - yPos);
2333 XRenderComposite(d->dpy, mode,
2334 pmPicture, XNone, pmPicture,
2335 0, 0, 0, 0, 0, yPos, sw, sh);
2336 yPos *= 2;
2337 }
2338
2339 // composite
2340 if (mono_src)
2341 qt_render_bitmap(d->dpy, d->scrn, pmPicture, d->picture,
2342 sx, sy, x, y, w, h, d->cpen);
2343 else
2344 XRenderComposite(d->dpy, d->composition_mode,
2345 pmPicture, XNone, d->picture,
2346 sx, sy, 0, 0, x, y, w, h);
2347 }
2348 } else
2349#endif // QT_CONFIG(xrender)
2350 if (pixmap.depth() > 1 && !static_cast<QX11PlatformPixmap*>(pixmap.handle())->x11_mask) {
2351 XSetTile(d->dpy, d->gc, qt_x11PixmapHandle(pixmap));
2352 XSetFillStyle(d->dpy, d->gc, FillTiled);
2353 XSetTSOrigin(d->dpy, d->gc, x-sx, y-sy);
2354 XFillRectangle(d->dpy, d->hd, d->gc, x, y, w, h);
2355 XSetTSOrigin(d->dpy, d->gc, 0, 0);
2356 XSetFillStyle(d->dpy, d->gc, FillSolid);
2357 } else {
2358 qt_draw_tile(this, x, y, w, h, pixmap, sx, sy);
2359 }
2360}
2361
2362bool QX11PaintEngine::drawCachedGlyphs(const QTransform &transform, const QTextItemInt &ti)
2363{
2364#if QT_CONFIG(xrender)
2365 Q_D(QX11PaintEngine);
2366 Q_ASSERT(ti.fontEngine->type() == QFontEngine::Freetype);
2367
2368 if (!X11->use_xrender)
2369 return false;
2370
2371 QFontEngineFT *ft = static_cast<QFontEngineFT *>(ti.fontEngine);
2372 QFontEngineFT::QGlyphSet *set = ft->loadGlyphSet(transform);
2373
2374 if (!set || set->outline_drawing)
2375 return false;
2376
2377 QFontEngine::GlyphFormat glyphFormat = QXRenderGlyphCache::glyphFormatForDepth(ft, d->pdev_depth);
2378
2379 QXRenderGlyphCache *cache = static_cast<QXRenderGlyphCache *>(ft->glyphCache(set, glyphFormat, transform));
2380 if (!cache) {
2381 cache = new QXRenderGlyphCache(QXcbX11Info(), glyphFormat, transform);
2382 ft->setGlyphCache(set, cache);
2383 }
2384
2385 return cache->draw(X11->getSolidFill(d->scrn, d->cpen.color()), d->picture, transform, ti);
2386#else // !QT_CONFIG(xrender)
2387 return false;
2388#endif // QT_CONFIG(xrender)
2389}
2390
2392{
2393 Q_D(QX11PaintEngine);
2394 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
2395
2396 switch (ti.fontEngine->type()) {
2398 case QFontEngine::Box:
2399 d->drawBoxTextItem(p, ti);
2400 break;
2401#if QT_CONFIG(fontconfig)
2403 drawFreetype(p, ti);
2404 break;
2405#endif
2406 default:
2407 Q_ASSERT(false);
2408 }
2409}
2410
2411#if QT_CONFIG(fontconfig)
2412static bool path_for_glyphs(QPainterPath *path,
2413 const QVarLengthArray<glyph_t> &glyphs,
2414 const QVarLengthArray<QFixedPoint> &positions,
2415 const QFontEngineFT *ft)
2416{
2417 bool result = true;
2418 *path = QPainterPath();
2419 path->setFillRule(Qt::WindingFill);
2420 ft->lockFace();
2421 int i = 0;
2422 while (i < glyphs.size()) {
2423 QFontEngineFT::Glyph *glyph = ft->loadGlyph(glyphs[i], QFixedPoint(), QFontEngineFT::Format_Mono);
2424 // #### fix case where we don't get a glyph
2425 if (!glyph || glyph->format != QFontEngineFT::Format_Mono) {
2426 result = false;
2427 break;
2428 }
2429
2430 int n = 0;
2431 int h = glyph->height;
2432 int xp = qRound(positions[i].x);
2433 int yp = qRound(positions[i].y);
2434
2435 xp += glyph->x;
2436 yp += -glyph->y + glyph->height;
2437 int pitch = ((glyph->width + 31) & ~31) >> 3;
2438
2439 uchar *src = glyph->data;
2440 while (h--) {
2441 for (int x = 0; x < glyph->width; ++x) {
2442 bool set = src[x >> 3] & (0x80 >> (x & 7));
2443 if (set) {
2444 QRect r(xp + x, yp - h, 1, 1);
2445 while (x+1 < glyph->width && src[(x+1) >> 3] & (0x80 >> ((x+1) & 7))) {
2446 ++x;
2447 r.setRight(r.right()+1);
2448 }
2449
2450 path->addRect(r);
2451 ++n;
2452 }
2453 }
2454 src += pitch;
2455 }
2456 ++i;
2457 }
2458 ft->unlockFace();
2459 return result;
2460}
2461
2462void QX11PaintEngine::drawFreetype(const QPointF &p, const QTextItemInt &ti)
2463{
2464 Q_D(QX11PaintEngine);
2465
2466 if (!ti.glyphs.numGlyphs)
2467 return;
2468
2469 if (!d->cpen.isSolid()) {
2471 return;
2472 }
2473
2474 const bool xrenderPath = (X11->use_xrender
2475 && !(d->pdev->devType() == QInternal::Pixmap
2476 && static_cast<const QPixmap *>(d->pdev)->handle()->pixelType() == QPlatformPixmap::BitmapType));
2477
2478 if (xrenderPath) {
2479 QTransform transform = d->matrix;
2480 transform.translate(p.x(), p.y());
2481
2482 if (drawCachedGlyphs(transform, ti))
2483 return;
2484 }
2485
2487 transform.translate(p.x(), p.y());
2488
2489 QVarLengthArray<QFixedPoint> positions;
2490 QVarLengthArray<glyph_t> glyphs;
2491 ti.fontEngine->getGlyphPositions(ti.glyphs, transform, ti.flags, glyphs, positions);
2492
2493 if (glyphs.count() == 0)
2494 return;
2495
2496 QFontEngineFT *ft = static_cast<QFontEngineFT *>(ti.fontEngine);
2497 QFontEngineFT::QGlyphSet *set = ft->loadGlyphSet(transform);
2499
2500 if (!set || set->outline_drawing || !path_for_glyphs(&path, glyphs, positions, ft)) {
2502 return;
2503 }
2504
2505 if (path.elementCount() <= 1)
2506 return;
2507
2508 Q_ASSERT((path.elementCount() % 5) == 0);
2509 if (d->txop >= QTransform::TxScale) {
2510 painter()->save();
2511 painter()->setBrush(d->cpen.brush());
2513 painter()->drawPath(path);
2514 painter()->restore();
2515 return;
2516 }
2517
2518 const int rectcount = 256;
2519 XRectangle rects[rectcount];
2520 int num_rects = 0;
2521
2522 QPoint delta(qRound(d->matrix.dx()), qRound(d->matrix.dy()));
2523 QRect clip(d->polygonClipper.boundingRect());
2524 for (int i=0; i < path.elementCount(); i+=5) {
2525 int x = qRound(path.elementAt(i).x);
2526 int y = qRound(path.elementAt(i).y);
2527 int w = qRound(path.elementAt(i+1).x) - x;
2528 int h = qRound(path.elementAt(i+2).y) - y;
2529
2530 QRect rect = QRect(x + delta.x(), y + delta.y(), w, h);
2531 rect = rect.intersected(clip);
2532 if (rect.isEmpty())
2533 continue;
2534
2535 rects[num_rects].x = short(rect.x());
2536 rects[num_rects].y = short(rect.y());
2537 rects[num_rects].width = ushort(rect.width());
2538 rects[num_rects].height = ushort(rect.height());
2539 ++num_rects;
2540 if (num_rects == rectcount) {
2541 XFillRectangles(d->dpy, d->hd, d->gc, rects, num_rects);
2542 num_rects = 0;
2543 }
2544 }
2545 if (num_rects > 0)
2546 XFillRectangles(d->dpy, d->hd, d->gc, rects, num_rects);
2547}
2548#endif // QT_CONFIG(fontconfig)
2549
2550#if QT_CONFIG(xrender)
2551QXRenderGlyphCache::QXRenderGlyphCache(QXcbX11Info x, QFontEngine::GlyphFormat format, const QTransform &matrix)
2553 , xinfo(x)
2554 , gset(XNone)
2555{}
2556
2557QXRenderGlyphCache::~QXRenderGlyphCache()
2558{
2559 if (gset != XNone)
2560 XRenderFreeGlyphSet(xinfo.display(), gset);
2561}
2562
2563bool QXRenderGlyphCache::addGlyphs(const QTextItemInt &ti,
2564 const QVarLengthArray<glyph_t> &glyphs,
2565 const QVarLengthArray<QFixedPoint> &positions)
2566{
2567 Q_ASSERT(ti.fontEngine->type() == QFontEngine::Freetype);
2568
2569 QFontEngineFT *ft = static_cast<QFontEngineFT *>(ti.fontEngine);
2570 QFontEngineFT::QGlyphSet *set = ft->loadGlyphSet(transform());
2571
2572 XGlyphInfo xglyphinfo;
2573
2574 for (int i = 0; i < glyphs.size(); ++i) {
2575 const QFixed sppx = ft->subPixelPositionForX(positions[i].x);
2576 const QFixedPoint spp(sppx, 0);
2577 QFontEngineFT::Glyph *glyph = set->getGlyph(glyphs[i], spp);
2578 Glyph xglyphid = qHash(QFontEngineFT::GlyphAndSubPixelPosition(glyphs[i], spp));
2579
2580 if (glyph && glyph->format == glyphFormat()) {
2581 if (cachedGlyphs.contains(xglyphid)) {
2582 continue;
2583 } else {
2584 set->setGlyph(glyphs[i], spp, nullptr);
2585 delete glyph;
2586 glyph = 0;
2587 }
2588 }
2589
2590 glyph = ft->loadGlyphFor(glyphs[i], spp, glyphFormat(), transform());
2591
2592 if (glyph == 0 || glyph->format != glyphFormat())
2593 return false;
2594
2595 if (glyph->format == QFontEngine::Format_Mono) {
2596 // Must convert bitmap from msb to lsb bit order
2597 QImage img(glyph->data, glyph->width, glyph->height, QImage::Format_Mono);
2598 img = img.convertToFormat(QImage::Format_MonoLSB);
2599 memcpy(glyph->data, img.constBits(), static_cast<size_t>(img.sizeInBytes()));
2600 }
2601
2602 set->setGlyph(glyphs[i], spp, glyph);
2603 Q_ASSERT(glyph->data || glyph->width == 0 || glyph->height == 0);
2604
2605 xglyphinfo.width = glyph->width;
2606 xglyphinfo.height = glyph->height;
2607 xglyphinfo.x = -glyph->x;
2608 xglyphinfo.y = glyph->y;
2609 xglyphinfo.xOff = glyph->advance;
2610 xglyphinfo.yOff = 0;
2611
2612 XRenderAddGlyphs(xinfo.display(), glyphSet(), &xglyphid, &xglyphinfo, 1, (const char *) glyph->data, glyphBufferSize(*glyph));
2613 cachedGlyphs.insert(xglyphid);
2614 }
2615
2616 return true;
2617}
2618
2619bool QXRenderGlyphCache::draw(Drawable src, Drawable dst, const QTransform &matrix, const QTextItemInt &ti)
2620{
2621 Q_ASSERT(ti.fontEngine->type() == QFontEngine::Freetype);
2622
2623 if (ti.glyphs.numGlyphs == 0)
2624 return true;
2625
2626 QFontEngineFT *ft = static_cast<QFontEngineFT *>(ti.fontEngine);
2627 QFontEngineFT::QGlyphSet *set = ft->loadGlyphSet(matrix);
2628
2629 QVarLengthArray<glyph_t> glyphs;
2630 QVarLengthArray<QFixedPoint> positions;
2631 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
2632
2633 if (glyphs.isEmpty())
2634 return true;
2635
2636 if (!addGlyphs(ti, glyphs, positions))
2637 return false;
2638
2639 QVarLengthArray<unsigned int> chars(glyphs.size());
2640
2641 for (int i = 0; i < glyphs.size(); ++i)
2642 chars[i] = glyphId(glyphs[i], ft->subPixelPositionForX(positions[i].x));
2643
2644 int i = 0;
2645 while (i < glyphs.size() && !isValidCoordinate(positions[i]))
2646 ++i;
2647
2648 if (i >= glyphs.size())
2649 return true;
2650
2651 QFixed xp = positions[i].x;
2652 QFixed yp = positions[i].y;
2654
2655 XGlyphElt32 elt;
2656 elt.glyphset = gset;
2657 elt.chars = &chars[i];
2658 elt.nchars = 1;
2659 elt.xOff = qRound(xp + offs);
2660 elt.yOff = qRound(yp + offs);
2661
2662 ++i;
2663
2664 for (; i < glyphs.size(); ++i) {
2665 if (!isValidCoordinate(positions[i]))
2666 break;
2667
2668 const QFixed sppx = ft->subPixelPositionForX(positions[i].x);
2669 const QFixedPoint spp(sppx, 0);
2670 QFontEngineFT::Glyph *g = set->getGlyph(glyphs[i], spp);
2671
2672 if (g
2673 && positions[i].x == xp + g->advance
2674 && positions[i].y == yp
2675 && elt.nchars < 253 // don't draw more than 253 characters as some X servers
2676 // hang with it
2677 ) {
2678 elt.nchars++;
2679 xp += g->advance;
2680 } else {
2681 xp = positions[i].x;
2682 yp = positions[i].y;
2683
2684 XRenderCompositeText32(xinfo.display(), PictOpOver, src, dst,
2685 renderPictFormat(), 0, 0, 0, 0,
2686 &elt, 1);
2687 elt.chars = &chars[i];
2688 elt.nchars = 1;
2689 elt.xOff = qRound(xp + offs);
2690 elt.yOff = qRound(yp + offs);
2691 }
2692 }
2693
2694 XRenderCompositeText32(xinfo.display(), PictOpOver, src, dst,
2695 renderPictFormat(), 0, 0, 0, 0, &elt, 1);
2696
2697 return true;
2698}
2699
2700GlyphSet QXRenderGlyphCache::glyphSet()
2701{
2702 if (gset == XNone)
2703 gset = XRenderCreateGlyphSet(xinfo.display(), renderPictFormat());
2704
2705 Q_ASSERT(gset != XNone);
2706 return gset;
2707}
2708
2709int QXRenderGlyphCache::glyphBufferSize(const QFontEngineFT::Glyph &glyph) const
2710{
2711 int pitch = 0;
2712
2713 switch (glyphFormat()) {
2715 pitch = ((glyph.width + 31) & ~31) >> 3;
2716 break;
2718 pitch = (glyph.width + 3) & ~3;
2719 break;
2720 default:
2721 pitch = glyph.width * 4;
2722 break;
2723 }
2724
2725 return pitch * glyph.height;
2726}
2727
2728QImage::Format QXRenderGlyphCache::imageFormat() const
2729{
2730 switch (glyphFormat()) {
2732 Q_UNREACHABLE();
2733 break;
2735 return QImage::Format_Mono;
2736 break;
2738 return QImage::Format_Alpha8;
2739 break;
2743 break;
2744 }
2745
2746 Q_UNREACHABLE();
2747}
2748
2749const XRenderPictFormat *QXRenderGlyphCache::renderPictFormat() const
2750{
2751 switch (glyphFormat()) {
2753 Q_UNREACHABLE();
2754 break;
2756 return XRenderFindStandardFormat(xinfo.display(), PictStandardA1);
2757 break;
2759 return XRenderFindStandardFormat(xinfo.display(), PictStandardA8);
2760 break;
2763 return XRenderFindStandardFormat(xinfo.display(), PictStandardARGB32);
2764 break;
2765 }
2766
2767 Q_UNREACHABLE();
2768}
2769
2770QFontEngine::GlyphFormat QXRenderGlyphCache::glyphFormatForDepth(QFontEngine *fontEngine, int depth)
2771{
2772 QFontEngine::GlyphFormat glyphFormat = fontEngine->glyphFormat;
2773
2774 if (glyphFormat == QFontEngine::Format_None) {
2775 switch (depth) {
2776 case 32:
2777 glyphFormat = QFontEngine::Format_ARGB;
2778 break;
2779 case 24:
2780 glyphFormat = QFontEngine::Format_A32;
2781 break;
2782 case 1:
2783 glyphFormat = QFontEngine::Format_Mono;
2784 break;
2785 default:
2786 glyphFormat = QFontEngine::Format_A8;
2787 break;
2788 }
2789 }
2790
2791 return glyphFormat;
2792}
2793
2794Glyph QXRenderGlyphCache::glyphId(glyph_t glyph, QFixed subPixelPosition)
2795{
2796 return qHash(QFontEngineFT::GlyphAndSubPixelPosition(glyph, QFixedPoint(subPixelPosition, 0)));
2797}
2798
2799bool QXRenderGlyphCache::isValidCoordinate(const QFixedPoint &fp)
2800{
2801 enum { t_min = SHRT_MIN, t_max = SHRT_MAX };
2802 return (fp.x < t_min || fp.x > t_max || fp.y < t_min || fp.y > t_max) ? false : true;
2803}
2804#endif // QT_CONFIG(xrender)
2805
\inmodule QtGui
Definition qbitmap.h:16
static QBitmap fromImage(const QImage &image, Qt::ImageConversionFlags flags=Qt::AutoColor)
Returns a copy of the given image converted to a bitmap using the specified image conversion flags.
Definition qbitmap.cpp:170
static QBitmap fromPixmap(const QPixmap &pixmap)
Returns a copy of the given pixmap converted to a bitmap.
Definition qbitmap.cpp:234
\inmodule QtGui
Definition qbrush.h:30
\inmodule QtCore
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
QRgb rgb() const noexcept
Returns the RGB value of the color.
Definition qcolor.cpp:1439
QRgb rgba() const noexcept
Returns the RGB value of the color, including its alpha.
Definition qcolor.cpp:1376
int alpha() const noexcept
Returns the alpha color component of this color.
Definition qcolor.cpp:1466
void setAlpha(int alpha)
Sets the alpha of this color to alpha.
Definition qcolor.cpp:1481
Definition qflags.h:17
GlyphFormat glyphFormat
\reentrant
Definition qfont.h:22
\inmodule QtGui
Definition qimage.h:37
qsizetype bytesPerLine() const
Returns the number of bytes per image scanline.
Definition qimage.cpp:1560
uchar * bits()
Returns a pointer to the first pixel data.
Definition qimage.cpp:1698
Format
The following image formats are available in Qt.
Definition qimage.h:41
@ Format_Alpha8
Definition qimage.h:65
@ Format_RGB32
Definition qimage.h:46
@ Format_MonoLSB
Definition qimage.h:44
@ Format_Mono
Definition qimage.h:43
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
@ Format_ARGB32
Definition qimage.h:47
\inmodule QtCore\compares equality \compareswith equality QLine \endcompareswith
Definition qline.h:192
\inmodule QtCore\compares equality \compareswith equality QLineF \endcompareswith
Definition qline.h:18
constexpr QPoint p1() const
Returns the line's start point.
Definition qline.h:104
constexpr QPoint p2() const
Returns the line's end point.
Definition qline.h:109
virtual int devType() const
int width() const
int height() const
QPaintDevice * pdev
The QPaintEngineState class provides information about the active paint engine's current state....
QTransform transform() const
QPainterPath clipPath() const
Returns the clip path in the current paint engine state.
Qt::ClipOperation clipOperation() const
Returns the clip operation in the current paint engine state.
QPointF brushOrigin() const
Returns the brush origin in the current paint engine state.
qreal opacity() const
bool isClipEnabled() const
Returns whether clipping is enabled or not in the current paint engine state.
QBrush brush() const
Returns the brush in the current paint engine state.
QRegion clipRegion() const
Returns the clip region in the current paint engine state.
QPainter::RenderHints renderHints() const
Returns the render hints in the current paint engine state.
QFont font() const
Returns the font in the current paint engine state.
QPen pen() const
Returns the pen in the current paint engine state.
QPaintEngine::DirtyFlags state() const
Returns a combination of flags identifying the set of properties that need to be updated when updatin...
QPainter::CompositionMode compositionMode() const
Returns the composition mode in the current paint engine state.
\inmodule QtGui
void setActive(bool newState)
Sets the active state of the paint engine to state.
virtual void drawRects(const QRect *rects, int rectCount)
This is an overloaded member function, provided for convenience. It differs from the above function o...
virtual void drawTextItem(const QPointF &p, const QTextItem &textItem)
This function draws the text item textItem at position p.
PolygonDrawMode
\value OddEvenMode The polygon should be drawn using OddEven fill rule.
virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags=Qt::AutoColor)
Reimplement this function to draw the part of the image specified by the sr rectangle in the given re...
QPainter * painter() const
Returns the paint engine's painter.
void setDirty(DirtyFlags df)
void setSystemClip(const QRegion &baseClip)
QPaintEngineState * state
bool isActive() const
Returns true if the paint engine is actively drawing; otherwise returns false.
virtual void drawEllipse(const QRectF &r)
Reimplement this function to draw the largest ellipse that can be contained within rectangle rect.
QRegion systemClip() const
QPaintDevice * paintDevice() const
Returns the device that this engine is painting on, if painting is active; otherwise returns \nullptr...
The QPainterPathStroker class is used to generate fillable outlines for a given painter path.
void setDashPattern(Qt::PenStyle)
Sets the dash pattern for the generated outlines to style.
void setDashOffset(qreal offset)
Sets the dash offset for the generated outlines to offset.
void setCapStyle(Qt::PenCapStyle style)
Sets the cap style of the generated outlines to style.
void setWidth(qreal width)
Sets the width of the generated outline painter path to width.
QPainterPath createStroke(const QPainterPath &path) const
Generates a new path that is a fillable area representing the outline of the given path.
void setJoinStyle(Qt::PenJoinStyle style)
Sets the join style of the generated outlines to style.
\inmodule QtGui
void addRect(const QRectF &rect)
Adds the given rectangle to this path as a closed subpath.
void setFillRule(Qt::FillRule fillRule)
Sets the fill rule of the painter path to the given fillRule.
QPolygonF toFillPolygon(const QTransform &matrix=QTransform()) const
Converts the path into a polygon using the QTransform matrix, and returns the polygon.
Qt::FillRule fillRule() const
Returns the painter path's currently set fill rule.
bool isEmpty() const
Returns true if either there are no elements in this path, or if the only element is a MoveToElement;...
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
void drawPath(const QPainterPath &path)
Draws the given painter path using the current pen for outline and the current brush for filling.
void setPen(const QColor &color)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void setBrushOrigin(int x, int y)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qpainter.h:698
void restore()
Restores the current painter state (pops a saved state off the stack).
void save()
Saves the current painter state (pushes the state onto a stack).
QPainterPath clipPath() const
Returns the current clip path in logical coordinates.
void setBrush(const QBrush &brush)
Sets the painter's brush to the given brush.
@ Antialiasing
Definition qpainter.h:52
bool end()
Ends painting.
CompositionMode
Defines the modes supported for digital image compositing.
Definition qpainter.h:97
@ CompositionMode_Xor
Definition qpainter.h:109
@ RasterOp_SourceAndNotDestination
Definition qpainter.h:134
@ RasterOp_NotSourceAndNotDestination
Definition qpainter.h:129
@ RasterOp_NotSourceOrNotDestination
Definition qpainter.h:130
@ RasterOp_SourceXorDestination
Definition qpainter.h:128
@ RasterOp_NotSourceAndDestination
Definition qpainter.h:133
@ RasterOp_SourceOrDestination
Definition qpainter.h:126
@ RasterOp_NotSource
Definition qpainter.h:132
@ RasterOp_NotSourceXorDestination
Definition qpainter.h:131
@ RasterOp_SourceAndDestination
Definition qpainter.h:127
void drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule=Qt::OddEvenFill)
Draws the polygon defined by the first pointCount points in the array points using the current pen an...
void translate(const QPointF &offset)
Translates the coordinate system by the given offset; i.e.
bool hasClipping() const
Returns true if clipping has been set; otherwise returns false.
\inmodule QtGui
Definition qpen.h:28
qreal widthF() const
Returns the pen width with floating point precision.
Definition qpen.cpp:572
QColor color() const
Returns the color of this pen's brush.
Definition qpen.cpp:692
Qt::PenCapStyle capStyle() const
Returns the pen's cap style.
Definition qpen.cpp:636
Qt::PenJoinStyle joinStyle() const
Returns the pen's join style.
Definition qpen.cpp:663
QBrush brush() const
Returns the brush used to fill strokes generated with this pen.
Definition qpen.cpp:715
Qt::PenStyle style() const
Returns the pen style.
Definition qpen.cpp:366
static bool find(const QString &key, QPixmap *pixmap)
Looks for a cached pixmap associated with the given key in the cache.
static bool insert(const QString &key, const QPixmap &pixmap)
Inserts a copy of the pixmap pixmap associated with the key into the cache.
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
QPlatformPixmap * handle() const
Definition qpixmap.cpp:1506
void fill(const QColor &fillColor=Qt::white)
Fills the pixmap with the given color.
Definition qpixmap.cpp:850
\inmodule QtCore\reentrant
Definition qpoint.h:217
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:343
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:348
\inmodule QtCore\reentrant
Definition qpoint.h:25
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:130
The QPolygonF class provides a list of points using floating point precision.
Definition qpolygon.h:96
The QPolygon class provides a list of points using integer precision.
Definition qpolygon.h:23
static Q_DECL_CONST_FUNCTION QRandomGenerator * global()
\threadsafe
Definition qrandom.h:275
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr QRect toRect() const noexcept
Returns a QRect based on the values of this rectangle.
Definition qrect.h:859
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr int bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
Definition qrect.h:182
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:176
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:173
constexpr int right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
Definition qrect.h:179
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
QRegion intersected(const QRegion &r) const
\inmodule QtCore
Definition qsize.h:25
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
void setClipRect(const QRectF &clip)
Definition qstroker_p.h:129
@ BigEndian
Definition qsysinfo.h:29
@ ByteOrder
Definition qsysinfo.h:34
@ LittleEndian
Definition qsysinfo.h:30
QRectF tessellate(const QPointF *points, int nPoints)
Internal QTextItem.
\inmodule QtGui
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
TransformationType type() const
Returns the transformation type of this matrix.
QTransform & translate(qreal dx, qreal dy)
Moves the coordinate system dx along the x axis and dy along the y axis, and returns a reference to t...
TransformationType
\value TxNone \value TxTranslate \value TxScale \value TxRotate \value TxShear \value TxProject
Definition qtransform.h:22
void systemStateChanged() override
void setupAdaptedOrigin(const QPoint &p)
void fillPolygon_translated(const QPointF *points, int pointCount, GCMode gcMode, QPaintEngine::PolygonDrawMode mode)
void clipPolygon_dev(const QPolygonF &poly, QPolygonF *clipped_poly)
const QXcbX11Info * xinfo
QTransform::TransformationType txop
QPolygonClipper< qt_float_point, qt_float_point, float > polygonClipper
void strokePolygon_dev(const QPointF *points, int pointCount, bool close)
void fillPath(const QPainterPath &path, GCMode gcmode, bool transform)
void strokePolygon_translated(const QPointF *points, int pointCount, bool close)
void fillPolygon_dev(const QPointF *points, int pointCount, GCMode gcMode, QPaintEngine::PolygonDrawMode mode)
void updateState(const QPaintEngineState &state) override
Reimplement this function to update the state of a paint engine.
void drawTextItem(const QPointF &p, const QTextItem &textItem) override
This function draws the text item textItem at position p.
void drawLines(const QLine *lines, int lineCount) override
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool begin(QPaintDevice *pdev) override
Reimplement this function to initialise your paint engine when painting is to start on the paint devi...
void updateBrush(const QBrush &brush, const QPointF &pt)
void updateClipRegion_dev(const QRegion &region, Qt::ClipOperation op)
void updateFont(const QFont &font)
virtual Drawable handle() const
void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) override
Reimplement this function to draw the part of the pm specified by the sr rectangle in the given r.
void drawRects(const QRect *rects, int rectCount) override
This is an overloaded member function, provided for convenience. It differs from the above function o...
void updateMatrix(const QTransform &matrix)
QPainter::RenderHints supportedRenderHints() const
void updateRenderHints(QPainter::RenderHints hints)
void drawPath(const QPainterPath &path) override
The default implementation ignores the path and does nothing.
void drawPoints(const QPoint *points, int pointCount) override
Draws the first pointCount points in the buffer points.
virtual void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) override
Reimplement this virtual function to draw the polygon defined by the pointCount first points in point...
void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s) override
Reimplement this function to draw the pixmap in the given rect, starting at the given p.
void updatePen(const QPen &pen)
void drawImage(const QRectF &r, const QImage &img, const QRectF &sr, Qt::ImageConversionFlags flags=Qt::AutoColor) override
Reimplement this function to draw the part of the image specified by the sr rectangle in the given re...
bool end() override
Reimplement this function to finish painting on the current paint device.
void drawEllipse(const QRect &r) override
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QXcbColormap instance(int screen=-1)
uint pixel(const QColor &color) const
static Display * display()
QString str
[2]
QPixmap p2
QPixmap p1
[0]
QCache< int, Employee > cache
[0]
rect
[4]
else opt state
[0]
Combined button and popup list for selecting options.
@ AutoColor
Definition qnamespace.h:478
ClipOperation
@ ReplaceClip
@ IntersectClip
@ NoClip
@ white
Definition qnamespace.h:31
@ transparent
Definition qnamespace.h:47
@ black
Definition qnamespace.h:30
@ CustomDashLine
@ DashDotDotLine
@ DotLine
@ SolidLine
@ DashDotLine
@ DashLine
@ NoPen
@ BevelJoin
@ MiterJoin
@ RoundJoin
void * HANDLE
@ DiagCrossPattern
@ SolidPattern
@ Dense1Pattern
@ TexturePattern
@ NoBrush
@ WindingFill
@ OddEvenFill
PenCapStyle
@ SquareCap
@ RoundCap
@ FlatCap
Definition brush.cpp:5
Definition image.cpp:4
Q_GUI_EXPORT QPixmap qt_pixmapForBrush(int brushStyle, bool invert)
Definition qbrush.cpp:80
#define rgb(r, g, b)
Definition qcolor.cpp:124
static const QCssKnownValue positions[NumKnownPositionModes - 1]
static struct AttrInfo attrs[]
size_t qHash(const QFileSystemWatcherPathKey &key, size_t seed=0)
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
@ XNone
int qFloor(T v)
Definition qmath.h:42
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
GLint GLenum GLsizei GLsizei GLsizei depth
GLenum mode
GLuint64 key
GLfloat GLfloat GLfloat w
[0]
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLuint GLuint end
GLuint GLfloat GLfloat GLfloat x1
GLdouble GLdouble GLdouble GLdouble top
GLdouble GLdouble right
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum src
GLint GLsizei width
GLuint color
[2]
GLint left
GLenum GLenum dst
GLint GLint bottom
GLbitfield flags
GLenum GLuint GLintptr offset
GLboolean GLboolean g
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLfloat n
GLint GLsizei GLsizei GLenum format
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLuint GLenum GLenum transform
GLfixed GLfixed GLint GLint GLfixed points
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
GLuint GLfloat * val
GLfixed GLfixed GLfixed y2
GLint void * img
Definition qopenglext.h:233
GLsizei GLfixed GLfixed GLfixed GLfixed const GLubyte * bitmap
GLuint GLenum matrix
GLfixed GLfixed x2
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLuint num
GLfloat GLfloat GLfloat alpha
Definition qopenglext.h:418
GLenum GLenum GLenum GLenum GLenum scale
GLubyte * pattern
GLboolean invert
Definition qopenglext.h:226
Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale)
Q_GUI_EXPORT void qt_draw_tile(QPaintEngine *gc, qreal x, qreal y, qreal w, qreal h, const QPixmap &pixmap, qreal xOffset, qreal yOffset)
static void setCapStyle(int cap_style, GC gc)
static void x11SetClipRegion(Display *dpy, GC gc, GC gc2, Qt::HANDLE picture, const QRegion &r)
#define X11
static QPaintEngine::PaintEngineFeatures qt_decide_features()
Q_GUI_EXPORT void qt_x11_drawImage(const QRect &rect, const QPoint &pos, const QImage &image, Drawable hd, GC gc, Display *dpy, Visual *visual, int depth)
static QLine clipStraightLine(const QRect &clip, const QLine &l)
static const qreal aliasedCoordinateDelta
Q_XCB_EXPORT Drawable qt_x11Handle(const QPaintDevice *pd)
GC Q_XCB_EXPORT qt_x11_get_brush_gc(QPainter *p)
Returns the X11 specific brush GC for the painter p.
#define DITHER_SIZE
QPixmap qt_toX11Pixmap(const QPixmap &pixmap)
static void x11ClearClipRegion(Display *dpy, GC gc, GC gc2, Qt::HANDLE picture)
static const QXcbX11Info * qt_x11Info(const QPaintDevice *pd)
void qt_draw_tile(QPaintEngine *, qreal, qreal, qreal, qreal, const QPixmap &, qreal, qreal)
GC Q_XCB_EXPORT qt_x11_get_pen_gc(QPainter *p)
Returns the X11 specific pen GC for the painter p.
static QPixmap qt_patternForAlpha(uchar alpha, int screen)
static const uchar base_dither_matrix[DITHER_SIZE][DITHER_SIZE]
static bool clipLine(QLineF *line, const QRect &rect)
QT_BEGIN_NAMESPACE Drawable qt_x11Handle(const QPaintDevice *pd)
struct _XGC * GC
XID Drawable
QPainterPath qt_regionToPath(const QRegion &region)
Definition qregion.cpp:1007
@ Bottom
@ Top
@ Left
@ Right
static qreal dot(const QPointF &a, const QPointF &b)
void qt_x11SetScreen(QPixmap &pixmap, int screen)
int qt_x11SetDefaultScreen(int screen)
XID Picture
XID Pixmap
Pixmap qt_x11PixmapHandle(const QPixmap &pixmap)
Picture qt_x11PictureHandle(const QPixmap &pixmap)
QX11PlatformPixmap * qt_x11Pixmap(const QPixmap &pixmap)
static QRectF alignedRect(bool mirrored, Qt::Alignment alignment, const QSizeF &size, const QRectF &rectangle)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
constexpr int qGray(int r, int g, int b)
Definition qrgb.h:36
Int aligned(Int v, Int byteAlign)
#define fp
QScreen * screen
[1]
Definition main.cpp:29
#define QT_CONFIG(feature)
void gc(QV4::ExecutionEngine &engine, GCFlags flags)
Definition qmlutils.cpp:118
#define Q27Dot5ToXFixed(i)
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
unsigned int glyph_t
#define Q_UNUSED(x)
struct _XDisplay Display
unsigned char uchar
Definition qtypes.h:32
unsigned long ulong
Definition qtypes.h:35
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned int uint
Definition qtypes.h:34
unsigned short ushort
Definition qtypes.h:33
double qreal
Definition qtypes.h:187
#define Q_XCB_EXPORT
Definition qxcbexport.h:14
QList< XRectangle > qt_region_to_xrectangles(const QRegion &r)
QFuture< QSet< QChar > > set
[10]
QTextStream out(stdout)
[7]
ba fill(true)
p ry()++
p rx()++
myFilter draw(painter, QPoint(0, 0), originalPixmap)
widget render & pixmap
QPainter painter(this)
[7]
void write(QChar *&dest) const
HexString(const T t)
static int size(const HexString< T > &)
static void appendTo(const HexString< T > &str, QChar *&out)
static constexpr QFixed fromReal(qreal r)
Definition qfixed_p.h:35
unsigned short height
unsigned short width