Example #1
0
void
PictureZoneEditor::onPaint(QPainter& painter, InteractionState const& interaction)
{
	painter.setWorldTransform(QTransform());
	painter.setRenderHint(QPainter::Antialiasing);

	if (!validateScreenPictureMask()) {
		schedulePictureMaskRebuild();
	} else {
		double const sn = sin(constants::DEG2RAD * m_pictureMaskAnimationPhase);
		double const scale = 0.5 * (sn + 1.0); // 0 .. 1
		double const opacity = 0.35 * scale + 0.15;

		QPixmap mask(m_screenPictureMask);

		{
			QPainter mask_painter(&mask);
			mask_painter.translate(-m_screenPictureMaskOrigin);
			paintOverPictureMask(mask_painter);
		}

		painter.setOpacity(opacity);
		painter.drawPixmap(m_screenPictureMaskOrigin, mask);
		painter.setOpacity(1.0);

		if (!m_pictureMaskAnimateTimer.isActive()) {
			m_pictureMaskAnimateTimer.start();
		}
	}
}
void KisCanvasWidgetBase::drawDecorations(QPainter & gc, const QRect &updateWidgetRect) const
{
    gc.save();
    if (!m_d->canvas) {
        dbgFile<<"canvas doesn't exist, in canvas widget base!";
    }
    // Setup the painter to take care of the offset; all that the
    // classes that do painting need to keep track of is resolution
    gc.setRenderHint(QPainter::Antialiasing);
    gc.setRenderHint(QPainter::TextAntialiasing);

    // This option does not do anything anymore with Qt4.6, so don't reenable it since it seems to break display
    // http://www.archivum.info/[email protected]/2010-01/00481/Re:-(Qt-interest)-Is-QPainter::HighQualityAntialiasing-render-hint-broken-in-Qt-4.6.html
    // gc.setRenderHint(QPainter::HighQualityAntialiasing);

    gc.setRenderHint(QPainter::SmoothPixmapTransform);


    gc.save();
    gc.setClipRect(updateWidgetRect);

    QTransform transform = m_d->coordinatesConverter->flakeToWidgetTransform();
    gc.setTransform(transform);

    // Paint the shapes (other than the layers)
    m_d->canvas->globalShapeManager()->paint(gc, *m_d->viewConverter, false);

    // draw green selection outlines around text shapes that are edited, so the user sees where they end
    gc.save();
    QTransform worldTransform = gc.worldTransform();
    gc.setPen( Qt::green );

    Q_FOREACH (KoShape *shape, canvas()->shapeManager()->selection()->selectedShapes()) {
        if (shape->shapeId() == "ArtisticText" || shape->shapeId() == "TextShapeID") {
            gc.setWorldTransform(shape->absoluteTransformation(m_d->viewConverter) * worldTransform);
            KoShape::applyConversion(gc, *m_d->viewConverter);
            gc.drawRect(QRectF(QPointF(), shape->size()));
        }
    }
    gc.restore();

    // Draw text shape over canvas while editing it, that's needs to show the text selection correctly
    QString toolId = KoToolManager::instance()->activeToolId();
    if (toolId == "ArtisticTextTool" || toolId == "TextTool") {
        gc.save();
        gc.setPen(Qt::NoPen);
        gc.setBrush(Qt::NoBrush);
        Q_FOREACH (KoShape *shape, canvas()->shapeManager()->selection()->selectedShapes()) {
            if (shape->shapeId() == "ArtisticText" || shape->shapeId() == "TextShapeID") {
                KoShapePaintingContext  paintContext(canvas(), false);
                gc.save();
                gc.setTransform(shape->absoluteTransformation(m_d->viewConverter) * gc.transform());
                canvas()->shapeManager()->paintShape(shape, gc, *m_d->viewConverter, paintContext);
                gc.restore();
            }
        }
        gc.restore();
    }
Example #3
0
void plotPathsToPainter(QPainter& painter, QPainterPath& path,
			const Numpy1DObj& x, const Numpy1DObj& y,
			const Numpy1DObj* scaling,
			const QRectF* clip,
			const QImage* colorimg)
{
  QRectF cliprect( QPointF(-32767,-32767), QPointF(32767,32767) );
  if( clip != 0 )
    {
      qreal x1, y1, x2, y2;
      clip->getCoords(&x1, &y1, &x2, &y2);
      cliprect.setCoords(x1, y1, x2, y2);
    }
  QRectF pathbox = path.boundingRect();
  cliprect.adjust(pathbox.left(), pathbox.top(),
		  pathbox.bottom(), pathbox.right());

  // keep track of duplicate points
  QPointF lastpt(-1e6, -1e6);
  // keep original transformation for restoration after each iteration
  QTransform origtrans(painter.worldTransform());

  // number of iterations
  int size = min(x.dim, y.dim);

  // if few color points, trim down number of paths
  if( colorimg != 0 )
    size = min(size, colorimg->width());
  // too few scaling points
  if( scaling != 0 )
    size = min(size, scaling->dim);

  // draw each path
  for(int i = 0; i < size; ++i)
    {
      const QPointF pt(x(i), y(i));
      if( cliprect.contains(pt) && ! smallDelta(lastpt, pt) )
	{
	  painter.translate(pt);
	  if( scaling != 0 )
	    {
	      // scale point if requested
	      const qreal s = (*scaling)(i);
	      painter.scale(s, s);
	    }
	  if( colorimg != 0 )
	    {
	      // get color from pixel and create a new brush
	      QBrush b( QColor::fromRgba(colorimg->pixel(i, 0)) );
	      painter.setBrush(b);
	    }

	  painter.drawPath(path);
	  painter.setWorldTransform(origtrans);
	  lastpt = pt;
	}
    }
}
Example #4
0
void KoPathPoint::paint(QPainter &painter, int handleRadius, PointTypes types, bool active)
{
    QRectF handle(-handleRadius, -handleRadius, 2*handleRadius, 2*handleRadius);

    bool drawControlPoint1 = types & ControlPoint1 && (!active || activeControlPoint1());
    bool drawControlPoint2 = types & ControlPoint2 && (!active || activeControlPoint2());

    // draw lines at the bottom
    if (drawControlPoint2)
        painter.drawLine(point(), controlPoint2());

    if (drawControlPoint1)
        painter.drawLine(point(), controlPoint1());


    QTransform worldMatrix = painter.worldTransform();

    painter.setWorldTransform(QTransform());

    // the point is lowest
    if (types & Node) {
        if (properties() & IsSmooth)
            painter.drawRect(handle.translated(worldMatrix.map(point())));
        else if (properties() & IsSymmetric) {
            QTransform matrix;
            matrix.rotate(45.0);
            QPolygonF poly(handle);
            poly = matrix.map(poly);
            poly.translate(worldMatrix.map(point()));
            painter.drawPolygon(poly);
        } else
            painter.drawEllipse(handle.translated(worldMatrix.map(point())));
    }

    // then comes control point 2
    if (drawControlPoint2)
        painter.drawEllipse(handle.translated(worldMatrix.map(controlPoint2())));

    // then comes control point 1
    if (drawControlPoint1)
        painter.drawEllipse(handle.translated(worldMatrix.map(controlPoint1())));

    painter.setWorldTransform(worldMatrix);
}
Example #5
0
void
Thumbnail::paintOverImage(
	QPainter& painter, QTransform const& image_to_display,
	QTransform const& thumb_to_display)
{	
	// We work in display coordinates because we want to be
	// pixel-accurate with what we draw.
	painter.setWorldTransform(QTransform());

	QTransform const virt_to_display(virtToThumb() * thumb_to_display);

	QRectF const inner_rect(virt_to_display.map(m_virtContentRect).boundingRect());
	
	// We extend the outer rectangle because otherwise we may get white
	// thin lines near the edges due to rounding errors and the lack
	// of subpixel accuracy.  Doing that is actually OK, because what
	// we paint will be clipped anyway.
	QRectF const outer_rect(
		virt_to_display.map(m_virtOuterRect).boundingRect().adjusted(-1.0, -1.0, 1.0, 1.0)
	);
	
	QPainterPath outer_outline;
	outer_outline.addPolygon(PolygonUtils::round(outer_rect));
	
	QPainterPath content_outline;
	content_outline.addPolygon(PolygonUtils::round(inner_rect));
	
	painter.setRenderHint(QPainter::Antialiasing, true);
	
	QColor bg_color;
	QColor fg_color;
	if (m_params.alignment().isNull()) {
		// "Align with other pages" is turned off.
		// Different color is useful on a thumbnail list to
		// distinguish "safe" pages from potentially problematic ones.
		bg_color = QColor(0x58, 0x7f, 0xf4, 70);
		fg_color = QColor(0x00, 0x52, 0xff);
	} else {
		bg_color = QColor(0xbb, 0x00, 0xff, 40);
		fg_color = QColor(0xbe, 0x5b, 0xec);
	}

	// Draw margins.
	painter.fillPath(outer_outline.subtracted(content_outline), bg_color);
	
	QPen pen(fg_color);
	pen.setCosmetic(true);
	pen.setWidthF(1.0);
	painter.setPen(pen);
	painter.setBrush(Qt::NoBrush);
	
	// toRect() is necessary because we turn off antialiasing.
	// For some reason, if we let Qt round the coordinates,
	// the result is slightly different.
	painter.drawRect(inner_rect.toRect());
}
Example #6
0
void KoPatternBackground::paint(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &/*context*/, const QPainterPath &fillPath) const
{
    Q_D(const KoPatternBackground);
    if (! d->imageData)
        return;

    painter.save();

    if (d->repeat == Tiled) {
        // calculate scaling of pixmap
        QSizeF targetSize = d->targetSize();
        QSizeF imageSize = d->imageData->imageSize();
        qreal scaleX = targetSize.width() / imageSize.width();
        qreal scaleY = targetSize.height() / imageSize.height();

        QRectF targetRect = fillPath.boundingRect();
        // undo scaling on target rectangle
        targetRect.setWidth(targetRect.width() / scaleX);
        targetRect.setHeight(targetRect.height() / scaleY);

        // determine pattern offset
        QPointF offset = d->offsetFromRect(targetRect, imageSize);

        // create matrix for pixmap scaling
        QTransform matrix;
        matrix.scale(scaleX, scaleY);

        painter.setClipPath(fillPath);
        painter.setWorldTransform(matrix, true);
        painter.drawTiledPixmap(targetRect, d->imageData->pixmap(imageSize.toSize()), -offset);
    } else if (d->repeat == Original) {
        QRectF sourceRect(QPointF(0, 0), d->imageData->imageSize());
        QRectF targetRect(QPoint(0, 0), d->targetSize());
        targetRect.moveCenter(fillPath.boundingRect().center());
        painter.setClipPath(fillPath);
        painter.drawPixmap(targetRect, d->imageData->pixmap(sourceRect.size().toSize()), sourceRect);
    } else if (d->repeat == Stretched) {
        painter.setClipPath(fillPath);
        // undo conversion of the scaling so that we can use a nicely scaled image of the correct size
        qreal zoomX, zoomY;
        converter.zoom(&zoomX, &zoomY);
        zoomX = zoomX ? 1 / zoomX : zoomX;
        zoomY = zoomY ? 1 / zoomY : zoomY;
        painter.scale(zoomX, zoomY);

        QRectF targetRect = converter.documentToView(fillPath.boundingRect());
        painter.drawPixmap(targetRect.topLeft(), d->imageData->pixmap(targetRect.size().toSize()));
    }

    painter.restore();
}
Example #7
0
void
ImageView::onPaint(QPainter& painter, InteractionState const& interaction)
{
	painter.setRenderHint(QPainter::Antialiasing, false);
	painter.setRenderHint(QPainter::SmoothPixmapTransform, true);

	painter.setPen(Qt::NoPen);
	QRectF const virt_rect(virtualDisplayRect());

	switch (m_virtLayout.type()) {
		case PageLayout::SINGLE_PAGE_UNCUT:
			painter.setBrush(QColor(0, 0, 255, 50));
			painter.drawRect(virt_rect);
			return; // No Split Line will be drawn.
		case PageLayout::SINGLE_PAGE_CUT:
			painter.setBrush(QColor(0, 0, 255, 50));
			painter.drawPolygon(m_virtLayout.singlePageOutline());
			break;
		case PageLayout::TWO_PAGES:
			painter.setBrush(m_leftPageRemoved ? QColor(0, 0, 0, 80) : QColor(0, 0, 255, 50));
			painter.drawPolygon(m_virtLayout.leftPageOutline());
			painter.setBrush(m_rightPageRemoved ? QColor(0, 0, 0, 80) : QColor(255, 0, 0, 50));
			painter.drawPolygon(m_virtLayout.rightPageOutline());
			break;
	}

	painter.setRenderHint(QPainter::Antialiasing, true);
	painter.setWorldTransform(QTransform());

	QPen pen(QColor(0, 0, 255));
	pen.setCosmetic(true);
	pen.setWidth(2);
	painter.setPen(pen);
	painter.setBrush(Qt::NoBrush);

	int const num_cutters = m_virtLayout.numCutters();
	for (int i = 0; i < num_cutters; ++i) {
		QLineF const cutter(widgetCutterLine(i));
		painter.drawLine(cutter);
		
		QRectF rect(m_handlePixmap.rect());

		rect.moveCenter(cutter.p1());
		painter.drawPixmap(rect.topLeft(), m_handlePixmap);

		rect.moveCenter(cutter.p2());
		painter.drawPixmap(rect.topLeft(), m_handlePixmap);
	}
}
void Tile::paintCheckerPattern(GraphicsContext* context, const FloatRect& target)
{
    QPainter* painter = context->platformContext();
    QTransform worldTransform = painter->worldTransform();
    qreal scaleX = worldTransform.m11();
    qreal scaleY = worldTransform.m22();
    
    QRect targetViewRect = QRectF(target.x() * scaleX,
                                  target.y() * scaleY,
                                  target.width() * scaleX,
                                  target.height() * scaleY).toAlignedRect();
    
    QTransform adjustedTransform(1., worldTransform.m12(), worldTransform.m13(),
                  worldTransform.m21(), 1., worldTransform.m23(),
                  worldTransform.m31(), worldTransform.m32(), worldTransform.m33());
    painter->setWorldTransform(adjustedTransform);
    
    painter->drawTiledPixmap(targetViewRect,
                             checkeredPixmap(),
                             QPoint(targetViewRect.left() % checkerSize,
                                    targetViewRect.top() % checkerSize));
    
    painter->setWorldTransform(worldTransform);
}
Example #9
0
void CGContextDrawLayerInRect(CGContextRef context, CGRect rect, CGLayerRef layer)
{
	QPainter* painter = CGContextGetPainter(context);
	QTransform tf = painter->worldTransform();
	qreal sx, sy;
	CGSize origSize = CGLayerGetSize(layer);
	
	sx = CGRectGetWidth(rect) / origSize.width;
	sy = CGRectGetHeight(rect) / origSize.height;
	
	painter->scale(sx, sy);
	
	painter->drawPicture(QPointF(rect.origin.x / sx, rect.origin.y / sy), *layer->picture);
	
	painter->setWorldTransform(tf);
}
void
DewarpingView::paintXSpline(
	QPainter& painter, InteractionState const& interaction,
	InteractiveXSpline const& ispline)
{
	XSpline const& spline = ispline.spline();

	painter.save();
	painter.setBrush(Qt::NoBrush);

#if 0 // No point in drawing the curve itself - we already draw the grid.
	painter.setWorldTransform(imageToVirtual() * virtualToWidget());
	
	QPen curve_pen(Qt::blue);
	curve_pen.setWidthF(1.5);
	curve_pen.setCosmetic(true);
	painter.setPen(curve_pen);
	
	std::vector<QPointF> const polyline(spline.toPolyline());
	painter.drawPolyline(&polyline[0], polyline.size());
#endif

	// Drawing cosmetic points in transformed coordinates seems unreliable,
	// so let's draw them in widget coordinates.
	painter.setWorldMatrixEnabled(false);

	QPen existing_point_pen(Qt::red);
	existing_point_pen.setWidthF(4.0);
	existing_point_pen.setCosmetic(true);
	painter.setPen(existing_point_pen);

	int const num_control_points = spline.numControlPoints();
	for (int i = 0; i < num_control_points; ++i) {
		painter.drawPoint(sourceToWidget(spline.controlPointPosition(i)));
	}

	QPointF pt;
	if (ispline.curveIsProximityLeader(interaction, &pt)) {
		QPen new_point_pen(existing_point_pen);
		new_point_pen.setColor(QColor(0x00ffff));
		painter.setPen(new_point_pen);
		painter.drawPoint(pt);
	}

	painter.restore();
}
void
DewarpingView::onPaint(QPainter& painter, InteractionState const& interaction)
{
	painter.setRenderHint(QPainter::Antialiasing);

	painter.setPen(Qt::NoPen);
	painter.setBrush(QColor(0xff, 0xff, 0xff, 150)); // Translucent white.
	painter.drawPolygon(virtMarginArea(0)); // Left margin.
	painter.drawPolygon(virtMarginArea(1)); // Right margin.

	painter.setWorldTransform(imageToVirtual() * painter.worldTransform());
	painter.setBrush(Qt::NoBrush);

	QPen grid_pen;
	grid_pen.setColor(Qt::blue);
	grid_pen.setCosmetic(true);
	grid_pen.setWidthF(1.2);

	painter.setPen(grid_pen);
	painter.setBrush(Qt::NoBrush);
	
	int const num_vert_grid_lines = 30;
	int const num_hor_grid_lines = 30;

	bool valid_model = m_distortionModel.isValid();

	if (valid_model) {
		try {
			std::vector<QVector<QPointF> > curves(num_hor_grid_lines);

			dewarping::CylindricalSurfaceDewarper dewarper(
				m_distortionModel.topCurve().polyline(),
				m_distortionModel.bottomCurve().polyline(), m_depthPerception.value()
			);
			dewarping::CylindricalSurfaceDewarper::State state;

			for (int j = 0; j < num_vert_grid_lines; ++j) {
				double const x = j / (num_vert_grid_lines - 1.0);
				dewarping::CylindricalSurfaceDewarper::Generatrix const gtx(dewarper.mapGeneratrix(x, state));
				QPointF const gtx_p0(gtx.imgLine.pointAt(gtx.pln2img(0)));
				QPointF const gtx_p1(gtx.imgLine.pointAt(gtx.pln2img(1)));
				painter.drawLine(gtx_p0, gtx_p1);
				for (int i = 0; i < num_hor_grid_lines; ++i) {
					double const y = i / (num_hor_grid_lines - 1.0);
					curves[i].push_back(gtx.imgLine.pointAt(gtx.pln2img(y)));
				}
			}

			BOOST_FOREACH(QVector<QPointF> const& curve, curves) {
				painter.drawPolyline(curve);
			}
		} catch (std::runtime_error const&) {
			// Still probably a bad model, even though DistortionModel::isValid() was true.
			valid_model = false;
		}
	} // valid_model

	if (!valid_model) {
		// Just draw the frame.
		dewarping::Curve const& top_curve = m_distortionModel.topCurve();
		dewarping::Curve const& bottom_curve = m_distortionModel.bottomCurve();
		painter.drawLine(top_curve.polyline().front(), bottom_curve.polyline().front());
		painter.drawLine(top_curve.polyline().back(), bottom_curve.polyline().back());
		painter.drawPolyline(QVector<QPointF>::fromStdVector(top_curve.polyline()));
		painter.drawPolyline(QVector<QPointF>::fromStdVector(bottom_curve.polyline()));
	}

	paintXSpline(painter, interaction, m_topSpline);
	paintXSpline(painter, interaction, m_bottomSpline);
}
void GraphicsWidget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event)

	//set up painting with antialiasing etc
	QPainter painter;

	painter.begin(&elements);
	painter.setRenderHint(QPainter::Antialiasing);
	painter.setRenderHint(QPainter::HighQualityAntialiasing);
	painter.setRenderHint(QPainter::SmoothPixmapTransform);

	//transform coordinates to fit everything neatly on the screen
	painter.save();
	painter.setWorldTransform(getCurrentTransform());

	if (grid != nullptr)
	{
		//loop through and draw each entry
		for (const auto& cell: grid->getCells())
		{
			GridEntry &entry = grid->getEntry(cell);
			if (entry.modified) {
				entry.modified = false;
				painter.save();

				painter.translate(cell.x(), cell.y());

				QPen pen(Qt::black);
				pen.setWidthF(0);

				painter.setPen(pen);
				if (entry.type == GridEntry::Wall)
					painter.setBrush(Qt::darkBlue);

				else if (entry.type == GridEntry::Start)
					painter.setBrush(Qt::yellow);

				else if (entry.type == GridEntry::End)
					painter.setBrush(Qt::red);

				else if (entry.path)
					painter.setBrush(Qt::white);

				else if (entry.searched)
					painter.setBrush(Qt::cyan);
				
				else
					painter.setBrush(Qt::darkGreen);

                painter.drawConvexPolygon(DISPLAY_HEXAGON);

				painter.restore();
			}
		}
	}

	painter.restore();
	painter.setPen(Qt::white);

	QPainter screenPainter(this);
	screenPainter.fillRect(rect(), QBrush(Qt::black));
	screenPainter.drawImage(0, 0, elements);
}
Example #13
0
void PictureShape::paint(QPainter &painter, const KoViewConverter &converter,
                         KoShapePaintingContext &paintContext)
{
    Q_UNUSED(paintContext);

    QRectF viewRect = converter.documentToView(QRectF(QPointF(0,0), size()));
    if (imageData() == 0) {
        painter.fillRect(viewRect, QColor(Qt::gray));
        return;
    }

    painter.save();
    applyConversion(painter, converter);
    paintBorder(painter, converter);
    painter.restore();

    QSize pixmapSize = calcOptimalPixmapSize(viewRect.size(), imageData()->image().size());

    // Normalize the clipping rect if it isn't already done.
    m_clippingRect.normalize(imageData()->imageSize());

    // Handle style:mirror, i.e. mirroring horizontally and/or vertically.
    // 
    // NOTE: At this time we don't handle HorizontalOnEven
    //       and HorizontalOnOdd, which have to know which
    //       page they are on.  In those cases we treat it as
    //       no horizontal mirroring at all.
    bool   doFlip = false;
    QSizeF shapeSize = size();
    QSizeF viewSize = converter.documentToView(shapeSize);
    qreal  midpointX = 0.0;
    qreal  midpointY = 0.0;
    qreal  scaleX = 1.0;
    qreal  scaleY = 1.0;
    if (m_mirrorMode & MirrorHorizontal) {
        midpointX = viewSize.width() / qreal(2.0);
        scaleX = -1.0;
        doFlip = true;
    }
    if (m_mirrorMode & MirrorVertical) {
        midpointY = viewSize.height() / qreal(2.0);
        scaleY = -1.0;
        doFlip = true;
    }
    if (doFlip) {
        QTransform outputTransform = painter.transform();
        QTransform worldTransform  = QTransform();

        //kDebug(31000) << "Flipping" << midpointX << midpointY << scaleX << scaleY;
        worldTransform.translate(midpointX, midpointY);
        worldTransform.scale(scaleX, scaleY);
        worldTransform.translate(-midpointX, -midpointY);
        //kDebug(31000) << "After flipping for window" << worldTransform;

        QTransform newTransform = worldTransform * outputTransform;
        painter.setWorldTransform(newTransform);
    }

    // Paint the image as prepared in waitUntilReady()
    if (!m_printQualityImage.isNull() && pixmapSize != m_printQualityRequestedSize) {
        QSizeF imageSize = m_printQualityImage.size();
        QRectF cropRect(
            imageSize.width()  * m_clippingRect.left,
            imageSize.height() * m_clippingRect.top,
            imageSize.width()  * m_clippingRect.width(),
            imageSize.height() * m_clippingRect.height()
        );

        painter.drawImage(viewRect, m_printQualityImage, cropRect);
        m_printQualityImage = QImage(); // free memory
    }
    else {
        QPixmap pixmap;
        QString key(generate_key(imageData()->key(), pixmapSize));

        // If the required pixmap is not in the cache
        // launch a task in a background thread that scales
        // the source image to the required size
        if (!QPixmapCache::find(key, &pixmap)) {
            QThreadPool::globalInstance()->start(new _Private::PixmapScaler(this, pixmapSize));
            painter.fillRect(viewRect, QColor(Qt::gray)); // just paint a gray rect as long as we don't have the required pixmap
        }
        else {
            QRectF cropRect(
                pixmapSize.width()  * m_clippingRect.left,
                pixmapSize.height() * m_clippingRect.top,
                pixmapSize.width()  * m_clippingRect.width(),
                pixmapSize.height() * m_clippingRect.height()
            );

            painter.drawPixmap(viewRect, pixmap, cropRect);
        }
    }
}
Example #14
0
void
IncompleteThumbnail::drawQuestionMark(QPainter& painter, QRectF const& bounding_rect)
{
	QString const text(QString::fromAscii("?"));
	
	// Because painting happens only from the main thread, we don't
	// need to care about concurrent access.
	if (m_sCachedPath.isEmpty()) {
#if 0
		QFont font(painter.font());
		font.setWeight(QFont::DemiBold);
		font.setStyleStrategy(QFont::ForceOutline);
		m_sCachedPath.addText(0, 0, font, text);
#else
		m_sCachedPath.moveTo(QPointF(4.42188, -2.40625));
		m_sCachedPath.cubicTo(
			QPointF(4.42188, -3.20312),
			QPointF(4.51562, -3.32812),
			QPointF(5.23438, -3.84375)
		);
		m_sCachedPath.cubicTo(
			QPointF(6.34375, -4.625),
			QPointF(6.67188, -5.15625),
			QPointF(6.67188, -6.17188)
		);
		m_sCachedPath.cubicTo(
			QPointF(6.67188, -7.79688),
			QPointF(5.4375, -8.92188),
			QPointF(3.6875, -8.92188)
		);
		m_sCachedPath.cubicTo(
			QPointF(2.65625, -8.92188),
			QPointF(1.84375, -8.5625),
			QPointF(1.32812, -7.85938)
		);
		m_sCachedPath.cubicTo(
			QPointF(0.9375, -7.32812),
			QPointF(0.78125, -6.75),
			QPointF(0.765625, -5.76562)
		);
		m_sCachedPath.lineTo(QPointF(2.40625, -5.76562));
		m_sCachedPath.lineTo(QPointF(2.40625, -5.79688));
		m_sCachedPath.cubicTo(
			QPointF(2.34375, -6.76562),
			QPointF(2.92188, -7.51562),
			QPointF(3.71875, -7.51562)
		);
		m_sCachedPath.cubicTo(
			QPointF(4.4375, -7.51562),
			QPointF(4.98438, -6.90625),
			QPointF(4.98438, -6.125)
		);
		m_sCachedPath.cubicTo(
			QPointF(4.98438, -5.59375),
			QPointF(4.82812, -5.35938),
			QPointF(4.125, -4.78125)
		);
		m_sCachedPath.cubicTo(
			QPointF(3.17188, -3.96875),
			QPointF(2.90625, -3.4375),
			QPointF(2.9375, -2.40625)
		);
		m_sCachedPath.lineTo(QPointF(4.42188, -2.40625));
		m_sCachedPath.moveTo(QPointF(4.625, -1.75));
		m_sCachedPath.lineTo(QPointF(2.8125, -1.75));
		m_sCachedPath.lineTo(QPointF(2.8125, 0.0));
		m_sCachedPath.lineTo(QPointF(4.625, 0.0));
		m_sCachedPath.lineTo(QPointF(4.625, -1.75));
#endif
	}
	
	QRectF const text_rect(m_sCachedPath.boundingRect());
	
	QTransform xform1;
	xform1.translate(-text_rect.left(), -text_rect.top());
	
	QSizeF const unscaled_size(text_rect.size());
	QSizeF scaled_size(unscaled_size);
	scaled_size.scale(bounding_rect.size() * 0.9, Qt::KeepAspectRatio);
	
	double const hscale = scaled_size.width() / unscaled_size.width();
	double const vscale = scaled_size.height() / unscaled_size.height();
	QTransform xform2;
	xform2.scale(hscale, vscale);
	
	// Position the text at the center of our bounding rect.
	QSizeF const translation(bounding_rect.size() * 0.5 - scaled_size * 0.5);
	QTransform xform3;
	xform3.translate(translation.width(), translation.height());
	
	painter.setWorldTransform(xform1 * xform2 * xform3, true);
	painter.setRenderHint(QPainter::Antialiasing);
	
	QPen pen(QColor(0x00, 0x00, 0x00, 60));
	pen.setWidth(2);
	pen.setCosmetic(true);
	painter.setPen(pen);
	
	painter.drawPath(m_sCachedPath);
}