1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
41 #include "qpaintengine.h"
42 #include "qpaintengine_p.h"
43 #include "qpainter_p.h"
48 #include <qguiapplication.h>
49 #include <private/qtextengine_p.h>
50 #include <qvarlengtharray.h>
51 #include <private/qfontengine_p.h>
52 #include <private/qpaintengineex_p.h>
61 \brief The QTextItem class provides all the information required to draw
62 text in a custom paint engine.
64 When you reimplement your own paint engine, you must reimplement
65 QPaintEngine::drawTextItem(), a function that takes a QTextItem as
70 \enum QTextItem::RenderFlag
72 \value RightToLeft Render the text from right to left.
73 \value Overline Paint a line above the text.
74 \value Underline Paint a line under the text.
75 \value StrikeOut Paint a line through the text.
81 \fn qreal QTextItem::descent() const
83 Corresponds to the \l{QFontMetrics::descent()}{descent} of the piece of text that is drawn.
85 qreal QTextItem::descent() const
87 const QTextItemInt *ti = static_cast<const QTextItemInt *>(this);
88 return ti->descent.toReal();
92 \fn qreal QTextItem::ascent() const
94 Corresponds to the \l{QFontMetrics::ascent()}{ascent} of the piece of text that is drawn.
96 qreal QTextItem::ascent() const
98 const QTextItemInt *ti = static_cast<const QTextItemInt *>(this);
99 return ti->ascent.toReal();
103 \fn qreal QTextItem::width() const
105 Specifies the total width of the text to be drawn.
107 qreal QTextItem::width() const
109 const QTextItemInt *ti = static_cast<const QTextItemInt *>(this);
110 return ti->width.toReal();
114 \fn QTextItem::RenderFlags QTextItem::renderFlags() const
116 Returns the render flags used.
118 QTextItem::RenderFlags QTextItem::renderFlags() const
120 const QTextItemInt *ti = static_cast<const QTextItemInt *>(this);
125 \fn QString QTextItem::text() const
127 Returns the text that should be drawn.
129 QString QTextItem::text() const
131 const QTextItemInt *ti = static_cast<const QTextItemInt *>(this);
132 return QString(ti->chars, ti->num_chars);
136 \fn QFont QTextItem::font() const
138 Returns the font that should be used to draw the text.
140 QFont QTextItem::font() const
142 const QTextItemInt *ti = static_cast<const QTextItemInt *>(this);
143 return ti->f ? *ti->f : QGuiApplication::font();
152 \brief The QPaintEngine class provides an abstract definition of how
153 QPainter draws to a given device on a given platform.
155 Qt 4.0 provides several premade implementations of QPaintEngine for the
156 different painter backends we support. We provide one paint engine for each
157 window system and painting framework we support. This includes X11 on
158 Unix/Linux and CoreGraphics on Mac OS X. In addition we provide QPaintEngine
159 implementations for OpenGL (accessible through QOpenGLWidget) and PostScript
160 (accessible through QPSPrinter on X11). Additionally there is a raster-based
161 paint engine that is a fallback for when an engine does not support a certain
164 If one wants to use QPainter to draw to a different backend,
165 one must subclass QPaintEngine and reimplement all its virtual
166 functions. The QPaintEngine implementation is then made available by
167 subclassing QPaintDevice and reimplementing the virtual function
168 QPaintDevice::paintEngine().
170 QPaintEngine is created and owned by the QPaintDevice that created it.
172 The big advantage of the QPaintEngine approach opposed to
173 Qt 3's QPainter/QPaintDevice::cmd() approach is that it is now
174 possible to adapt to multiple technologies on each platform and take
175 advantage of each to the fullest.
177 \sa QPainter, QPaintDevice::paintEngine(), {Paint System}
181 \enum QPaintEngine::PaintEngineFeature
183 This enum is used to describe the features or capabilities that the
184 paint engine has. If a feature is not supported by the engine,
185 QPainter will do a best effort to emulate that feature through other
186 means and pass on an alpha blended QImage to the engine with the
187 emulated results. Some features cannot be emulated: AlphaBlend and PorterDuff.
189 \value AlphaBlend The engine can alpha blend primitives.
190 \value Antialiasing The engine can use antialising to improve the appearance
191 of rendered primitives.
192 \value BlendModes The engine supports blending modes.
193 \value BrushStroke The engine supports drawing strokes that
194 contain brushes as fills, not just solid
195 colors (e.g. a dashed gradient line of
197 \value ConicalGradientFill The engine supports conical gradient fills.
198 \value ConstantOpacity The engine supports the feature provided by
199 QPainter::setOpacity().
200 \value LinearGradientFill The engine supports linear gradient fills.
201 \value MaskedBrush The engine is capable of rendering brushes that has a
202 texture with an alpha channel or a mask.
203 \value ObjectBoundingModeGradients The engine has native support for gradients
204 with coordinate mode QGradient::ObjectBoundingMode.
205 Otherwise, if QPaintEngine::PatternTransform is
206 supported, object bounding mode gradients are
207 converted to gradients with coordinate mode
208 QGradient::LogicalMode and a brush transform for
209 the coordinate mapping.
210 \value PainterPaths The engine has path support.
211 \value PaintOutsidePaintEvent The engine is capable of painting outside of
213 \value PatternBrush The engine is capable of rendering brushes with
214 the brush patterns specified in Qt::BrushStyle.
215 \value PatternTransform The engine has support for transforming brush
217 \value PerspectiveTransform The engine has support for performing perspective
218 transformations on primitives.
219 \value PixmapTransform The engine can transform pixmaps, including
220 rotation and shearing.
221 \value PorterDuff The engine supports Porter-Duff operations
222 \value PrimitiveTransform The engine has support for transforming
224 \value RadialGradientFill The engine supports radial gradient fills.
225 \value RasterOpModes The engine supports bitwise raster operations.
226 \value AllFeatures All of the above features. This enum value is usually
231 \enum QPaintEngine::PolygonDrawMode
233 \value OddEvenMode The polygon should be drawn using OddEven fill
236 \value WindingMode The polygon should be drawn using Winding fill rule.
238 \value ConvexMode The polygon is a convex polygon and can be drawn
239 using specialized algorithms where available.
241 \value PolylineMode Only the outline of the polygon should be
247 \enum QPaintEngine::DirtyFlag
249 \value DirtyPen The pen is dirty and needs to be updated.
251 \value DirtyBrush The brush is dirty and needs to be updated.
253 \value DirtyBrushOrigin The brush origin is dirty and needs to
256 \value DirtyFont The font is dirty and needs to be updated.
258 \value DirtyBackground The background is dirty and needs to be
261 \value DirtyBackgroundMode The background mode is dirty and needs
264 \value DirtyTransform The transform is dirty and needs to be
267 \value DirtyClipRegion The clip region is dirty and needs to be
270 \value DirtyClipPath The clip path is dirty and needs to be
273 \value DirtyHints The render hints is dirty and needs to be
276 \value DirtyCompositionMode The composition mode is dirty and
279 \value DirtyClipEnabled Whether clipping is enabled or not is
280 dirty and needs to be updated.
282 \value DirtyOpacity The constant opacity has changed and needs to
283 be updated as part of the state change in
284 QPaintEngine::updateState().
286 \value AllDirty Convenience enum used internally.
288 These types are used by QPainter to trigger lazy updates of the
289 various states in the QPaintEngine using
290 QPaintEngine::updateState().
292 A paint engine must update every dirty state.
296 \fn void QPaintEngine::syncState()
300 Updates all dirty states in this engine. This function should ONLY
301 be used when drawing with native handles directly and immediate sync
302 from QPainters state to the native state is required.
304 void QPaintEngine::syncState()
310 static_cast<QPaintEngineEx *>(this)->sync();
313 static QPaintEngine *qt_polygon_recursion = 0;
320 \fn void QPaintEngine::drawPolygon(const QPointF *points, int pointCount,
321 PolygonDrawMode mode)
323 Reimplement this virtual function to draw the polygon defined
324 by the \a pointCount first points in \a points, using mode \a
327 \note At least one of the drawPolygon() functions must be reimplemented.
329 void QPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
331 Q_ASSERT_X(qt_polygon_recursion != this, "QPaintEngine::drawPolygon",
332 "At least one drawPolygon function must be implemented");
333 qt_polygon_recursion = this;
334 Q_ASSERT(sizeof(QT_Point) == sizeof(QPoint));
335 QVarLengthArray<QT_Point> p(pointCount);
336 for (int i = 0; i < pointCount; ++i) {
337 p[i].x = qRound(points[i].x());
338 p[i].y = qRound(points[i].y());
340 drawPolygon((QPoint *)p.data(), pointCount, mode);
341 qt_polygon_recursion = 0;
351 Reimplement this virtual function to draw the polygon defined by the
352 \a pointCount first points in \a points, using mode \a mode.
354 \note At least one of the drawPolygon() functions must be reimplemented.
356 void QPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
358 Q_ASSERT_X(qt_polygon_recursion != this, "QPaintEngine::drawPolygon",
359 "At least one drawPolygon function must be implemented");
360 qt_polygon_recursion = this;
361 Q_ASSERT(sizeof(QT_PointF) == sizeof(QPointF));
362 QVarLengthArray<QT_PointF> p(pointCount);
363 for (int i=0; i<pointCount; ++i) {
364 p[i].x = points[i].x();
365 p[i].y = points[i].y();
367 drawPolygon((QPointF *)p.data(), pointCount, mode);
368 qt_polygon_recursion = 0;
372 \enum QPaintEngine::Type
377 \value CoreGraphics Mac OS X's Quartz2D (CoreGraphics)
378 \value QuickDraw Mac OS X's QuickDraw
379 \value QWindowSystem Qt for Embedded Linux
382 \value Picture QPicture format
383 \value SVG Scalable Vector Graphics XML format
385 \value Direct3D Windows only, Direct3D based engine
386 \value Pdf Portable Document Format
388 \value User First user type ID
389 \value MaxUser Last user type ID
396 \fn bool QPaintEngine::isActive() const
398 Returns true if the paint engine is actively drawing; otherwise
405 \fn void QPaintEngine::setActive(bool state)
407 Sets the active state of the paint engine to \a state.
413 \fn bool QPaintEngine::begin(QPaintDevice *pdev)
415 Reimplement this function to initialise your paint engine when
416 painting is to start on the paint device \a pdev. Return true if
417 the initialization was successful; otherwise return false.
419 \sa end(), isActive()
423 \fn bool QPaintEngine::end()
425 Reimplement this function to finish painting on the current paint
426 device. Return true if painting was finished successfully;
427 otherwise return false.
429 \sa begin(), isActive()
434 Draws the first \a pointCount points in the buffer \a points
436 void QPaintEngine::drawPoints(const QPointF *points, int pointCount)
438 QPainter *p = painter();
442 qreal penWidth = p->pen().widthF();
446 bool ellipses = p->pen().capStyle() == Qt::RoundCap;
450 QTransform transform;
451 if (p->pen().isCosmetic()) {
452 transform = p->transform();
453 p->setTransform(QTransform());
456 p->setBrush(p->pen().brush());
457 p->setPen(Qt::NoPen);
459 for (int i=0; i<pointCount; ++i) {
460 QPointF pos = transform.map(points[i]);
461 QRectF rect(pos.x() - penWidth / 2, pos.y() - penWidth / 2, penWidth, penWidth);
464 p->drawEllipse(rect);
474 Draws the first \a pointCount points in the buffer \a points
476 The default implementation converts the first \a pointCount QPoints in \a points
477 to QPointFs and calls the floating point version of drawPoints.
480 void QPaintEngine::drawPoints(const QPoint *points, int pointCount)
482 Q_ASSERT(sizeof(QT_PointF) == sizeof(QPointF));
486 while (i < pointCount && i < 256) {
487 fp[i].x = points[i].x();
488 fp[i].y = points[i].y();
491 drawPoints((QPointF *)(void *)fp, i);
498 \fn void QPaintEngine::drawEllipse(const QRectF &rect)
500 Reimplement this function to draw the largest ellipse that can be
501 contained within rectangle \a rect.
503 The default implementation calls drawPolygon().
505 void QPaintEngine::drawEllipse(const QRectF &rect)
508 path.addEllipse(rect);
509 if (hasFeature(PainterPaths)) {
512 QPolygonF polygon = path.toFillPolygon();
513 drawPolygon(polygon.data(), polygon.size(), ConvexMode);
518 The default implementation of this function calls the floating
519 point version of this function
521 void QPaintEngine::drawEllipse(const QRect &rect)
523 drawEllipse(QRectF(rect));
527 \fn void QPaintEngine::drawPixmap(const QRectF &r, const QPixmap
528 &pm, const QRectF &sr)
530 Reimplement this function to draw the part of the \a pm
531 specified by the \a sr rectangle in the given \a r.
535 void qt_fill_tile(QPixmap *tile, const QPixmap &pixmap)
538 p.drawPixmap(0, 0, pixmap);
539 int x = pixmap.width();
540 while (x < tile->width()) {
541 p.drawPixmap(x, 0, *tile, 0, 0, x, pixmap.height());
544 int y = pixmap.height();
545 while (y < tile->height()) {
546 p.drawPixmap(0, y, *tile, 0, 0, tile->width(), y);
551 void qt_draw_tile(QPaintEngine *gc, qreal x, qreal y, qreal w, qreal h,
552 const QPixmap &pixmap, qreal xOffset, qreal yOffset)
554 qreal yPos, xPos, drawH, drawW, yOff, xOff;
557 while(yPos < y + h) {
558 drawH = pixmap.height() - yOff; // Cropping first row
559 if (yPos + drawH > y + h) // Cropping last row
560 drawH = y + h - yPos;
563 while(xPos < x + w) {
564 drawW = pixmap.width() - xOff; // Cropping first column
565 if (xPos + drawW > x + w) // Cropping last column
566 drawW = x + w - xPos;
567 if (drawW > 0 && drawH > 0)
568 gc->drawPixmap(QRectF(xPos, yPos, drawW, drawH), pixmap, QRectF(xOff, yOff, drawW, drawH));
579 Reimplement this function to draw the \a pixmap in the given \a
580 rect, starting at the given \a p. The pixmap will be
581 drawn repeatedly until the \a rect is filled.
583 void QPaintEngine::drawTiledPixmap(const QRectF &rect, const QPixmap &pixmap, const QPointF &p)
585 int sw = pixmap.width();
586 int sh = pixmap.height();
588 if (sw*sh < 8192 && sw*sh < 16*rect.width()*rect.height()) {
589 int tw = sw, th = sh;
590 while (tw*th < 32678 && tw < rect.width()/2)
592 while (tw*th < 32678 && th < rect.height()/2)
595 if (pixmap.depth() == 1) {
596 tile = QBitmap(tw, th);
598 tile = QPixmap(tw, th);
599 if (pixmap.hasAlphaChannel())
600 tile.fill(Qt::transparent);
602 qt_fill_tile(&tile, pixmap);
603 qt_draw_tile(this, rect.x(), rect.y(), rect.width(), rect.height(), tile, p.x(), p.y());
605 qt_draw_tile(this, rect.x(), rect.y(), rect.width(), rect.height(), pixmap, p.x(), p.y());
610 \fn void QPaintEngine::drawImage(const QRectF &rectangle, const QImage
611 &image, const QRectF &sr, Qt::ImageConversionFlags flags)
613 Reimplement this function to draw the part of the \a image
614 specified by the \a sr rectangle in the given \a rectangle using
615 the given conversion flags \a flags, to convert it to a pixmap.
618 void QPaintEngine::drawImage(const QRectF &r, const QImage &image, const QRectF &sr,
619 Qt::ImageConversionFlags flags)
621 QRectF baseSize(0, 0, image.width(), image.height());
624 im = im.copy(qFloor(sr.x()), qFloor(sr.y()),
625 qCeil(sr.width()), qCeil(sr.height()));
626 QPixmap pm = QPixmap::fromImage(im, flags);
627 drawPixmap(r, pm, QRectF(QPointF(0, 0), pm.size()));
631 \fn Type QPaintEngine::type() const
633 Reimplement this function to return the paint engine \l{Type}.
637 \fn void QPaintEngine::fix_neg_rect(int *x, int *y, int *w, int *h);
643 \fn bool QPaintEngine::testDirty(DirtyFlags df)
649 \fn void QPaintEngine::clearDirty(DirtyFlags df)
655 \fn void QPaintEngine::setDirty(DirtyFlags df)
661 \fn bool QPaintEngine::hasFeature(PaintEngineFeatures feature) const
663 Returns true if the paint engine supports the specified \a
664 feature; otherwise returns false.
668 \fn bool QPaintEngine::isExtended() const
672 Returns true if the paint engine is a QPaintEngineEx derivative.
676 \fn void QPaintEngine::updateState(const QPaintEngineState &state)
678 Reimplement this function to update the state of a paint engine.
680 When implemented, this function is responsible for checking the
681 paint engine's current \a state and update the properties that are
682 changed. Use the QPaintEngineState::state() function to find out
683 which properties that must be updated, then use the corresponding
684 \l {GetFunction}{get function} to retrieve the current values for
685 the given properties.
687 \sa QPaintEngineState
691 Creates a paint engine with the featureset specified by \a caps.
694 QPaintEngine::QPaintEngine(PaintEngineFeatures caps)
700 d_ptr(new QPaintEnginePrivate)
709 QPaintEngine::QPaintEngine(QPaintEnginePrivate &dptr, PaintEngineFeatures caps)
721 Destroys the paint engine.
723 QPaintEngine::~QPaintEngine()
728 Returns the paint engine's painter.
730 QPainter *QPaintEngine::painter() const
732 return state ? state->painter() : 0;
736 The default implementation ignores the \a path and does nothing.
739 void QPaintEngine::drawPath(const QPainterPath &)
741 if (hasFeature(PainterPaths)) {
742 qWarning("QPaintEngine::drawPath: Must be implemented when feature PainterPaths is set");
747 This function draws the text item \a textItem at position \a p. The
748 default implementation of this function converts the text to a
749 QPainterPath and paints the resulting path.
752 void QPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
754 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
757 path.setFillRule(Qt::WindingFill);
758 if (ti.glyphs.numGlyphs)
759 ti.fontEngine->addOutlineToPath(0, 0, ti.glyphs, &path, ti.flags);
760 if (!path.isEmpty()) {
762 painter()->setRenderHint(QPainter::Antialiasing,
763 bool((painter()->renderHints() & QPainter::TextAntialiasing)
764 && !(painter()->font().styleStrategy() & QFont::NoAntialias)));
765 painter()->translate(p.x(), p.y());
766 painter()->fillPath(path, state->pen().brush());
767 painter()->restore();
772 The default implementation splits the list of lines in \a lines
773 into \a lineCount separate calls to drawPath() or drawPolygon()
774 depending on the feature set of the paint engine.
776 void QPaintEngine::drawLines(const QLineF *lines, int lineCount)
778 for (int i=0; i<lineCount; ++i) {
779 QPointF pts[2] = { lines[i].p1(), lines[i].p2() };
781 if (pts[0] == pts[1]) {
782 if (state->pen().capStyle() != Qt::FlatCap)
787 drawPolygon(pts, 2, PolylineMode);
794 The default implementation converts the first \a lineCount lines
795 in \a lines to a QLineF and calls the floating point version of
798 void QPaintEngine::drawLines(const QLine *lines, int lineCount)
808 Q_ASSERT(sizeof(PointF) == sizeof(QPointF));
809 Q_ASSERT(sizeof(LineF) == sizeof(QLineF));
813 while (i < lineCount && i < 256) {
814 fl[i].p1.x = lines[i].x1();
815 fl[i].p1.y = lines[i].y1();
816 fl[i].p2.x = lines[i].x2();
817 fl[i].p2.y = lines[i].y2();
820 drawLines((QLineF *)(void *)fl, i);
830 The default implementation converts the first \a rectCount
831 rectangles in the buffer \a rects to a QRectF and calls the
832 floating point version of this function.
834 void QPaintEngine::drawRects(const QRect *rects, int rectCount)
842 Q_ASSERT(sizeof(RectF) == sizeof(QRectF));
846 while (i < rectCount && i < 256) {
847 fr[i].x = rects[i].x();
848 fr[i].y = rects[i].y();
849 fr[i].w = rects[i].width();
850 fr[i].h = rects[i].height();
853 drawRects((QRectF *)(void *)fr, i);
860 Draws the first \a rectCount rectangles in the buffer \a
861 rects. The default implementation of this function calls drawPath()
862 or drawPolygon() depending on the feature set of the paint engine.
864 void QPaintEngine::drawRects(const QRectF *rects, int rectCount)
866 if (hasFeature(PainterPaths) &&
867 !state->penNeedsResolving() &&
868 !state->brushNeedsResolving()) {
869 for (int i=0; i<rectCount; ++i) {
871 path.addRect(rects[i]);
877 for (int i=0; i<rectCount; ++i) {
878 QRectF rf = rects[i];
879 QPointF pts[4] = { QPointF(rf.x(), rf.y()),
880 QPointF(rf.x() + rf.width(), rf.y()),
881 QPointF(rf.x() + rf.width(), rf.y() + rf.height()),
882 QPointF(rf.x(), rf.y() + rf.height()) };
883 drawPolygon(pts, 4, ConvexMode);
890 Sets the paintdevice that this engine operates on to \a device
892 void QPaintEngine::setPaintDevice(QPaintDevice *device)
894 d_func()->pdev = device;
898 Returns the device that this engine is painting on, if painting is
899 active; otherwise returns 0.
901 QPaintDevice *QPaintEngine::paintDevice() const
903 return d_func()->pdev;
910 Returns the offset from the painters origo to the engines
911 origo. This value is used by QPainter for engines who have
912 internal double buffering.
914 This function only makes sense when the engine is active.
916 QPoint QPaintEngine::coordinateOffset() const
924 Sets the system clip for this engine. The system clip defines the
925 basis area that the engine has to draw in. All clips that are
926 set will be be an intersection with the system clip.
928 Reset the systemclip to no clip by setting an empty region.
930 void QPaintEngine::setSystemClip(const QRegion ®ion)
933 d->systemClip = region;
934 // Be backward compatible and only call d->systemStateChanged()
935 // if we currently have a system transform/viewport set.
936 if (d->hasSystemTransform || d->hasSystemViewport) {
937 d->transformSystemClip();
938 d->systemStateChanged();
945 Returns the system clip. The system clip is read only while the
946 painter is active. An empty region indicates that system clip
950 QRegion QPaintEngine::systemClip() const
952 return d_func()->systemClip;
958 Sets the target rect for drawing within the backing store. This
959 function should ONLY be used by the backing store.
961 void QPaintEngine::setSystemRect(const QRect &rect)
964 qWarning("QPaintEngine::setSystemRect: Should not be changed while engine is active");
967 d_func()->systemRect = rect;
973 Retrieves the rect for drawing within the backing store. This
974 function should ONLY be used by the backing store.
976 QRect QPaintEngine::systemRect() const
978 return d_func()->systemRect;
981 void QPaintEnginePrivate::drawBoxTextItem(const QPointF &p, const QTextItemInt &ti)
983 if (!ti.glyphs.numGlyphs)
986 // any fixes here should probably also be done in QFontEngineBox::draw
987 const int size = qRound(ti.fontEngine->ascent());
988 QVarLengthArray<QFixedPoint> positions;
989 QVarLengthArray<glyph_t> glyphs;
990 QTransform matrix = QTransform::fromTranslate(p.x(), p.y() - size);
991 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
992 if (glyphs.size() == 0)
995 QSize s(size - 3, size - 3);
997 QPainter *painter = q_func()->state->painter();
999 painter->setBrush(Qt::NoBrush);
1000 QPen pen = painter->pen();
1001 pen.setWidthF(ti.fontEngine->lineThickness().toReal());
1002 painter->setPen(pen);
1003 for (int k = 0; k < positions.size(); k++)
1004 painter->drawRect(QRectF(positions[k].toPointF(), s));