Ejemplo n.º 1
0
static QPainterPath getPathStroke(const QPainterPath &path, const RenderObject* object, const RenderStyle* style)
{ 
    QPainterPathStroker s;
    s.setWidth(KSVGPainterFactory::cssPrimitiveToLength(object, style->svgStyle()->strokeWidth(), 1.0));

    if (style->svgStyle()->capStyle() == ButtCap)
        s.setCapStyle(Qt::FlatCap);
    else if (style->svgStyle()->capStyle() == RoundCap)
        s.setCapStyle(Qt::RoundCap);

    if (style->svgStyle()->joinStyle() == MiterJoin) {
        s.setJoinStyle(Qt::MiterJoin);
        s.setMiterLimit((qreal) style->svgStyle()->strokeMiterLimit());
    } else if(style->svgStyle()->joinStyle() == RoundJoin)
        s.setJoinStyle(Qt::RoundJoin);

    const KCDashArray& dashes = KSVGPainterFactory::dashArrayFromRenderingStyle(style);
    double dashOffset = KSVGPainterFactory::cssPrimitiveToLength(object, style->svgStyle()->strokeDashOffset(), 0.0);

    unsigned int dashLength = !dashes.isEmpty() ? dashes.size() : 0;
    if(dashLength) {
        QVector<qreal> pattern;
        unsigned int count = (dashLength % 2) == 0 ? dashLength : dashLength * 2;

        for(unsigned int i = 0; i < count; i++)
            pattern.append(dashes[i % dashLength] / (float)s.width());

        s.setDashPattern(pattern);
    
        Q_UNUSED(dashOffset);
        // TODO: dash-offset, does/will qt4 API allow it? (Rob)
    }

    return s.createStroke(path);
}
Ejemplo n.º 2
0
void LineObject::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* /*widget*/)
{
    QGraphicsScene* objScene = scene();
    if(!objScene) return;

    QPen paintPen = pen();
    painter->setPen(paintPen);
    updateRubber(painter);
    if(option->state & QStyle::State_Selected)  { paintPen.setStyle(Qt::DashLine); }
    if(objScene->property(ENABLE_LWT).toBool()) { paintPen = lineWeightPen(); }
    painter->setPen(paintPen);

    if(objectRubberMode() != OBJ_RUBBER_LINE) painter->drawLine(line());

    //TODO: This is the initial concept for what realistic rendering be like. It's somewhat decent but needs improvement.
    if(objScene->property(ENABLE_LWT).toBool() && objScene->property(ENABLE_REAL).toBool())
    {
        painter->setPen(objectColor().darker(150)); //TODO: Improve this for black and dark colors
        QPainterPathStroker stroker;
        stroker.setWidth(0.35);
        stroker.setCapStyle(Qt::RoundCap);
        stroker.setJoinStyle(Qt::RoundJoin);
        QPainterPath realPath = stroker.createStroke(path());
        painter->drawPath(realPath);

        QLinearGradient grad(mapFromScene(objectMidPoint()), mapFromScene(objectEndPoint1()));
        grad.setColorAt(0, objectColor());
        grad.setColorAt(1, objectColor().darker(150)); //TODO: Improve this for black and dark colors
        grad.setSpread(QGradient::ReflectSpread);

        painter->fillPath(realPath, QBrush(grad));
    }
}
Ejemplo n.º 3
0
QRectF QAlphaPaintEnginePrivate::addPenWidth(const QPainterPath &path)
{
    Q_Q(QAlphaPaintEngine);

    QPainterPath tmp = path;

    if (m_pen.style() == Qt::NoPen)
        return (path.controlPointRect() * m_transform).boundingRect();
    bool cosmetic = qt_pen_is_cosmetic(m_pen, q->state->renderHints());
    if (cosmetic)
        tmp = path * m_transform;

    QPainterPathStroker stroker;
    if (m_pen.widthF() == 0.0f)
        stroker.setWidth(1.0);
    else
        stroker.setWidth(m_pen.widthF());
    stroker.setJoinStyle(m_pen.joinStyle());
    stroker.setCapStyle(m_pen.capStyle());
    tmp = stroker.createStroke(tmp);
    if (cosmetic)
        return tmp.controlPointRect();

    return (tmp.controlPointRect() * m_transform).boundingRect();
}
Ejemplo n.º 4
0
QPainterPath GraphicsUtils::shapeFromPath(const QPainterPath &path, const QPen &pen, double shapeStrokeWidth, bool includeOriginalPath)
{
	// this function mostly copied from QGraphicsItem::qt_graphicsItem_shapeFromPath


    // We unfortunately need this hack as QPainterPathStroker will set a width of 1.0
    // if we pass a value of 0.0 to QPainterPathStroker::setWidth()
    static const double penWidthZero = double(0.00000001);

    if (path == QPainterPath())
        return path;
    QPainterPathStroker ps;
    ps.setCapStyle(pen.capStyle());
    //ps.setCapStyle(Qt::FlatCap);
    if (shapeStrokeWidth <= 0.0)
        ps.setWidth(penWidthZero);
    else
        ps.setWidth(shapeStrokeWidth);

    ps.setJoinStyle(pen.joinStyle());
    ps.setMiterLimit(pen.miterLimit());
    QPainterPath p = ps.createStroke(path);
	if (includeOriginalPath) {
		p.addPath(path);
	}
    return p;
}
Ejemplo n.º 5
0
void LayoutBreak::draw(QPainter* painter) const
      {
      if (score()->printing() || !score()->showUnprintable())
            return;

      QPainterPathStroker stroker;
      stroker.setWidth(lw/2);
      stroker.setJoinStyle(Qt::MiterJoin);
      stroker.setCapStyle(Qt::SquareCap);

      QVector<qreal> dashes ;
      dashes.append(1);
      dashes.append(3);
      stroker.setDashPattern(dashes);
      QPainterPath stroke = stroker.createStroke(path);

      painter->fillPath(stroke, selected() ? MScore::selectColor[0] : MScore::layoutBreakColor);


      painter->setPen(QPen(selected() ? MScore::selectColor[0] : MScore::layoutBreakColor,
         lw, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin));
      painter->setBrush(Qt::NoBrush);
      painter->drawPath(path2);

      }
