예제 #1
0
void ScreenPainter::drawGlyphOutline(const GlyphLayout gl, bool fill)
{
	if (fill)
		drawGlyph(gl);
	m_painter->save();
	bool fr = m_painter->fillRule();
	m_painter->setFillRule(false);

	setupState(false);
	m_painter->translate(0, -(fontSize() * gl.scaleV));

	FPointArray outline = font().glyphOutline(gl.glyph);
	double scaleHv = gl.scaleH * fontSize() / 10.0;
	double scaleVv = gl.scaleV * fontSize() / 10.0;
	QTransform trans;
	trans.scale(scaleHv, scaleVv);
	outline.map(trans);
	m_painter->setupPolygon(&outline, true);
	if (outline.size() > 3)
	{
		m_painter->setLineWidth(strokeWidth());
		m_painter->strokePath();
	}

	m_painter->setFillRule(fr);
	m_painter->restore();

}
예제 #2
0
QRectF QSvgEllipse::bounds(QPainter *p, QSvgExtraStates &) const
{
    QPainterPath path;
    path.addEllipse(m_bounds);
    qreal sw = strokeWidth(p);
    return qFuzzyIsNull(sw) ? p->transform().map(path).boundingRect() : boundsOnStroke(p, path, sw);
}
예제 #3
0
void LayoutSVGRect::updateStrokeAndFillBoundingBoxes()
{
    SVGLengthContext lengthContext(toSVGRectElement(element()));
    FloatSize boundingBoxSize(
        lengthContext.valueForLength(styleRef().width(), styleRef(), SVGLengthMode::Width),
        lengthContext.valueForLength(styleRef().height(), styleRef(), SVGLengthMode::Height));

    // Spec: "A negative value is an error."
    if (boundingBoxSize.width() < 0 || boundingBoxSize.height() < 0) {
        m_fillBoundingBox = FloatRect();
        m_strokeBoundingBox = FloatRect();
        return;
    }

    if (m_usePathFallback) {
        // Spec: "A value of zero disables rendering of the element." so we can skip
        // the path fallback and rely on the existing bounding box calculation.
        if (!boundingBoxSize.isEmpty()) {
            LayoutSVGShape::updateStrokeAndFillBoundingBoxes();
            return;
        }
        m_usePathFallback = false;
        clearPath();
    }

    m_fillBoundingBox = FloatRect(
        FloatPoint(
            lengthContext.valueForLength(styleRef().svgStyle().x(), styleRef(), SVGLengthMode::Width),
            lengthContext.valueForLength(styleRef().svgStyle().y(), styleRef(), SVGLengthMode::Height)),
        boundingBoxSize);
    m_strokeBoundingBox = m_fillBoundingBox;
    if (style()->svgStyle().hasStroke())
        m_strokeBoundingBox.inflate(strokeWidth() / 2);
}
예제 #4
0
void RenderSVGEllipse::updateShapeFromElement()
{
    // Before creating a new object we need to clear the cached bounding box
    // to avoid using garbage.
    m_fillBoundingBox = FloatRect();
    m_strokeBoundingBox = FloatRect();
    m_center = FloatPoint();
    m_radii = FloatSize();

    calculateRadiiAndCenter();

    // Spec: "A negative value is an error. A value of zero disables rendering of the element."
    if (m_radii.width() < 0 || m_radii.height() < 0)
        return;

    if (!m_radii.isEmpty()) {
        // Fallback to RenderSVGShape if shape has a non-scaling stroke.
        if (hasNonScalingStroke()) {
            RenderSVGShape::updateShapeFromElement();
            m_usePathFallback = true;
            return;
        }
        m_usePathFallback = false;
    }

    m_fillBoundingBox = FloatRect(m_center.x() - m_radii.width(), m_center.y() - m_radii.height(), 2 * m_radii.width(), 2 * m_radii.height());
    m_strokeBoundingBox = m_fillBoundingBox;
    if (style()->svgStyle()->hasStroke())
        m_strokeBoundingBox.inflate(strokeWidth() / 2);
}
예제 #5
0
FloatRect RenderSVGShape::calculateStrokeBoundingBox() const
{
    ASSERT(m_path);
    FloatRect strokeBoundingBox = m_fillBoundingBox;

    const SVGRenderStyle& svgStyle = style().svgStyle();
    if (svgStyle.hasStroke()) {
        BoundingRectStrokeStyleApplier strokeStyle(*this);
        if (hasNonScalingStroke()) {
            AffineTransform nonScalingTransform = nonScalingStrokeTransform();
            if (Optional<AffineTransform> inverse = nonScalingTransform.inverse()) {
                Path* usePath = nonScalingStrokePath(m_path.get(), nonScalingTransform);
                FloatRect strokeBoundingRect = usePath->strokeBoundingRect(&strokeStyle);
                strokeBoundingRect = inverse.value().mapRect(strokeBoundingRect);
                strokeBoundingBox.unite(strokeBoundingRect);
            }
        } else
            strokeBoundingBox.unite(path().strokeBoundingRect(&strokeStyle));
    }

    if (!m_markerPositions.isEmpty())
        strokeBoundingBox.unite(markerRect(strokeWidth()));

    return strokeBoundingBox;
}
예제 #6
0
void RenderSVGRect::strokeShape(GraphicsContext* context) const
{
    if (!isPaintingFallback()) {
        context->strokeRect(m_boundingBox, strokeWidth());
        return;
    }
    RenderSVGShape::strokeShape(context);
}
LayoutRect LayoutSVGShape::clippedOverflowRectForPaintInvalidation(
    const LayoutBoxModelObject* paintInvalidationContainer,
    const PaintInvalidationState* paintInvalidationState) const
{
    const float strokeWidthForHairlinePadding = style()->svgStyle().hasStroke() ? strokeWidth() : 0;
    return SVGLayoutSupport::clippedOverflowRectForPaintInvalidation(*this,
        paintInvalidationContainer, paintInvalidationState, strokeWidthForHairlinePadding);
}
예제 #8
0
QRectF QSvgArc::bounds() const
{
    qreal sw = strokeWidth();
    if (qFuzzyCompare(sw + 1, 1))
        return m_cachedBounds;
    else {
        return boundsOnStroke(cubic, sw);
    }
}
예제 #9
0
void ScreenPainter::setupState(bool rect)
{
	if (selected() && rect)
	{
		// we are drawing a selection rect
		QColor color = qApp->palette().color(QPalette::Active, QPalette::Highlight);
		m_painter->setBrush(color);
		m_painter->setPen(color, strokeWidth(), Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
	}
	else if (selected())
	{
		// we are drawing selected text
		QColor color = qApp->palette().color(QPalette::Active, QPalette::HighlightedText);
		m_painter->setBrush(color);
		m_painter->setPen(color, strokeWidth(), Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
	}
	else
	{
		QColor tmp;
		if (m_fillColor != fillColor())
		{
			m_item->SetQColor(&tmp, fillColor().color, fillColor().shade);
			m_fillQColor = tmp;
			m_fillColor = fillColor();
		}
		if (m_strokeColor != strokeColor())
		{
			m_item->SetQColor(&tmp, strokeColor().color, strokeColor().shade);
			m_fillStrokeQColor = tmp;
			m_strokeColor = strokeColor();
		}
		m_painter->setBrush(m_fillQColor);
		m_painter->setPen(m_fillStrokeQColor, strokeWidth(), Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
	}

	m_painter->translate(x(), y());
	if (scaleH() != 1.0 || scaleV() != 1.0)
		m_painter->scale(scaleH(), scaleV());

	if (matrix() != QTransform())
	{
		m_painter->setWorldMatrix(matrix() * m_painter->worldMatrix());
	}
}
예제 #10
0
QRectF QSvgCircle::bounds() const
{
    qreal sw = strokeWidth();
    if (qFuzzyCompare(sw + 1, 1))
        return m_bounds;
    else {
        QPainterPath path;
        path.addRect(m_bounds);
        return boundsOnStroke(path, sw);
    }
}
예제 #11
0
QRectF QSvgPolyline::bounds(QPainter *p, QSvgExtraStates &) const
{
    qreal sw = strokeWidth(p);
    if (qFuzzyIsNull(sw)) {
        return p->transform().map(m_poly).boundingRect();
    } else {
        QPainterPath path;
        path.addPolygon(m_poly);
        return boundsOnStroke(p, path, sw);
    }
}
예제 #12
0
QRectF QSvgPolyline::bounds() const
{
    qreal sw = strokeWidth();
    if (qFuzzyCompare(sw + 1, 1))
        return m_poly.boundingRect();
    else {
        QPainterPath path;
        path.addPolygon(m_poly);
        return boundsOnStroke(path, sw);
    }
}
예제 #13
0
QRectF QSvgRect::bounds(QPainter *p, QSvgExtraStates &) const
{
    qreal sw = strokeWidth(p);
    if (qFuzzyIsNull(sw)) {
        return p->transform().mapRect(m_rect);
    } else {
        QPainterPath path;
        path.addRect(m_rect);
        return boundsOnStroke(p, path, sw);
    }
}
예제 #14
0
void RenderSVGRect::strokeShape(GraphicsContext* context) const
{
    if (!style()->svgStyle()->hasVisibleStroke())
        return;

    if (m_usePathFallback) {
        RenderSVGShape::strokeShape(context);
        return;
    }

    context->strokeRect(m_fillBoundingBox, strokeWidth());
}
예제 #15
0
QRectF QSvgLine::bounds() const
{
    qreal sw = strokeWidth();
    if (qFuzzyCompare(sw + 1, 1)) {
        qreal minX = qMin(m_bounds.x1(), m_bounds.x2());
        qreal minY = qMin(m_bounds.y1(), m_bounds.y2());
        qreal maxX = qMax(m_bounds.x1(), m_bounds.x2());
        qreal maxY = qMax(m_bounds.y1(), m_bounds.y2());
        return QRectF(minX, minY, maxX-minX, maxY-minY);
    } else {
        QPainterPath path;
        path.moveTo(m_bounds.x1(), m_bounds.y1());
        path.lineTo(m_bounds.x2(), m_bounds.y2());
        return boundsOnStroke(path, sw);
    }
}
예제 #16
0
bool LayoutSVGEllipse::shapeDependentStrokeContains(const FloatPoint& point)
{
    // The optimized check below for circles does not support non-scaling or
    // discontinuous strokes.
    if (m_usePathFallback
        || !hasContinuousStroke()
        || m_radii.width() != m_radii.height()) {
        if (!hasPath())
            createPath();
        return LayoutSVGShape::shapeDependentStrokeContains(point);
    }

    const FloatPoint center = FloatPoint(m_center.x() - point.x(), m_center.y() - point.y());
    const float halfStrokeWidth = strokeWidth() / 2;
    const float r = m_radii.width();
    return std::abs(center.length() - r) <= halfStrokeWidth;
}
예제 #17
0
QRectF QSvgLine::bounds(QPainter *p, QSvgExtraStates &) const
{
    qreal sw = strokeWidth(p);
    if (qFuzzyIsNull(sw)) {
        QPointF p1 = p->transform().map(m_line.p1());
        QPointF p2 = p->transform().map(m_line.p2());
        qreal minX = qMin(p1.x(), p2.x());
        qreal minY = qMin(p1.y(), p2.y());
        qreal maxX = qMax(p1.x(), p2.x());
        qreal maxY = qMax(p1.y(), p2.y());
        return QRectF(minX, minY, maxX - minX, maxY - minY);
    } else {
        QPainterPath path;
        path.moveTo(m_line.p1());
        path.lineTo(m_line.p2());
        return boundsOnStroke(p, path, sw);
    }
}
예제 #18
0
void LayoutSVGRect::updateShapeFromElement()
{
    // Before creating a new object we need to clear the cached bounding box
    // to avoid using garbage.
    m_fillBoundingBox = FloatRect();
    m_strokeBoundingBox = FloatRect();
    m_usePathFallback = false;
    SVGRectElement* rect = toSVGRectElement(element());
    ASSERT(rect);

    SVGLengthContext lengthContext(rect);
    FloatSize boundingBoxSize(
        lengthContext.valueForLength(styleRef().width(), styleRef(), SVGLengthMode::Width),
        lengthContext.valueForLength(styleRef().height(), styleRef(), SVGLengthMode::Height));

    // Spec: "A negative value is an error."
    if (boundingBoxSize.width() < 0 || boundingBoxSize.height() < 0)
        return;

    // Spec: "A value of zero disables rendering of the element."
    if (!boundingBoxSize.isEmpty()) {
        // Fallback to LayoutSVGShape and path-based hit detection if the rect
        // has rounded corners or a non-scaling or non-simple stroke.
        if (lengthContext.valueForLength(styleRef().svgStyle().rx(), styleRef(), SVGLengthMode::Width) > 0
                || lengthContext.valueForLength(styleRef().svgStyle().ry(), styleRef(), SVGLengthMode::Height) > 0
                || hasNonScalingStroke()
                || !definitelyHasSimpleStroke()) {
            LayoutSVGShape::updateShapeFromElement();
            m_usePathFallback = true;
            return;
        }
    }

    m_fillBoundingBox = FloatRect(
                            FloatPoint(
                                lengthContext.valueForLength(styleRef().svgStyle().x(), styleRef(), SVGLengthMode::Width),
                                lengthContext.valueForLength(styleRef().svgStyle().y(), styleRef(), SVGLengthMode::Height)),
                            boundingBoxSize);
    m_strokeBoundingBox = m_fillBoundingBox;
    if (style()->svgStyle().hasStroke())
        m_strokeBoundingBox.inflate(strokeWidth() / 2);
}
예제 #19
0
bool RenderSVGEllipse::shapeDependentStrokeContains(const FloatPoint& point)
{
    // The optimized contains code below does not support non-smooth strokes so we need
    // to fall back to RenderSVGShape::shapeDependentStrokeContains in these cases.
    if (m_usePathFallback || !hasSmoothStroke()) {
        if (!hasPath())
            RenderSVGShape::updateShapeFromElement();
        return RenderSVGShape::shapeDependentStrokeContains(point);
    }

    float halfStrokeWidth = strokeWidth() / 2;
    FloatPoint center = FloatPoint(m_center.x() - point.x(), m_center.y() - point.y());

    // This works by checking if the point satisfies the ellipse equation,
    // (x/rX)^2 + (y/rY)^2 <= 1, for the outer but not the inner stroke.
    float xrXOuter = center.x() / (m_radii.width() + halfStrokeWidth);
    float yrYOuter = center.y() / (m_radii.height() + halfStrokeWidth);
    if (xrXOuter * xrXOuter + yrYOuter * yrYOuter > 1.0)
        return false;

    float xrXInner = center.x() / (m_radii.width() - halfStrokeWidth);
    float yrYInner = center.y() / (m_radii.height() - halfStrokeWidth);
    return xrXInner * xrXInner + yrYInner * yrYInner >= 1.0;
}
예제 #20
0
bool LayoutSVGRect::shapeDependentStrokeContains(const FloatPoint& point)
{
    // The optimized code below does not support non-simple strokes so we need
    // to fall back to LayoutSVGShape::shapeDependentStrokeContains in these cases.
    if (m_usePathFallback || !definitelyHasSimpleStroke()) {
        if (!hasPath())
            LayoutSVGShape::updateShapeFromElement();
        return LayoutSVGShape::shapeDependentStrokeContains(point);
    }

    const float halfStrokeWidth = strokeWidth() / 2;
    const float halfWidth = m_fillBoundingBox.width() / 2;
    const float halfHeight = m_fillBoundingBox.height() / 2;

    const FloatPoint fillBoundingBoxCenter = FloatPoint(m_fillBoundingBox.x() + halfWidth, m_fillBoundingBox.y() + halfHeight);
    const float absDeltaX = std::abs(point.x() - fillBoundingBoxCenter.x());
    const float absDeltaY = std::abs(point.y() - fillBoundingBoxCenter.y());

    if (!(absDeltaX <= halfWidth + halfStrokeWidth && absDeltaY <= halfHeight + halfStrokeWidth))
        return false;

    return (halfWidth - halfStrokeWidth <= absDeltaX)
           || (halfHeight - halfStrokeWidth <= absDeltaY);
}
예제 #21
0
QRectF QSvgArc::bounds(QPainter *p, QSvgExtraStates &) const
{
    qreal sw = strokeWidth(p);
    return qFuzzyIsNull(sw) ? p->transform().map(m_path).boundingRect()
        : boundsOnStroke(p, m_path, sw);
}