// 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); }
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(); }
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); }
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); }
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); }
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); }