Ejemplo n.º 6
0
static QRectF qwtStrokedPathRect( 
    const QPainter *painter, const QPainterPath &path )
{
    QPainterPathStroker stroker;
    stroker.setWidth( painter->pen().widthF() );
    stroker.setCapStyle( painter->pen().capStyle() );
    stroker.setJoinStyle( painter->pen().joinStyle() );
    stroker.setMiterLimit( painter->pen().miterLimit() );

    QRectF rect;
    if ( qwtHasScalablePen( painter ) )
    {
        QPainterPath stroke = stroker.createStroke(path);
        rect = painter->transform().map(stroke).boundingRect();
    }
    else
    {
        QPainterPath mappedPath = painter->transform().map(path);
        mappedPath = stroker.createStroke( mappedPath );

        rect = mappedPath.boundingRect();
    }

    return rect;
}
Ejemplo n.º 7
0
QPainterPath GraphicsItemEdge::shape() const
{
    QPainterPathStroker stroker;
    stroker.setWidth(g_settings->edgeWidth);
    stroker.setCapStyle(Qt::RoundCap);
    stroker.setJoinStyle(Qt::RoundJoin);
    return stroker.createStroke(path());
}
Ejemplo n.º 8
0
QPainterPath LatexArrow::contour(qreal width) const
{
    QPainterPathStroker stroker;
    stroker.setJoinStyle(Qt::RoundJoin);
    stroker.setCapStyle(Qt::RoundCap);
    stroker.setWidth(width);

    return stroker.createStroke(path());
}
Ejemplo n.º 9
0
QPainterPath QGVEdge::shape() const
{
    QPainterPathStroker ps;
    ps.setCapStyle(_pen.capStyle());
    ps.setWidth(_pen.widthF() + 10);
    ps.setJoinStyle(_pen.joinStyle());
    ps.setMiterLimit(_pen.miterLimit());
    return ps.createStroke(_path);
}
Ejemplo n.º 10
0
QPainterPath GraphicsItemNode::shape() const
{
    //If there is only one segment and it is shorter than half its
    //width, then the arrow head will not be made with 45 degree
    //angles, but rather whatever angle is made by going from the
    //end to the back corners (the final node will be a triangle).
    if (m_hasArrow
            && m_linePoints.size() == 2
            && distance(getLast(), getSecondLast()) < m_width / 2.0)
    {
        QLineF backline = QLineF(getSecondLast(), getLast()).normalVector();
        backline.setLength(m_width / 2.0);
        QPointF backVector = backline.p2() - backline.p1();
        QPainterPath trianglePath;
        trianglePath.moveTo(getLast());
        trianglePath.lineTo(getSecondLast() + backVector);
        trianglePath.lineTo(getSecondLast() - backVector);
        trianglePath.lineTo(getLast());
        return trianglePath;
    }

    //Create a path that outlines the main node shape.
    QPainterPathStroker stroker;
    stroker.setWidth(m_width);
    stroker.setCapStyle(Qt::FlatCap);
    stroker.setJoinStyle(Qt::RoundJoin);
    QPainterPath mainNodePath = stroker.createStroke(path());

    if (!m_hasArrow)
        return mainNodePath;

    //If the node has an arrow head, subtract the part of its
    //final segment to give it a pointy end.
    //NOTE: THIS APPROACH CAN LEAD TO WEIRD EFFECTS WHEN THE NODE'S
    //POINTY END OVERLAPS WITH ANOTHER PART OF THE NODE.  PERHAPS THERE
    //IS A BETTER WAY TO MAKE ARROWHEADS?
    QLineF frontline = QLineF(getLast(), getSecondLast()).normalVector();
    frontline.setLength(m_width / 2.0);
    QPointF frontVector = frontline.p2() - frontline.p1();
    QLineF arrowheadLine(getLast(), getSecondLast());
    arrowheadLine.setLength(1.42 * (m_width / 2.0));
    arrowheadLine.setAngle(arrowheadLine.angle() + 45.0);
    QPointF arrow1 = arrowheadLine.p2();
    arrowheadLine.setAngle(arrowheadLine.angle() - 90.0);
    QPointF arrow2 = arrowheadLine.p2();
    QLineF lastSegmentLine(getSecondLast(), getLast());
    lastSegmentLine.setLength(0.01);
    QPointF additionalForwardBit = lastSegmentLine.p2() - lastSegmentLine.p1();
    QPainterPath subtractionPath;
    subtractionPath.moveTo(getLast());
    subtractionPath.lineTo(arrow1);
    subtractionPath.lineTo(getLast() + frontVector + additionalForwardBit);
    subtractionPath.lineTo(getLast() - frontVector + additionalForwardBit);
    subtractionPath.lineTo(arrow2);
    subtractionPath.lineTo(getLast());
    return mainNodePath.subtracted(subtractionPath);
}
Ejemplo n.º 11
0
QPainterPath AbstractArrow::contour(qreal width) const
{
    QPainterPath arrowPath = path();

    // if path is empty, return immediately
    if (arrowPath.isEmpty()) {
        return QPainterPath();
    }

    QPainterPathStroker stroker;
    stroker.setJoinStyle(Qt::RoundJoin);
    stroker.setCapStyle(Qt::RoundCap);
    stroker.setWidth(width + style()->penWidth().toPoint());

    return stroker.createStroke(arrowPath);
}
Ejemplo n.º 12
0
FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
{
    GraphicsContext* gc = scratchContext();
    QPainterPathStroker stroke;
    if (applier) {
        applier->strokeStyle(gc);

        QPen pen = gc->pen();
        stroke.setWidth(pen.widthF());
        stroke.setCapStyle(pen.capStyle());
        stroke.setJoinStyle(pen.joinStyle());
        stroke.setMiterLimit(pen.miterLimit());
        stroke.setDashPattern(pen.dashPattern());
        stroke.setDashOffset(pen.dashOffset());
    }
    return stroke.createStroke(m_path).boundingRect();
}
Ejemplo n.º 13
0
bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const
{
    ASSERT(applier);

    QPainterPathStroker stroke;
    GraphicsContext* gc = scratchContext();
    applier->strokeStyle(gc);

    QPen pen = gc->pen();
    stroke.setWidth(pen.widthF());
    stroke.setCapStyle(pen.capStyle());
    stroke.setJoinStyle(pen.joinStyle());
    stroke.setMiterLimit(pen.miterLimit());
    stroke.setDashPattern(pen.dashPattern());
    stroke.setDashOffset(pen.dashOffset());

    return stroke.createStroke(m_path).contains(point);
}
Ejemplo n.º 14
0
void tst_QPainterPath::testStroker()
{
    QFETCH(QPainterPath, path);
    QFETCH(QPen, pen);
    QFETCH(QPainterPath, stroke);

    QPainterPathStroker stroker;
    stroker.setWidth(pen.widthF());
    stroker.setCapStyle(pen.capStyle());
    stroker.setJoinStyle(pen.joinStyle());
    stroker.setMiterLimit(pen.miterLimit());
    stroker.setDashPattern(pen.style());
    stroker.setDashOffset(pen.dashOffset());

    QPainterPath result = stroker.createStroke(path);

    // check if stroke == result
    QVERIFY(result.subtracted(stroke).isEmpty());
    QVERIFY(stroke.subtracted(result).isEmpty());
}
FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
{
    // FIXME: We should try to use a 'shared Context' instead of creating a new ImageBuffer
    // on each call.
    OwnPtr<ImageBuffer> scratchImage = ImageBuffer::create(IntSize(1, 1));
    GraphicsContext* gc = scratchImage->context();
    QPainterPathStroker stroke;
    if (applier) {
        applier->strokeStyle(gc);

        QPen pen = gc->pen();
        stroke.setWidth(pen.widthF());
        stroke.setCapStyle(pen.capStyle());
        stroke.setJoinStyle(pen.joinStyle());
        stroke.setMiterLimit(pen.miterLimit());
        stroke.setDashPattern(pen.dashPattern());
        stroke.setDashOffset(pen.dashOffset());
    }
    return stroke.createStroke(m_path).boundingRect();
}
bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const
{
    ASSERT(applier);

    // FIXME: We should try to use a 'shared Context' instead of creating a new ImageBuffer
    // on each call.
    OwnPtr<ImageBuffer> scratchImage = ImageBuffer::create(IntSize(1, 1));
    GraphicsContext* gc = scratchImage->context();
    QPainterPathStroker stroke;
    applier->strokeStyle(gc);

    QPen pen = gc->pen();
    stroke.setWidth(pen.widthF());
    stroke.setCapStyle(pen.capStyle());
    stroke.setJoinStyle(pen.joinStyle());
    stroke.setMiterLimit(pen.miterLimit());
    stroke.setDashPattern(pen.dashPattern());
    stroke.setDashOffset(pen.dashOffset());

    return stroke.createStroke(m_path).contains(point);
}
Ejemplo n.º 17
0
QPainterPath ArrowItem::shape() const
{
    QPainterPath path;
    path.setFillRule(Qt::WindingFill);
    if (m_shaftItem &&m_shaftItem->path() != QPainterPath()) {
        QPainterPathStroker ps;
        QPen pen = m_shaftItem->pen();
        ps.setCapStyle(pen.capStyle());
        ps.setJoinStyle(pen.joinStyle());
        ps.setMiterLimit(pen.miterLimit());
        // overwrite pen width to make selection more lazy
        ps.setWidth(16.0);
        QPainterPath p = ps.createStroke(m_shaftItem->path());
        path.addPath(p);
    }
    if (m_startHeadItem)
        path.addRect(mapRectFromItem(m_startHeadItem, m_startHeadItem->boundingRect()));
    if (m_endHeadItem)
        path.addRect(mapRectFromItem(m_endHeadItem, m_endHeadItem->boundingRect()));
    return path;
}
Ejemplo n.º 18
0
QPainterPath Toolbox::shapeFromPath(const QPainterPath& path, const QPen& pen,
                                    const QBrush&         brush,
                                    const UnsignedLength& minWidth) noexcept {
  // http://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/graphicsview/qgraphicsitem.cpp
  // Function: qt_graphicsItem_shapeFromPath()

  if (path == QPainterPath() || pen == Qt::NoPen) {
    return path;
  } else {
    QPainterPathStroker ps;
    ps.setCapStyle(pen.capStyle());
    ps.setWidth(qMax(qMax(pen.widthF(), qreal(0.00000001)), minWidth->toPx()));
    ps.setJoinStyle(pen.joinStyle());
    ps.setMiterLimit(pen.miterLimit());
    QPainterPath p = ps.createStroke(path);
    if (brush != Qt::NoBrush) {
      p.addPath(path);
    }
    return p;
  }
}
Ejemplo n.º 19
0
QRectF QAlphaPaintEnginePrivate::addPenWidth(const QPainterPath &path)
{
    QPainterPath tmp = path;

    if (m_pen.style() == Qt::NoPen)
        return (path.controlPointRect() * m_transform).boundingRect();
    if (m_pen.isCosmetic())
        tmp = path * m_transform;

    QPainterPathStroker stroker;
    if (m_pen.widthF() == 0.0f)
        stroker.setWidth(1.0);
    else
        stroker.setWidth(m_pen.widthF());
    stroker.setJoinStyle(m_pen.joinStyle());
    stroker.setCapStyle(m_pen.capStyle());
    tmp = stroker.createStroke(tmp);
    if (m_pen.isCosmetic())
        return tmp.controlPointRect();

    return (tmp.controlPointRect() * m_transform).boundingRect();
}
Ejemplo n.º 20
0
void Box::draw(QPainter* painter) const
      {
      if (score() && score()->printing())
            return;
      if (selected() || editMode || dropTarget() || score()->showFrames()) {
            qreal w = spatium() * .15;
            QPainterPathStroker stroker;
            stroker.setWidth(w);
            stroker.setJoinStyle(Qt::MiterJoin);
            stroker.setCapStyle(Qt::SquareCap);

            QVector<qreal> dashes ;
            dashes.append(1);
            dashes.append(3);
            stroker.setDashPattern(dashes);
            QPainterPath path;
            w *= .5;
            path.addRect(bbox().adjusted(w, w, -w, -w));
            QPainterPath stroke = stroker.createStroke(path);
            painter->setBrush(Qt::NoBrush);
            painter->fillPath(stroke, (selected() || editMode || dropTarget()) ? MScore::selectColor[0] : MScore::frameMarginColor);
            }
      }
