Exemple #1
0
// This is only used to draw borders.
void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
{
    if (paintingDisabled())
        return;

    StrokeStyle penStyle = strokeStyle();
    if (penStyle == NoStroke)
        return;

    SkPaint paint;
    if (!isPointSkiaSafe(getCTM(), point1) || !isPointSkiaSafe(getCTM(), point2))
        return;

    platformContext()->prepareForSoftwareDraw();

    FloatPoint p1 = point1;
    FloatPoint p2 = point2;
    bool isVerticalLine = (p1.x() == p2.x());
    int width = roundf(strokeThickness());

    // We know these are vertical or horizontal lines, so the length will just
    // be the sum of the displacement component vectors give or take 1 -
    // probably worth the speed up of no square root, which also won't be exact.
    FloatSize disp = p2 - p1;
    int length = SkScalarRound(disp.width() + disp.height());
    platformContext()->setupPaintForStroking(&paint, 0, length);

    if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) {
        // Do a rect fill of our endpoints.  This ensures we always have the
        // appearance of being a border.  We then draw the actual dotted/dashed line.

        SkRect r1, r2;
        r1.set(p1.x(), p1.y(), p1.x() + width, p1.y() + width);
        r2.set(p2.x(), p2.y(), p2.x() + width, p2.y() + width);

        if (isVerticalLine) {
            r1.offset(-width / 2, 0);
            r2.offset(-width / 2, -width);
        } else {
            r1.offset(0, -width / 2);
            r2.offset(-width, -width / 2);
        }
        SkPaint fillPaint;
        fillPaint.setColor(paint.getColor());
        platformContext()->canvas()->drawRect(r1, fillPaint);
        platformContext()->canvas()->drawRect(r2, fillPaint);
    }

    adjustLineToPixelBoundaries(p1, p2, width, penStyle);
    SkPoint pts[2] = { (SkPoint)p1, (SkPoint)p2 };

    platformContext()->canvas()->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint);
}
Exemple #2
0
void GraphicsContext::fillRect(const FloatRect& rect)
{
    if (paintingDisabled())
        return;

    SkRect r = rect;
    if (!isRectSkiaSafe(getCTM(), r)) {
        // See the other version of fillRect below.
        ClipRectToCanvas(*platformContext()->canvas(), r, &r);
    }

    if (platformContext()->useGPU() && !m_common->state.fillPattern && !m_common->state.fillGradient && !platformContext()->getDrawLooper()) {
        platformContext()->prepareForHardwareDraw();
        platformContext()->gpuCanvas()->fillRect(rect);
        return;
    }

    platformContext()->save();

    platformContext()->prepareForSoftwareDraw();

    SkPaint paint;
    platformContext()->setupPaintForFilling(&paint);
    platformContext()->canvas()->drawRect(r, paint);

    platformContext()->restore();
}
Exemple #3
0
FloatRect GraphicsContext::computeLineBoundsAndAntialiasingModeForText(const FloatPoint& point, float width, bool printing, Color& color)
{
    FloatPoint origin = point;
    float thickness = std::max(strokeThickness(), 0.5f);
    if (printing)
        return FloatRect(origin, FloatSize(width, thickness));

    AffineTransform transform = getCTM(GraphicsContext::DefinitelyIncludeDeviceScale);
    // Just compute scale in x dimension, assuming x and y scales are equal.
    float scale = transform.b() ? sqrtf(transform.a() * transform.a() + transform.b() * transform.b()) : transform.a();
    if (scale < 1.0) {
        // This code always draws a line that is at least one-pixel line high,
        // which tends to visually overwhelm text at small scales. To counter this
        // effect, an alpha is applied to the underline color when text is at small scales.
        static const float minimumUnderlineAlpha = 0.4f;
        float shade = scale > minimumUnderlineAlpha ? scale : minimumUnderlineAlpha;
        int alpha = color.alpha() * shade;
        color = Color(color.red(), color.green(), color.blue(), alpha);
    }

    FloatPoint devicePoint = transform.mapPoint(point);
    // Visual overflow might occur here due to integral roundf/ceilf. visualOverflowForDecorations adjusts the overflow value for underline decoration.
    FloatPoint deviceOrigin = FloatPoint(roundf(devicePoint.x()), ceilf(devicePoint.y()));
    if (auto inverse = transform.inverse())
        origin = inverse.value().mapPoint(deviceOrigin);
    return FloatRect(origin, FloatSize(width, thickness));
}
void GraphicsContext::drawConvexPolygon(size_t numPoints,
                                        const FloatPoint* points,
                                        bool shouldAntialias)
{
    if (paintingDisabled())
        return;

    if (numPoints <= 1)
        return;

    SkPath path;

    path.incReserve(numPoints);
    path.moveTo(WebCoreFloatToSkScalar(points[0].x()),
                WebCoreFloatToSkScalar(points[0].y()));
    for (size_t i = 1; i < numPoints; i++) {
        path.lineTo(WebCoreFloatToSkScalar(points[i].x()),
                    WebCoreFloatToSkScalar(points[i].y()));
    }

    if (!isPathSkiaSafe(getCTM(), path))
        return;

    SkPaint paint;
    platformContext()->setupPaintForFilling(&paint);
    platformContext()->canvas()->drawPath(path, paint);

    if (strokeStyle() != NoStroke) {
        paint.reset();
        platformContext()->setupPaintForStroking(&paint, 0, 0);
        platformContext()->canvas()->drawPath(path, paint);
    }
}
void GraphicsContext::setPlatformFillPattern(Pattern* pattern)
{
    if (paintingDisabled())
        return;

    platformContext()->setFillShader(pattern->platformPattern(getCTM()));
}
FloatRect GraphicsContext::computeLineBoundsAndAntialiasingModeForText(const FloatPoint& point, float width, bool printing, bool& shouldAntialias, Color& color)
{
    FloatPoint origin = point;
    float thickness = std::max(strokeThickness(), 0.5f);

    shouldAntialias = true;
    if (!printing) {
        AffineTransform transform = getCTM(GraphicsContext::DefinitelyIncludeDeviceScale);
        if (transform.preservesAxisAlignment())
            shouldAntialias = false;

        // This code always draws a line that is at least one-pixel line high,
        // which tends to visually overwhelm text at small scales. To counter this
        // effect, an alpha is applied to the underline color when text is at small scales.

        // Just compute scale in x dimension, assuming x and y scales are equal.
        float scale = transform.b() ? sqrtf(transform.a() * transform.a() + transform.b() * transform.b()) : transform.a();
        if (scale < 1.0) {
            static const float minimumUnderlineAlpha = 0.4f;
            float shade = scale > minimumUnderlineAlpha ? scale : minimumUnderlineAlpha;
            int alpha = color.alpha() * shade;
            color = Color(color.red(), color.green(), color.blue(), alpha);
        }

        FloatPoint devicePoint = transform.mapPoint(point);
        FloatPoint deviceOrigin = FloatPoint(roundf(devicePoint.x()), ceilf(devicePoint.y()));
        if (auto inverse = transform.inverse())
            origin = inverse.value().mapPoint(deviceOrigin);
    }
    return FloatRect(origin.x(), origin.y(), width, thickness);
}
void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan)
{
    if (paintingDisabled())
        return;

    SkPaint paint;
    SkRect oval = r;
    if (strokeStyle() == NoStroke) {
        // Stroke using the fill color.
        // TODO(brettw) is this really correct? It seems unreasonable.
        platformContext()->setupPaintForFilling(&paint);
        paint.setStyle(SkPaint::kStroke_Style);
        paint.setStrokeWidth(WebCoreFloatToSkScalar(strokeThickness()));
    } else
        platformContext()->setupPaintForStroking(&paint, 0, 0);

    // We do this before converting to scalar, so we don't overflow SkFixed.
    startAngle = fastMod(startAngle, 360);
    angleSpan = fastMod(angleSpan, 360);

    SkPath path;
    path.addArc(oval, SkIntToScalar(-startAngle), SkIntToScalar(-angleSpan));
    if (!isPathSkiaSafe(getCTM(), path))
        return;
    platformContext()->canvas()->drawPath(path, paint);
}
void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
{
    if (paintingDisabled())
        return;

    SkRect r = rect;
    if (!isRectSkiaSafe(getCTM(), r)) {
        // Special case when the rectangle overflows fixed point. This is a
        // workaround to fix bug 1212844. When the input rectangle is very
        // large, it can overflow Skia's internal fixed point rect. This
        // should be fixable in Skia (since the output bitmap isn't that
        // large), but until that is fixed, we try to handle it ourselves.
        //
        // We manually clip the rectangle to the current clip rect. This
        // will prevent overflow. The rectangle will be transformed to the
        // canvas' coordinate space before it is converted to fixed point
        // so we are guaranteed not to overflow after doing this.
        ClipRectToCanvas(*platformContext()->canvas(), r, &r);
    }

    SkPaint paint;
    platformContext()->setupPaintCommon(&paint);
    paint.setColor(color.rgb());
    platformContext()->canvas()->drawRect(r, paint);
}
void GraphicsContext::setPlatformFillPattern(Pattern* pattern)
{
    if (paintingDisabled())
        return;

    SkShader* pat = pattern->createPlatformPattern(getCTM());
    platformContext()->setFillShader(pat);
    pat->safeUnref();
}
void GraphicsContext::canvasClip(const Path& path)
{
    if (paintingDisabled())
        return;

    const SkPath& p = *path.platformPath();
    if (!isPathSkiaSafe(getCTM(), p))
        return;

    platformContext()->canvas()->clipPath(p);
}
void GraphicsContext::clipOut(const Path& p)
{
    if (paintingDisabled())
        return;

    const SkPath& path = *p.platformPath();
    if (!isPathSkiaSafe(getCTM(), path))
        return;

    platformContext()->canvas()->clipPath(path, SkRegion::kDifference_Op);
}
void GraphicsContext::clip(const FloatRect& rect)
{
    if (paintingDisabled())
        return;

    SkRect r(rect);
    if (!isRectSkiaSafe(getCTM(), r))
        return;

    platformContext()->canvas()->clipRect(r);
}
void GraphicsContext::clipOut(const IntRect& rect)
{
    if (paintingDisabled())
        return;

    SkRect r(rect);
    if (!isRectSkiaSafe(getCTM(), r))
        return;

    platformContext()->canvas()->clipRect(r, SkRegion::kDifference_Op);
}
// This is only used to draw borders.
void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
{
    if (paintingDisabled())
        return;

    StrokeStyle penStyle = strokeStyle();
    if (penStyle == NoStroke)
        return;

    SkPaint paint;
    SkPoint pts[2] = { (SkPoint)point1, (SkPoint)point2 };
    if (!isPointSkiaSafe(getCTM(), pts[0]) || !isPointSkiaSafe(getCTM(), pts[1]))
        return;

    // We know these are vertical or horizontal lines, so the length will just
    // be the sum of the displacement component vectors give or take 1 -
    // probably worth the speed up of no square root, which also won't be exact.
    SkPoint disp = pts[1] - pts[0];
    int length = SkScalarRound(disp.fX + disp.fY);
    int width = roundf(
        platformContext()->setupPaintForStroking(&paint, 0, length));

    // "Borrowed" this comment and idea from GraphicsContextCG.cpp
    // For odd widths, we add in 0.5 to the appropriate x/y so that the float
    // arithmetic works out.  For example, with a border width of 3, KHTML will
    // pass us (y1+y2)/2, e.g., (50+53)/2 = 103/2 = 51 when we want 51.5.  It is
    // always true that an even width gave us a perfect position, but an odd
    // width gave us a position that is off by exactly 0.5.
    bool isVerticalLine = pts[0].fX == pts[1].fX;

    if (width & 1) {  // Odd.
        if (isVerticalLine) {
            pts[0].fX = pts[0].fX + SK_ScalarHalf;
            pts[1].fX = pts[0].fX;
        } else {  // Horizontal line
            pts[0].fY = pts[0].fY + SK_ScalarHalf;
            pts[1].fY = pts[0].fY;
        }
    }
    platformContext()->canvas()->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint);
}
Exemple #15
0
void GraphicsContext::clip(const Path& path)
{
    if (paintingDisabled())
        return;

    const SkPath& p = *path.platformPath();
    if (!isPathSkiaSafe(getCTM(), p))
        return;

    platformContext()->prepareForSoftwareDraw();
    platformContext()->clipPathAntiAliased(p);
}
void GraphicsContext::clipPath(WindRule clipRule)
{
    if (paintingDisabled())
        return;

    SkPath path = platformContext()->currentPathInLocalCoordinates();
    if (!isPathSkiaSafe(getCTM(), path))
        return;

    path.setFillType(clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
    platformContext()->clipPathAntiAliased(path);
}
void GraphicsContext::clipOutEllipseInRect(const IntRect& rect)
{
    if (paintingDisabled())
        return;

    SkRect oval(rect);
    if (!isRectSkiaSafe(getCTM(), oval))
        return;

    SkPath path;
    path.addOval(oval, SkPath::kCCW_Direction);
    platformContext()->canvas()->clipPath(path, SkRegion::kDifference_Op);
}
void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
{
    if (paintingDisabled())
        return;

    if (!isRectSkiaSafe(getCTM(), rect))
        return;

    SkPaint paint;
    platformContext()->setupPaintForStroking(&paint, 0, 0);
    paint.setStrokeWidth(WebCoreFloatToSkScalar(lineWidth));
    platformContext()->canvas()->drawRect(rect, paint);
}
void GraphicsContext::strokePath()
{
    if (paintingDisabled())
        return;

    SkPath path = platformContext()->currentPathInLocalCoordinates();
    if (!isPathSkiaSafe(getCTM(), path))
        return;

    SkPaint paint;
    platformContext()->setupPaintForStroking(&paint, 0, 0);
    platformContext()->canvas()->drawPath(path, paint);
}
Exemple #20
0
bool GraphicsContext::isCompatibleWithBuffer(ImageBuffer* buffer) const
{
    AffineTransform localTransform = getCTM();
    AffineTransform bufferTransform = buffer->context()->getCTM();

    if (localTransform.xScale() != bufferTransform.xScale() || localTransform.yScale() != bufferTransform.yScale())
        return false;

    if (isAcceleratedContext() != buffer->context()->isAcceleratedContext())
        return false;

    return true;
}
// Draws a filled rectangle with a stroked border.
void GraphicsContext::drawRect(const IntRect& rect)
{
    if (paintingDisabled())
        return;

    SkRect r = rect;
    if (!isRectSkiaSafe(getCTM(), r)) {
        // See the fillRect below.
        ClipRectToCanvas(*platformContext()->canvas(), r, &r);
    }

    platformContext()->drawRect(r);
}
void GraphicsContext::clearRect(const FloatRect& rect)
{
    if (paintingDisabled())
        return;

    SkRect r = rect;
    if (!isRectSkiaSafe(getCTM(), r))
        ClipRectToCanvas(*platformContext()->canvas(), r, &r);

    SkPaint paint;
    platformContext()->setupPaintForFilling(&paint);
    paint.setXfermodeMode(SkXfermode::kClear_Mode);
    platformContext()->canvas()->drawRect(r, paint);
}
Exemple #23
0
AffineTransform SVGLocatable::getTransformToElement(SVGElement* target, ExceptionCode& ec, StyleUpdateStrategy styleUpdateStrategy) const
{
    AffineTransform ctm = getCTM(styleUpdateStrategy);

    if (target && target->isStyledLocatable()) {
        AffineTransform targetCTM = static_cast<SVGStyledLocatableElement*>(target)->getCTM(styleUpdateStrategy);
        if (!targetCTM.isInvertible()) {
            ec = SVGException::SVG_MATRIX_NOT_INVERTABLE;
            return ctm;
        }
        ctm *= targetCTM.inverse();
    }

    return ctm;
}
TransformationMatrix SVGLocatable::getTransformToElement(SVGElement* target, ExceptionCode& ec) const
{
    TransformationMatrix ctm = getCTM();

    if (target && target->isStyledLocatable()) {
        TransformationMatrix targetCTM = static_cast<SVGStyledLocatableElement*>(target)->getCTM();
        if (!targetCTM.isInvertible()) {
            ec = SVGException::SVG_MATRIX_NOT_INVERTABLE;
            return ctm;
        }
        ctm *= targetCTM.inverse();
    }

    return ctm;
}
bool GraphicsContext::mustUseShadowBlur() const
{
    // We can't avoid ShadowBlur if the shadow has blur.
    if (hasBlurredShadow())
        return true;
    // We can avoid ShadowBlur and optimize, since we're not drawing on a
    // canvas and box shadows are affected by the transformation matrix.
    if (!m_state.shadowsIgnoreTransforms)
        return false;
    // We can avoid ShadowBlur, since there are no transformations to apply to the canvas.
    if (getCTM().isIdentity())
        return false;
    // Otherwise, no chance avoiding ShadowBlur.
    return true;
}
void GraphicsContext::fillRect(const FloatRect& rect)
{
    if (paintingDisabled())
        return;

    SkRect r = rect;
    if (!isRectSkiaSafe(getCTM(), r)) {
        // See the other version of fillRect below.
        ClipRectToCanvas(*platformContext()->canvas(), r, &r);
    }

    SkPaint paint;
    platformContext()->setupPaintForFilling(&paint);
    platformContext()->canvas()->drawRect(r, paint);
}
std::unique_ptr<ImageBuffer> GraphicsContext::createCompatibleBuffer(const FloatSize& size, bool hasAlpha) const
{
    // Make the buffer larger if the context's transform is scaling it so we need a higher
    // resolution than one pixel per unit. Also set up a corresponding scale factor on the
    // graphics context.

    AffineTransform transform = getCTM(DefinitelyIncludeDeviceScale);
    FloatSize scaledSize(static_cast<int>(ceil(size.width() * transform.xScale())), static_cast<int>(ceil(size.height() * transform.yScale())));

    std::unique_ptr<ImageBuffer> buffer = ImageBuffer::createCompatibleBuffer(scaledSize, 1, ColorSpaceSRGB, *this, hasAlpha);
    if (!buffer)
        return nullptr;

    buffer->context().scale(FloatSize(scaledSize.width() / size.width(), scaledSize.height() / size.height()));

    return buffer;
}
void GraphicsContext::strokePath()
{
    if (paintingDisabled())
        return;

    SkPath path = platformContext()->currentPathInLocalCoordinates();
    if (!isPathSkiaSafe(getCTM(), path))
        return;

    const GraphicsContextState& state = m_common->state;
    ColorSpace colorSpace = state.strokeColorSpace;

    SkPaint paint;
    platformContext()->setupPaintForStroking(&paint, 0, 0);

    platformContext()->canvas()->drawPath(path, paint);
}
PassOwnPtr<ImageBuffer> GraphicsContext::createCompatibleBuffer(const IntSize& size) const
{
    // Make the buffer larger if the context's transform is scaling it so we need a higher
    // resolution than one pixel per unit. Also set up a corresponding scale factor on the
    // graphics context.

    AffineTransform transform = getCTM(DefinitelyIncludeDeviceScale);
    IntSize scaledSize(static_cast<int>(ceil(size.width() * transform.xScale())), static_cast<int>(ceil(size.height() * transform.yScale())));

    OwnPtr<ImageBuffer> buffer = ImageBuffer::create(scaledSize, 1, ColorSpaceDeviceRGB, isAcceleratedContext() ? Accelerated : Unaccelerated);
    if (!buffer)
        return nullptr;

    buffer->context()->scale(FloatSize(static_cast<float>(scaledSize.width()) / size.width(),
        static_cast<float>(scaledSize.height()) / size.height()));

    return buffer.release();
}
void GraphicsContext::fillPath()
{
    if (paintingDisabled())
        return;

    SkPath path = platformContext()->currentPathInLocalCoordinates();
    if (!isPathSkiaSafe(getCTM(), path))
        return;

    const GraphicsContextState& state = m_common->state;
    path.setFillType(state.fillRule == RULE_EVENODD ?
                     SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);

    SkPaint paint;
    platformContext()->setupPaintForFilling(&paint);

    platformContext()->canvas()->drawPath(path, paint);
}