Ejemplo n.º 21
0
QImage BitmapHelper::drawSelection(const QImage *source, const QPainterPath &selectedPath, int scale)
{
  QImage image = *source;
  QPixmap pixmap = QPixmap::fromImage(image);
  QPainter painter(&pixmap);

  QColor selectionBorderColor = QColor(0, 0, 248, 128);
  QBrush selectionFillBrush(QColor(64, 128, 248, 128));

  QTransform transform;
  transform = transform.scale((float)scale, (float)scale);
  painter.setTransform(transform);

  painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
  painter.setRenderHint(QPainter::Antialiasing, false);
  painter.setRenderHint(QPainter::HighQualityAntialiasing, false);
  painter.setPen(selectionBorderColor);
  painter.setBrush(selectionFillBrush);

  painter.fillPath(selectedPath, selectionFillBrush);

  if (scale > 5) {
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setRenderHint(QPainter::HighQualityAntialiasing, true);

    QPainterPathStroker stroker;
    float offset = 1.0f / (float)scale;
    stroker.setWidth(offset * 2.0f);
    stroker.setJoinStyle(Qt::RoundJoin);
    stroker.setDashPattern(Qt::DashLine);

    QPainterPath strokedPath = stroker.createStroke(selectedPath);
    painter.fillPath(strokedPath, QBrush(selectionBorderColor));
  }

  return pixmap.toImage();
}
void PathStrokeRenderer::paint(QPainter *painter)
{
    if (m_points.isEmpty())
        initializePoints();

    painter->setRenderHint(QPainter::Antialiasing);

    QPalette pal = palette();
    painter->setPen(Qt::NoPen);

    // Construct the path
    QPainterPath path;
    path.moveTo(m_points.at(0));

    if (m_pathMode == LineMode) {
        for (int i=1; i<m_points.size(); ++i)
            path.lineTo(m_points.at(i));
    } else {
        int i=1;
        while (i + 2 < m_points.size()) {
            path.cubicTo(m_points.at(i), m_points.at(i+1), m_points.at(i+2));
            i += 3;
        }
        while (i < m_points.size()) {
            path.lineTo(m_points.at(i));
            ++i;
        }
    }

    // Draw the path
    {
        QColor lg = Qt::red;

        // The "custom" pen
        if (m_penStyle == Qt::NoPen) {
            QPainterPathStroker stroker;
            stroker.setWidth(m_penWidth);
            stroker.setJoinStyle(m_joinStyle);
            stroker.setCapStyle(m_capStyle);

            QVector<qreal> dashes;
            qreal space = 4;
            dashes << 1 << space
                   << 3 << space
                   << 9 << space
                   << 27 << space
                   << 9 << space
                   << 3 << space;
            stroker.setDashPattern(dashes);
            QPainterPath stroke = stroker.createStroke(path);
            painter->fillPath(stroke, lg);

        } else {
            QPen pen(lg, m_penWidth, m_penStyle, m_capStyle, m_joinStyle);
            painter->strokePath(path, pen);
        }
    }

    if (1) {
        // Draw the control points
        painter->setPen(QColor(50, 100, 120, 200));
        painter->setBrush(QColor(200, 200, 210, 120));
        for (int i=0; i<m_points.size(); ++i) {
            QPointF pos = m_points.at(i);
            painter->drawEllipse(QRectF(pos.x() - m_pointSize,
                                       pos.y() - m_pointSize,
                                       m_pointSize*2, m_pointSize*2));
        }
        painter->setPen(QPen(Qt::lightGray, 0, Qt::SolidLine));
        painter->setBrush(Qt::NoBrush);
        painter->drawPolyline(m_points);
    }

}
Ejemplo n.º 23
0
void TextLayer::recreateTexture(VidgfxContext *gfx)
{
	if(!m_isTexDirty)
		return; // Don't waste any time if it hasn't changed
	m_isTexDirty = false;

	// Delete existing texture if one exists
	if(m_texture != NULL)
		vidgfx_context_destroy_tex(gfx, m_texture);
	m_texture = NULL;

	// Determine texture size. We need to keep in mind that the text in the
	// document might extend outside of the layer's bounds.
	m_document.setTextWidth(m_rect.width());
	QSize size(
		(int)ceilf(m_document.size().width()),
		(int)ceilf(m_document.size().height()));

	if(m_document.isEmpty() || size.isEmpty()) {
		// Nothing to display
		return;
	}

	// Create temporary canvas. We need to be careful here as text is rendered
	// differently on premultiplied vs non-premultiplied pixel formats. On a
	// premultiplied format text is rendered with subpixel rendering enabled
	// while on a non-premultiplied format it is not. As we don't want subpixel
	// rendering we use the standard ARGB32 format.
	QSize imgSize(
		size.width() + m_strokeSize * 2, size.height() + m_strokeSize * 2);
	QImage img(imgSize, QImage::Format_ARGB32);
	img.fill(Qt::transparent);
	QPainter p(&img);
	p.setRenderHint(QPainter::Antialiasing, true);

	// Render text
	//m_document.drawContents(&p);

	// Render stroke
	if(m_strokeSize > 0) {
#define STROKE_TECHNIQUE 0
#if STROKE_TECHNIQUE == 0
		// Technique 0: Use QTextDocument's built-in text outliner
		//quint64 timeStart = App->getUsecSinceExec();

		QTextDocument *outlineDoc = m_document.clone(this);

		QTextCharFormat format;
		QPen pen(m_strokeColor, (double)(m_strokeSize * 2));
		pen.setJoinStyle(Qt::RoundJoin);
		format.setTextOutline(pen);
		QTextCursor cursor(outlineDoc);
		cursor.select(QTextCursor::Document);
		cursor.mergeCharFormat(format);

		// Take into account the stroke offset
		p.translate(m_strokeSize, m_strokeSize);

		//quint64 timePath = App->getUsecSinceExec();
		outlineDoc->drawContents(&p);
		delete outlineDoc;

		//quint64 timeEnd = App->getUsecSinceExec();
		//appLog() << "Path time = " << (timePath - timeStart) << " usec";
		//appLog() << "Render time = " << (timeEnd - timePath) << " usec";
		//appLog() << "Full time = " << (timeEnd - timeStart) << " usec";
#elif STROKE_TECHNIQUE == 1
		// Technique 1: Create a text QPainterPath and stroke it
		quint64 timeStart = App->getUsecSinceExec();

		// Create the path for the text's stroke
		QPainterPath path;
		QTextBlock &block = m_document.firstBlock();
		int numBlocks = m_document.blockCount();
		for(int i = 0; i < numBlocks; i++) {
			QTextLayout *layout = block.layout();
			for(int j = 0; j < layout->lineCount(); j++) {
				QTextLine &line = layout->lineAt(j);
				const QString text = block.text().mid(
					line.textStart(), line.textLength());
				QPointF pos = layout->position() + line.position();
				pos.ry() += line.ascent();
				//appLog() << pos << ": " << text;
				path.addText(pos, block.charFormat().font(), text);
			}
			block = block.next();
		}

		quint64 timePath = App->getUsecSinceExec();
		path = path.simplified(); // Fixes gaps with large stroke sizes
		quint64 timeSimplify = App->getUsecSinceExec();

		// Render the path
		//p.strokePath(path, QPen(m_strokeColor, m_strokeSize));

		// Convert it to a stroke
		QPainterPathStroker stroker;
		stroker.setWidth(m_strokeSize);
		//stroker.setCurveThreshold(2.0);
		stroker.setJoinStyle(Qt::RoundJoin);
		path = stroker.createStroke(path);

		// Render the path
		p.fillPath(path, m_strokeColor);

		quint64 timeEnd = App->getUsecSinceExec();
		appLog() << "Path time = " << (timePath - timeStart) << " usec";
		appLog() << "Simplify time = " << (timeSimplify - timePath) << " usec";
		appLog() << "Render time = " << (timeEnd - timeSimplify) << " usec";
		appLog() << "Full time = " << (timeEnd - timeStart) << " usec";
#elif STROKE_TECHNIQUE == 2
		// Technique 2: Similar to technique 1 but do each block separately
		quint64 timeStart = App->getUsecSinceExec();
		quint64 timeTotalSimplify = 0;
		quint64 timeTotalRender = 0;

		// Create the path for the text's stroke
		QTextBlock &block = m_document.firstBlock();
		int numBlocks = m_document.blockCount();
		for(int i = 0; i < numBlocks; i++) {
			// Convert this block to a painter path
			QPainterPath path;
			QTextLayout *layout = block.layout();
			for(int j = 0; j < layout->lineCount(); j++) {
				QTextLine &line = layout->lineAt(j);
				const QString text = block.text().mid(
					line.textStart(), line.textLength());
				QPointF pos = layout->position() + line.position() +
					QPointF(m_strokeSize, m_strokeSize);
				pos.ry() += line.ascent();
				//appLog() << pos << ": " << text;
				path.addText(pos, block.charFormat().font(), text);
			}

			// Prevent gaps appearing at larger stroke sizes
			quint64 timeA = App->getUsecSinceExec();
			path = path.simplified();
			quint64 timeB = App->getUsecSinceExec();
			timeTotalSimplify += timeB - timeA;

			// Render the path
			QPen pen(m_strokeColor, m_strokeSize * 2);
			pen.setJoinStyle(Qt::RoundJoin);
			p.strokePath(path, pen);
			timeA = App->getUsecSinceExec();
			timeTotalRender += timeA - timeB;

			// Iterate
			block = block.next();
		}

		// Make the final draw take into account the stroke offset
		p.translate(m_strokeSize, m_strokeSize);

		quint64 timeEnd = App->getUsecSinceExec();
		appLog() << "Simplify time = " << timeTotalSimplify << " usec";
		appLog() << "Render time = " << timeTotalRender << " usec";
		appLog() << "Full time = " << (timeEnd - timeStart) << " usec";
#elif STROKE_TECHNIQUE == 3
		// Technique 3: Raster brute-force where for each destination pixel
		// we measure the distance to the closest opaque source pixel
		quint64 timeStart = App->getUsecSinceExec();

		// Get bounding region based on text line bounding rects
		QRegion region;
		QTextBlock &block = m_document.firstBlock();
		int numBlocks = m_document.blockCount();
		for(int i = 0; i < numBlocks; i++) {
			QTextLayout *layout = block.layout();
			for(int j = 0; j < layout->lineCount(); j++) {
				QTextLine &line = layout->lineAt(j);
				const QString text = block.text().mid(
					line.textStart(), line.textLength());
				QRect rect = line.naturalTextRect()
					.translated(layout->position()).toAlignedRect();
				if(rect.isEmpty())
					continue; // Don't add empty rectangles
				rect.adjust(0, 0, 1, 0); // QTextLine is incorrect?
				rect.adjust(
					-m_strokeSize, -m_strokeSize,
					m_strokeSize, m_strokeSize);
				//appLog() << rect;
				region += rect;
			}

			// Iterate
			block = block.next();
		}
		quint64 timeRegion = App->getUsecSinceExec();

#if 0
		// Debug bounding region
		QPainterPath regionPath;
		regionPath.addRegion(region);
		regionPath.setFillRule(Qt::WindingFill);
		p.fillPath(regionPath, QColor(255, 0, 0, 128));
#endif // 0

		// We cannot read and write to the same image at the same time so
		// create a second one. Note that this is not premultiplied.
		QImage imgOut(size, QImage::Format_ARGB32);
		imgOut.fill(Qt::transparent);

		// Do distance calculation. We assume that non-fully transparent
		// pixels are always next to a fully opaque one so if the closest
		// "covered" pixel is not fully opaque then we can use that pixel's
		// opacity to determine the distance to the shape's edge.
		for(int y = 0; y < img.height(); y++) {
			for(int x = 0; x < img.width(); x++) {
				if(!region.contains(QPoint(x, y)))
					continue;
				float dist = getDistance(img, x, y, m_strokeSize);

				// We fake antialiasing by blurring the edge by 1px
				float outEdge = (float)m_strokeSize;
				if(dist >= outEdge)
					continue; // Outside stroke completely
				float opacity = qMin(1.0f, outEdge - dist);
				QColor col = m_strokeColor;
				col.setAlphaF(col.alphaF() * opacity);

				// Blend the stroke so that it appears under the existing
				// pixel data
				QRgb origRgb = img.pixel(x, y);
				QColor origCol(origRgb);
				origCol.setAlpha(qAlpha(origRgb));
				col = blendColors(col, origCol, 1.0f);
				imgOut.setPixel(x, y, col.rgba());
			}
		}
		quint64 timeRender = App->getUsecSinceExec();

		// Swap image data
		p.end();
		img = imgOut;
		p.begin(&img);

		quint64 timeEnd = App->getUsecSinceExec();
		appLog() << "Region time = " << (timeRegion - timeStart) << " usec";
		appLog() << "Render time = " << (timeRender - timeRegion) << " usec";
		appLog() << "Swap time = " << (timeEnd - timeRender) << " usec";
		appLog() << "Full time = " << (timeEnd - timeStart) << " usec";
#endif // STROKE_TECHNIQUE
	}

	// Render text
	m_document.drawContents(&p);

	// Convert the image to a GPU texture
	m_texture = vidgfx_context_new_tex(gfx, img);

	// Preview texture for debugging
	//img.save(App->getDataDirectory().filePath("Preview.png"));
}
Ejemplo n.º 24
0
void SGI_Symbol::updateCacheAndRepaint() noexcept {
  prepareGeometryChange();

  mBoundingRect = QRectF();

  mShape = QPainterPath();
  mShape.setFillRule(Qt::WindingFill);

  // cross rect
  QRectF crossRect(-4, -4, 8, 8);
  mBoundingRect = mBoundingRect.united(crossRect);
  mShape.addRect(crossRect);

  // polygons
  for (const Polygon& polygon : mLibSymbol.getPolygons()) {
    // query polygon path and line width
    QPainterPath polygonPath = polygon.getPath().toQPainterPathPx();
    qreal        w           = polygon.getLineWidth()->toPx() / 2;

    // update bounding rectangle
    mBoundingRect =
        mBoundingRect.united(polygonPath.boundingRect().adjusted(-w, -w, w, w));

    // update shape
    if (polygon.isGrabArea()) {
      QPainterPathStroker stroker;
      stroker.setCapStyle(Qt::RoundCap);
      stroker.setJoinStyle(Qt::RoundJoin);
      stroker.setWidth(2 * w);
      // add polygon area
      mShape = mShape.united(polygonPath);
      // add stroke area
      mShape = mShape.united(stroker.createStroke(polygonPath));
    }
  }

  // circles
  for (const Circle& circle : mLibSymbol.getCircles()) {
    // get circle radius, including compensation for the stroke width
    qreal w = circle.getLineWidth()->toPx() / 2;
    qreal r = circle.getDiameter()->toPx() / 2 + w;

    // get the bounding rectangle for the circle
    QPointF center = circle.getCenter().toPxQPointF();
    QRectF  boundingRect =
        QRectF(QPointF(center.x() - r, center.y() - r), QSizeF(r * 2, r * 2));

    // update bounding rectangle
    mBoundingRect = mBoundingRect.united(boundingRect);

    // update shape
    if (circle.isGrabArea()) {
      mShape.addEllipse(circle.getCenter().toPxQPointF(), r, r);
    }
  }

  // texts
  mCachedTextProperties.clear();
  for (const Text& text : mLibSymbol.getTexts()) {
    // create static text properties
    CachedTextProperties_t props;

    // get the text to display
    props.text = AttributeSubstitutor::substitute(text.getText(), &mSymbol);

    // calculate font metrics
    props.fontPixelSize = qCeil(text.getHeight()->toPx());
    mFont.setPixelSize(props.fontPixelSize);
    QFontMetricsF metrics(mFont);
    props.scaleFactor = text.getHeight()->toPx() / metrics.height();
    props.textRect    = metrics.boundingRect(
        QRectF(), text.getAlign().toQtAlign() | Qt::TextDontClip, props.text);
    QRectF scaledTextRect =
        QRectF(props.textRect.topLeft() * props.scaleFactor,
               props.textRect.bottomRight() * props.scaleFactor);

    // check rotation
    Angle absAngle = text.getRotation() + mSymbol.getRotation();
    absAngle.mapTo180deg();
    props.mirrored = mSymbol.getMirrored();
    if (!props.mirrored)
      props.rotate180 =
          (absAngle <= -Angle::deg90() || absAngle > Angle::deg90());
    else
      props.rotate180 =
          (absAngle < -Angle::deg90() || absAngle >= Angle::deg90());

    // calculate text position
    scaledTextRect.translate(text.getPosition().toPxQPointF());

    // text alignment
    if (props.rotate180)
      props.flags = text.getAlign().mirrored().toQtAlign();
    else
      props.flags = text.getAlign().toQtAlign();

    // calculate text bounding rect
    mBoundingRect  = mBoundingRect.united(scaledTextRect);
    props.textRect = QRectF(scaledTextRect.topLeft() / props.scaleFactor,
                            scaledTextRect.bottomRight() / props.scaleFactor);
    if (props.rotate180) {
      props.textRect = QRectF(-props.textRect.x(), -props.textRect.y(),
                              -props.textRect.width(), -props.textRect.height())
                           .normalized();
    }

    // save properties
    mCachedTextProperties.insert(&text, props);
  }

  update();
}
Ejemplo n.º 25
0
bool PathStrokerPlugin::run(ScribusDoc* doc, QString)
{
	ScribusDoc* currDoc = doc;
	if (currDoc == 0)
		currDoc = ScCore->primaryMainWindow()->doc;
	if (currDoc->m_Selection->count() > 0)
	{
		QVector<double> m_array;
		PageItem *currItem = currDoc->m_Selection->itemAt(0);
		FPointArray path = currItem->PoLine;
		QPainterPath pp;
		if (currItem->itemType() == PageItem::PolyLine)
			pp = path.toQPainterPath(false);
		else
			pp = path.toQPainterPath(true);
		if (currItem->NamedLStyle.isEmpty())
		{
			QPainterPathStroker stroke;
			stroke.setCapStyle(currItem->lineEnd());
			stroke.setJoinStyle(currItem->lineJoin());
			if (currItem->lineStyle() == Qt::SolidLine)
				stroke.setDashPattern(currItem->lineStyle());
			else
			{
				getDashArray(currItem->lineStyle(), 1, m_array);
				stroke.setDashPattern(m_array);
			}
			stroke.setWidth(currItem->lineWidth());
			QPainterPath result = stroke.createStroke(pp).simplified();
			if (currItem->startArrowIndex() != 0)
			{
				FPoint Start = currItem->PoLine.point(0);
				for (uint xx = 1; xx < currItem->PoLine.size(); xx += 2)
				{
					FPoint Vector = currItem->PoLine.point(xx);
					if ((Start.x() != Vector.x()) || (Start.y() != Vector.y()))
					{
						double r = atan2(Start.y()-Vector.y(),Start.x()-Vector.x())*(180.0/M_PI);
						QMatrix arrowTrans;
						FPointArray arrow = currDoc->arrowStyles.at(currItem->startArrowIndex()-1).points.copy();
						arrowTrans.translate(Start.x(), Start.y());
						arrowTrans.rotate(r);
						arrowTrans.scale(currItem->lineWidth(), currItem->lineWidth());
						arrow.map(arrowTrans);
						result.addPath(arrow.toQPainterPath(true));
						break;
					}
				}
			}
			if (currItem->endArrowIndex() != 0)
			{
				FPoint End = currItem->PoLine.point(currItem->PoLine.size()-2);
				for (uint xx = currItem->PoLine.size()-1; xx > 0; xx -= 2)
				{
					FPoint Vector = currItem->PoLine.point(xx);
					if ((End.x() != Vector.x()) || (End.y() != Vector.y()))
					{
						double r = atan2(End.y()-Vector.y(),End.x()-Vector.x())*(180.0/M_PI);
						QMatrix arrowTrans;
						FPointArray arrow = currDoc->arrowStyles.at(currItem->endArrowIndex()-1).points.copy();
						arrowTrans.translate(End.x(), End.y());
						arrowTrans.rotate(r);
						arrowTrans.scale(currItem->lineWidth(), currItem->lineWidth());
						arrow.map(arrowTrans);
						result.addPath(arrow.toQPainterPath(true));
						break;
					}
				}
			}
			currDoc->m_Selection->clear();
			PageItem* newItem = currDoc->convertItemTo(currItem, PageItem::Polygon);
			newItem->setLineWidth(0);
			newItem->setLineStyle(Qt::SolidLine);
			newItem->setFillColor(newItem->lineColor());
			newItem->setFillShade(newItem->lineShade());
			newItem->setFillTransparency(newItem->lineTransparency());
			newItem->setFillBlendmode(newItem->lineBlendmode());
			FPointArray points;
			points.fromQPainterPath(result);
			newItem->PoLine = points;
			newItem->Frame = false;
			newItem->ClipEdited = true;
			newItem->FrameType = 3;
			currDoc->AdjustItemSize(newItem);
			newItem->OldB2 = newItem->width();
			newItem->OldH2 = newItem->height();
			newItem->updateClip();
			newItem->ContourLine = newItem->PoLine.copy();
			newItem->setFillEvenOdd(true);
			currDoc->m_Selection->addItem(newItem);
		}
		else
		{
			currDoc->m_Selection->clear();
			multiLine ml = currDoc->MLineStyles[currItem->NamedLStyle];
			bool first = true;
			for (int it = ml.size()-1; it > -1; it--)
			{
				if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
				{
					QPainterPathStroker stroke;
					stroke.setCapStyle(static_cast<Qt::PenCapStyle>(ml[it].LineEnd));
					stroke.setJoinStyle(static_cast<Qt::PenJoinStyle>(ml[it].LineJoin));
					if (static_cast<Qt::PenStyle>(ml[it].Dash) == Qt::SolidLine)
						stroke.setDashPattern(static_cast<Qt::PenStyle>(ml[it].Dash));
					else
					{
						getDashArray(static_cast<Qt::PenStyle>(ml[it].Dash), 1, m_array);
						stroke.setDashPattern(m_array);
					}
					stroke.setWidth(ml[it].Width);
					QPainterPath result = stroke.createStroke(pp).simplified();
					PageItem* newItem;
					if (first)
					{
						newItem = currDoc->convertItemTo(currItem, PageItem::Polygon);
					}
					else
					{
						newItem = new PageItem_Polygon(*currItem);
						newItem->convertTo(PageItem::Polygon);
						currDoc->Items->append(newItem);
					}
					first = false;
					newItem->ItemNr = currDoc->Items->count()-1;
					newItem->setLineStyle(Qt::SolidLine);
					newItem->setFillColor(ml[it].Color);
					newItem->setFillShade(ml[it].Shade);
					newItem->setFillTransparency(newItem->lineTransparency());
					newItem->setFillBlendmode(newItem->lineBlendmode());
					newItem->setLineColor(CommonStrings::None);
					newItem->setCustomLineStyle("");
					FPointArray points;
					points.fromQPainterPath(result);
					newItem->PoLine = points;
					newItem->Frame = false;
					newItem->ClipEdited = true;
					newItem->FrameType = 3;
					currDoc->AdjustItemSize(newItem);
					newItem->OldB2 = newItem->width();
					newItem->OldH2 = newItem->height();
					newItem->updateClip();
					newItem->ContourLine = newItem->PoLine.copy();
					newItem->setFillEvenOdd(true);
					currDoc->m_Selection->addItem(newItem);
				}
			}
			if (currItem->startArrowIndex() != 0)
			{
				FPoint Start = currItem->PoLine.point(0);
				for (uint xx = 1; xx < currItem->PoLine.size(); xx += 2)
				{
					FPoint Vector = currItem->PoLine.point(xx);
					if ((Start.x() != Vector.x()) || (Start.y() != Vector.y()))
					{
						double r = atan2(Start.y()-Vector.y(),Start.x()-Vector.x())*(180.0/M_PI);
						QMatrix arrowTrans;
						FPointArray arrow = currDoc->arrowStyles.at(currItem->startArrowIndex()-1).points.copy();
						arrowTrans.translate(Start.x(), Start.y());
						arrowTrans.rotate(r);
						arrowTrans.scale(currItem->lineWidth(), currItem->lineWidth());
						arrow.map(arrowTrans);
						PageItem* newItem = new PageItem_Polygon(*currItem);
						currDoc->Items->append(newItem);
						newItem->ItemNr = currDoc->Items->count()-1;
						newItem->setLineWidth(0);
						newItem->setLineStyle(Qt::SolidLine);
						newItem->setCustomLineStyle("");
						newItem->setFillColor(newItem->lineColor());
						newItem->setFillShade(newItem->lineShade());
						newItem->setFillTransparency(newItem->lineTransparency());
						newItem->setFillBlendmode(newItem->lineBlendmode());
						newItem->PoLine = arrow;
						newItem->Frame = false;
						newItem->ClipEdited = true;
						newItem->FrameType = 3;
						currDoc->AdjustItemSize(newItem);
						newItem->OldB2 = newItem->width();
						newItem->OldH2 = newItem->height();
						newItem->updateClip();
						newItem->ContourLine = newItem->PoLine.copy();
						newItem->setFillEvenOdd(true);
						currDoc->m_Selection->addItem(newItem);
						break;
					}
				}
			}
			if (currItem->endArrowIndex() != 0)
			{
				FPoint End = currItem->PoLine.point(currItem->PoLine.size()-2);
				for (uint xx = currItem->PoLine.size()-1; xx > 0; xx -= 2)
				{
					FPoint Vector = currItem->PoLine.point(xx);
					if ((End.x() != Vector.x()) || (End.y() != Vector.y()))
					{
						double r = atan2(End.y()-Vector.y(),End.x()-Vector.x())*(180.0/M_PI);
						QMatrix arrowTrans;
						FPointArray arrow = currDoc->arrowStyles.at(currItem->endArrowIndex()-1).points.copy();
						arrowTrans.translate(End.x(), End.y());
						arrowTrans.rotate(r);
						arrowTrans.scale(currItem->lineWidth(), currItem->lineWidth());
						arrow.map(arrowTrans);
						PageItem* newItem = new PageItem_Polygon(*currItem);
						currDoc->Items->append(newItem);
						newItem->ItemNr = currDoc->Items->count()-1;
						newItem->setLineWidth(0);
						newItem->setLineStyle(Qt::SolidLine);
						newItem->setCustomLineStyle("");
						newItem->setFillColor(newItem->lineColor());
						newItem->setFillShade(newItem->lineShade());
						newItem->setFillTransparency(newItem->lineTransparency());
						newItem->setFillBlendmode(newItem->lineBlendmode());
						newItem->PoLine = arrow;
						newItem->Frame = false;
						newItem->ClipEdited = true;
						newItem->FrameType = 3;
						currDoc->AdjustItemSize(newItem);
						newItem->OldB2 = newItem->width();
						newItem->OldH2 = newItem->height();
						newItem->updateClip();
						newItem->ContourLine = newItem->PoLine.copy();
						newItem->setFillEvenOdd(true);
						currDoc->m_Selection->addItem(newItem);
						break;
					}
				}
			}
			if (currDoc->m_Selection->count() > 1)
				currDoc->itemSelection_GroupObjects(false, false);
			currDoc->m_Selection->itemAt(0)->emitAllToGUI();
		}
		currDoc->changed();
	}
	return true;
}