GraphicsContextSkia.cpp [plain text]
#include "config.h"
#include "GraphicsContext.h"
#include "AffineTransform.h"
#include "Color.h"
#include "FloatRect.h"
#include "Gradient.h"
#include "GraphicsContextGPU.h"
#include "GraphicsContextPlatformPrivate.h"
#include "ImageBuffer.h"
#include "IntRect.h"
#include "NativeImageSkia.h"
#include "NotImplemented.h"
#include "PlatformContextSkia.h"
#include "SkBitmap.h"
#include "SkBlurMaskFilter.h"
#include "SkColorFilter.h"
#include "SkCornerPathEffect.h"
#include "SkLayerDrawLooper.h"
#include "SkShader.h"
#include "SkiaUtils.h"
#include "skia/ext/platform_canvas.h"
#include <math.h>
#include <wtf/Assertions.h>
#include <wtf/MathExtras.h>
#include <wtf/UnusedParam.h>
using namespace std;
namespace WebCore {
namespace {
inline int fastMod(int value, int max)
{
int sign = SkExtractSign(value);
value = SkApplySign(value, sign);
if (value >= max)
value %= max;
return SkApplySign(value, sign);
}
inline float square(float n)
{
return n * n;
}
}
#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
static bool isCoordinateSkiaSafe(float coord)
{
#if defined(_MSC_VER)
if (!_finite(coord))
#else
if (!finite(coord))
#endif
return false;
static const int maxPointMagnitude = 32767;
if (coord > maxPointMagnitude || coord < -maxPointMagnitude)
return false;
return true;
}
#endif
static bool isPointSkiaSafe(const SkMatrix& transform, const SkPoint& pt)
{
#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
SkPoint xPt;
transform.mapPoints(&xPt, &pt, 1);
return isCoordinateSkiaSafe(xPt.fX) && isCoordinateSkiaSafe(xPt.fY);
#else
return true;
#endif
}
static bool isRectSkiaSafe(const SkMatrix& transform, const SkRect& rc)
{
#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
SkPoint topleft = {rc.fLeft, rc.fTop};
SkPoint bottomright = {rc.fRight, rc.fBottom};
return isPointSkiaSafe(transform, topleft) && isPointSkiaSafe(transform, bottomright);
#else
return true;
#endif
}
bool isPathSkiaSafe(const SkMatrix& transform, const SkPath& path)
{
#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
SkPoint current_points[4];
SkPath::Iter iter(path, false);
for (SkPath::Verb verb = iter.next(current_points);
verb != SkPath::kDone_Verb;
verb = iter.next(current_points)) {
switch (verb) {
case SkPath::kMove_Verb:
break;
case SkPath::kLine_Verb:
if (!isPointSkiaSafe(transform, current_points[0])
|| !isPointSkiaSafe(transform, current_points[1]))
return false;
break;
case SkPath::kQuad_Verb:
if (!isPointSkiaSafe(transform, current_points[0])
|| !isPointSkiaSafe(transform, current_points[1])
|| !isPointSkiaSafe(transform, current_points[2]))
return false;
break;
case SkPath::kCubic_Verb:
if (!isPointSkiaSafe(transform, current_points[0])
|| !isPointSkiaSafe(transform, current_points[1])
|| !isPointSkiaSafe(transform, current_points[2])
|| !isPointSkiaSafe(transform, current_points[3]))
return false;
break;
case SkPath::kClose_Verb:
case SkPath::kDone_Verb:
default:
break;
}
}
return true;
#else
return true;
#endif
}
void addCornerArc(SkPath* path, const SkRect& rect, const IntSize& size, int startAngle)
{
SkIRect ir;
int rx = SkMin32(SkScalarRound(rect.width()), size.width());
int ry = SkMin32(SkScalarRound(rect.height()), size.height());
ir.set(-rx, -ry, rx, ry);
switch (startAngle) {
case 0:
ir.offset(rect.fRight - ir.fRight, rect.fBottom - ir.fBottom);
break;
case 90:
ir.offset(rect.fLeft - ir.fLeft, rect.fBottom - ir.fBottom);
break;
case 180:
ir.offset(rect.fLeft - ir.fLeft, rect.fTop - ir.fTop);
break;
case 270:
ir.offset(rect.fRight - ir.fRight, rect.fTop - ir.fTop);
break;
default:
ASSERT(0);
}
SkRect r;
r.set(ir);
path->arcTo(r, SkIntToScalar(startAngle), SkIntToScalar(90), false);
}
void GraphicsContext::platformInit(PlatformGraphicsContext* gc)
{
m_data = new GraphicsContextPlatformPrivate(gc);
setPaintingDisabled(!gc || !platformContext()->canvas());
}
void GraphicsContext::platformDestroy()
{
delete m_data;
}
PlatformGraphicsContext* GraphicsContext::platformContext() const
{
ASSERT(!paintingDisabled());
return m_data->context();
}
void GraphicsContext::savePlatformState()
{
if (paintingDisabled())
return;
if (platformContext()->useGPU())
platformContext()->gpuCanvas()->save();
platformContext()->save();
}
void GraphicsContext::restorePlatformState()
{
if (paintingDisabled())
return;
if (platformContext()->useGPU())
platformContext()->gpuCanvas()->restore();
platformContext()->restore();
}
void GraphicsContext::beginTransparencyLayer(float opacity)
{
if (paintingDisabled())
return;
platformContext()->canvas()->saveLayerAlpha(
0,
static_cast<unsigned char>(opacity * 255),
static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag |
SkCanvas::kFullColorLayer_SaveFlag));
}
void GraphicsContext::endTransparencyLayer()
{
if (paintingDisabled())
return;
platformContext()->canvas()->restore();
}
void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
{
if (paintingDisabled())
return;
SkRect r(rect);
if (!isRectSkiaSafe(getCTM(), r))
return;
platformContext()->prepareForSoftwareDraw();
SkPath path;
path.addOval(r, SkPath::kCW_Direction);
if (2 * thickness < rect.width() && 2 * thickness < rect.height()) {
r.inset(SkIntToScalar(thickness + 1), SkIntToScalar(thickness + 1));
path.addOval(r, SkPath::kCCW_Direction);
}
platformContext()->clipPathAntiAliased(path);
}
void GraphicsContext::clearPlatformShadow()
{
if (paintingDisabled())
return;
platformContext()->setDrawLooper(0);
}
void GraphicsContext::clearRect(const FloatRect& rect)
{
if (paintingDisabled())
return;
if (platformContext()->useGPU() && !platformContext()->canvasClipApplied()) {
platformContext()->prepareForHardwareDraw();
platformContext()->gpuCanvas()->clearRect(rect);
return;
}
platformContext()->syncSoftwareCanvas();
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);
}
void GraphicsContext::clip(const FloatRect& rect)
{
if (paintingDisabled())
return;
SkRect r(rect);
if (!isRectSkiaSafe(getCTM(), r))
return;
platformContext()->prepareForSoftwareDraw();
platformContext()->canvas()->clipRect(r);
}
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::canvasClip(const Path& path)
{
if (paintingDisabled())
return;
if (platformContext()->useGPU())
platformContext()->gpuCanvas()->clipPath(path);
const SkPath& p = *path.platformPath();
if (!isPathSkiaSafe(getCTM(), p))
return;
platformContext()->canvasClipPath(p);
}
void GraphicsContext::clipOut(const IntRect& rect)
{
if (paintingDisabled())
return;
SkRect r(rect);
if (!isRectSkiaSafe(getCTM(), r))
return;
platformContext()->canvas()->clipRect(r, SkRegion::kDifference_Op);
}
void GraphicsContext::clipOut(const Path& p)
{
if (paintingDisabled())
return;
if (platformContext()->useGPU())
platformContext()->gpuCanvas()->clipOut(p);
const SkPath& path = *p.platformPath();
if (!isPathSkiaSafe(getCTM(), path))
return;
platformContext()->canvas()->clipPath(path, SkRegion::kDifference_Op);
}
void GraphicsContext::clipPath(const Path& pathToClip, WindRule clipRule)
{
if (paintingDisabled())
return;
if (platformContext()->useGPU())
platformContext()->gpuCanvas()->clipPath(pathToClip);
SkPath path = *pathToClip.platformPath();
if (!isPathSkiaSafe(getCTM(), path))
return;
path.setFillType(clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
platformContext()->clipPathAntiAliased(path);
}
void GraphicsContext::concatCTM(const AffineTransform& affine)
{
if (paintingDisabled())
return;
if (platformContext()->useGPU())
platformContext()->gpuCanvas()->concatCTM(affine);
platformContext()->canvas()->concat(affine);
}
void GraphicsContext::setCTM(const AffineTransform& affine)
{
if (paintingDisabled())
return;
if (platformContext()->useGPU())
platformContext()->gpuCanvas()->setCTM(affine);
platformContext()->canvas()->setMatrix(affine);
}
void GraphicsContext::drawConvexPolygon(size_t numPoints,
const FloatPoint* points,
bool shouldAntialias)
{
if (paintingDisabled())
return;
if (numPoints <= 1)
return;
platformContext()->prepareForSoftwareDraw();
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::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
{
if (paintingDisabled())
return;
if (numPoints <= 1)
return;
}
void GraphicsContext::drawEllipse(const IntRect& elipseRect)
{
if (paintingDisabled())
return;
SkRect rect = elipseRect;
if (!isRectSkiaSafe(getCTM(), rect))
return;
platformContext()->prepareForSoftwareDraw();
SkPaint paint;
platformContext()->setupPaintForFilling(&paint);
platformContext()->canvas()->drawOval(rect, paint);
if (strokeStyle() != NoStroke) {
paint.reset();
platformContext()->setupPaintForStroking(&paint, &rect, 0);
platformContext()->canvas()->drawOval(rect, paint);
}
}
void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
{
}
void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int , int , const Color& color)
{
if (paintingDisabled())
return;
unsigned rectCount = rects.size();
if (!rectCount)
return;
platformContext()->prepareForSoftwareDraw();
SkRegion focusRingRegion;
const SkScalar focusRingOutset = WebCoreFloatToSkScalar(0.5);
for (unsigned i = 0; i < rectCount; i++) {
SkIRect r = rects[i];
r.inset(-focusRingOutset, -focusRingOutset);
focusRingRegion.op(r, SkRegion::kUnion_Op);
}
SkPath path;
SkPaint paint;
paint.setAntiAlias(true);
paint.setStyle(SkPaint::kStroke_Style);
paint.setColor(color.rgb());
paint.setStrokeWidth(focusRingOutset * 2);
paint.setPathEffect(new SkCornerPathEffect(focusRingOutset * 2))->unref();
focusRingRegion.getBoundaryPath(&path);
platformContext()->canvas()->drawPath(path, paint);
}
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());
FloatSize disp = p2 - p1;
int length = SkScalarRound(disp.width() + disp.height());
platformContext()->setupPaintForStroking(&paint, 0, length);
if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) {
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::drawLineForTextChecking(const FloatPoint& pt, float width, TextCheckingLineStyle style)
{
if (paintingDisabled())
return;
platformContext()->prepareForSoftwareDraw();
static SkBitmap* misspellBitmap = 0;
if (!misspellBitmap) {
const int rowPixels = 32; const int colPixels = 2;
misspellBitmap = new SkBitmap;
misspellBitmap->setConfig(SkBitmap::kARGB_8888_Config,
rowPixels, colPixels);
misspellBitmap->allocPixels();
misspellBitmap->eraseARGB(0, 0, 0, 0);
const uint32_t lineColor = 0xFFFF0000; const uint32_t antiColor = 0x60600000;
uint32_t* row1 = misspellBitmap->getAddr32(0, 0);
uint32_t* row2 = misspellBitmap->getAddr32(0, 1);
for (int x = 0; x < rowPixels; x++) {
switch (x % 4) {
case 0:
row1[x] = lineColor;
break;
case 1:
row1[x] = antiColor;
row2[x] = antiColor;
break;
case 2:
row2[x] = lineColor;
break;
case 3:
row1[x] = antiColor;
row2[x] = antiColor;
break;
}
}
}
SkScalar originX = WebCoreFloatToSkScalar(pt.x());
SkScalar originY = WebCoreFloatToSkScalar(pt.y()) + 1;
SkShader* shader = SkShader::CreateBitmapShader(
*misspellBitmap, SkShader::kRepeat_TileMode,
SkShader::kRepeat_TileMode);
SkMatrix matrix;
matrix.reset();
matrix.postTranslate(originX, originY);
shader->setLocalMatrix(matrix);
SkPaint paint;
paint.setShader(shader);
shader->unref();
SkRect rect;
rect.set(originX,
originY,
originX + WebCoreFloatToSkScalar(width),
originY + SkIntToScalar(misspellBitmap->height()));
platformContext()->canvas()->drawRect(rect, paint);
}
void GraphicsContext::drawLineForText(const FloatPoint& pt,
float width,
bool printing)
{
if (paintingDisabled())
return;
if (width <= 0)
return;
platformContext()->prepareForSoftwareDraw();
int thickness = SkMax32(static_cast<int>(strokeThickness()), 1);
SkRect r;
r.fLeft = WebCoreFloatToSkScalar(pt.x());
r.fTop = WebCoreFloatToSkScalar(pt.y());
r.fRight = r.fLeft + WebCoreFloatToSkScalar(width);
r.fBottom = r.fTop + SkIntToScalar(thickness);
SkPaint paint;
platformContext()->setupPaintForFilling(&paint);
paint.setColor(platformContext()->effectiveStrokeColor());
platformContext()->canvas()->drawRect(r, paint);
}
void GraphicsContext::drawRect(const IntRect& rect)
{
if (paintingDisabled())
return;
platformContext()->prepareForSoftwareDraw();
SkRect r = rect;
if (!isRectSkiaSafe(getCTM(), r)) {
ClipRectToCanvas(*platformContext()->canvas(), r, &r);
}
platformContext()->drawRect(r);
}
void GraphicsContext::fillPath(const Path& pathToFill)
{
if (paintingDisabled())
return;
if (platformContext()->useGPU() && platformContext()->canAccelerate()) {
platformContext()->prepareForHardwareDraw();
platformContext()->gpuCanvas()->fillPath(pathToFill);
return;
}
SkPath path = *pathToFill.platformPath();
if (!isPathSkiaSafe(getCTM(), path))
return;
platformContext()->prepareForSoftwareDraw();
const GraphicsContextState& state = m_state;
path.setFillType(state.fillRule == RULE_EVENODD ?
SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
SkPaint paint;
platformContext()->setupPaintForFilling(&paint);
platformContext()->canvas()->drawPath(path, paint);
}
void GraphicsContext::fillRect(const FloatRect& rect)
{
if (paintingDisabled())
return;
SkRect r = rect;
if (!isRectSkiaSafe(getCTM(), r)) {
ClipRectToCanvas(*platformContext()->canvas(), r, &r);
}
if (platformContext()->useGPU() && platformContext()->canAccelerate()) {
platformContext()->prepareForHardwareDraw();
platformContext()->gpuCanvas()->fillRect(rect);
return;
}
platformContext()->save();
platformContext()->prepareForSoftwareDraw();
SkPaint paint;
platformContext()->setupPaintForFilling(&paint);
platformContext()->canvas()->drawRect(r, paint);
platformContext()->restore();
}
void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
{
if (paintingDisabled())
return;
if (platformContext()->useGPU() && platformContext()->canAccelerate()) {
platformContext()->prepareForHardwareDraw();
platformContext()->gpuCanvas()->fillRect(rect, color, colorSpace);
return;
}
platformContext()->prepareForSoftwareDraw();
SkRect r = rect;
if (!isRectSkiaSafe(getCTM(), r)) {
ClipRectToCanvas(*platformContext()->canvas(), r, &r);
}
SkPaint paint;
platformContext()->setupPaintCommon(&paint);
paint.setColor(color.rgb());
platformContext()->canvas()->drawRect(r, paint);
}
void GraphicsContext::fillRoundedRect(const IntRect& rect,
const IntSize& topLeft,
const IntSize& topRight,
const IntSize& bottomLeft,
const IntSize& bottomRight,
const Color& color,
ColorSpace colorSpace)
{
if (paintingDisabled())
return;
platformContext()->prepareForSoftwareDraw();
SkRect r = rect;
if (!isRectSkiaSafe(getCTM(), r))
ClipRectToCanvas(*platformContext()->canvas(), r, &r);
if (topLeft.width() + topRight.width() > rect.width()
|| bottomLeft.width() + bottomRight.width() > rect.width()
|| topLeft.height() + bottomLeft.height() > rect.height()
|| topRight.height() + bottomRight.height() > rect.height()) {
fillRect(rect, color, colorSpace);
return;
}
SkPath path;
addCornerArc(&path, r, topRight, 270);
addCornerArc(&path, r, bottomRight, 0);
addCornerArc(&path, r, bottomLeft, 90);
addCornerArc(&path, r, topLeft, 180);
SkPaint paint;
platformContext()->setupPaintForFilling(&paint);
paint.setColor(color.rgb());
platformContext()->canvas()->drawPath(path, paint);
}
AffineTransform GraphicsContext::getCTM() const
{
const SkMatrix& m = platformContext()->canvas()->getTotalMatrix();
return AffineTransform(SkScalarToDouble(m.getScaleX()),
SkScalarToDouble(m.getSkewY()),
SkScalarToDouble(m.getSkewX()),
SkScalarToDouble(m.getScaleY()),
SkScalarToDouble(m.getTranslateX()),
SkScalarToDouble(m.getTranslateY()));
}
FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect, RoundingMode)
{
return rect;
}
void GraphicsContext::scale(const FloatSize& size)
{
if (paintingDisabled())
return;
if (platformContext()->useGPU())
platformContext()->gpuCanvas()->scale(size);
platformContext()->canvas()->scale(WebCoreFloatToSkScalar(size.width()),
WebCoreFloatToSkScalar(size.height()));
}
void GraphicsContext::setAlpha(float alpha)
{
if (paintingDisabled())
return;
if (platformContext()->useGPU())
platformContext()->gpuCanvas()->setAlpha(alpha);
platformContext()->setAlpha(alpha);
}
void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
{
if (paintingDisabled())
return;
if (platformContext()->useGPU())
platformContext()->gpuCanvas()->setCompositeOperation(op);
platformContext()->setXfermodeMode(WebCoreCompositeToSkiaComposite(op));
}
InterpolationQuality GraphicsContext::imageInterpolationQuality() const
{
return platformContext()->interpolationQuality();
}
void GraphicsContext::setImageInterpolationQuality(InterpolationQuality q)
{
platformContext()->setInterpolationQuality(q);
}
void GraphicsContext::setLineCap(LineCap cap)
{
if (paintingDisabled())
return;
switch (cap) {
case ButtCap:
platformContext()->setLineCap(SkPaint::kButt_Cap);
break;
case RoundCap:
platformContext()->setLineCap(SkPaint::kRound_Cap);
break;
case SquareCap:
platformContext()->setLineCap(SkPaint::kSquare_Cap);
break;
default:
ASSERT(0);
break;
}
}
void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
{
if (paintingDisabled())
return;
size_t dashLength = dashes.size();
if (!dashLength) {
platformContext()->setStrokeStyle(SolidStroke);
platformContext()->setDashPathEffect(0);
return;
}
size_t count = !(dashLength % 2) ? dashLength : dashLength * 2;
SkScalar* intervals = new SkScalar[count];
for (unsigned int i = 0; i < count; i++)
intervals[i] = dashes[i % dashLength];
platformContext()->setDashPathEffect(new SkDashPathEffect(intervals, count, dashOffset));
delete[] intervals;
}
void GraphicsContext::setLineJoin(LineJoin join)
{
if (paintingDisabled())
return;
switch (join) {
case MiterJoin:
platformContext()->setLineJoin(SkPaint::kMiter_Join);
break;
case RoundJoin:
platformContext()->setLineJoin(SkPaint::kRound_Join);
break;
case BevelJoin:
platformContext()->setLineJoin(SkPaint::kBevel_Join);
break;
default:
ASSERT(0);
break;
}
}
void GraphicsContext::setMiterLimit(float limit)
{
if (paintingDisabled())
return;
platformContext()->setMiterLimit(limit);
}
void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
{
if (paintingDisabled())
return;
if (platformContext()->useGPU())
platformContext()->gpuCanvas()->setFillColor(color, colorSpace);
platformContext()->setFillColor(color.rgb());
}
void GraphicsContext::setPlatformFillGradient(Gradient* gradient)
{
if (paintingDisabled())
return;
platformContext()->setFillShader(gradient->platformGradient());
}
void GraphicsContext::setPlatformFillPattern(Pattern* pattern)
{
if (paintingDisabled())
return;
platformContext()->setFillShader(pattern->platformPattern(getCTM()));
}
void GraphicsContext::setPlatformShadow(const FloatSize& size,
float blurFloat,
const Color& color,
ColorSpace colorSpace)
{
if (paintingDisabled())
return;
if (platformContext()->useGPU()) {
GraphicsContextGPU* canvas = platformContext()->gpuCanvas();
canvas->setShadowOffset(size);
canvas->setShadowBlur(blurFloat);
canvas->setShadowColor(color, colorSpace);
canvas->setShadowsIgnoreTransforms(m_state.shadowsIgnoreTransforms);
}
if (!size.width() && !size.height() && !blurFloat) {
platformContext()->setDrawLooper(0);
return;
}
double width = size.width();
double height = size.height();
double blur = blurFloat;
uint32_t mfFlags = SkBlurMaskFilter::kHighQuality_BlurFlag;
SkXfermode::Mode colorMode = SkXfermode::kSrc_Mode;
if (m_state.shadowsIgnoreTransforms) {
mfFlags |= SkBlurMaskFilter::kIgnoreTransform_BlurFlag;
colorMode = SkXfermode::kDst_Mode;
height = -height;
}
SkColor c;
if (color.isValid())
c = color.rgb();
else
c = SkColorSetARGB(0xFF/3, 0, 0, 0);
SkLayerDrawLooper* dl = new SkLayerDrawLooper;
SkAutoUnref aur(dl);
dl->addLayer();
SkLayerDrawLooper::LayerInfo info;
info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit; info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit;
info.fColorMode = colorMode;
info.fOffset.set(width, height);
info.fPostTranslate = m_state.shadowsIgnoreTransforms;
SkMaskFilter* mf = SkBlurMaskFilter::Create(blur / 2, SkBlurMaskFilter::kNormal_BlurStyle, mfFlags);
SkColorFilter* cf = SkColorFilter::CreateModeFilter(c, SkXfermode::kSrcIn_Mode);
SkPaint* paint = dl->addLayer(info);
SkSafeUnref(paint->setMaskFilter(mf));
SkSafeUnref(paint->setColorFilter(cf));
platformContext()->setDrawLooper(dl);
}
void GraphicsContext::setPlatformStrokeColor(const Color& strokecolor, ColorSpace colorSpace)
{
if (paintingDisabled())
return;
platformContext()->setStrokeColor(strokecolor.rgb());
}
void GraphicsContext::setPlatformStrokeStyle(StrokeStyle stroke)
{
if (paintingDisabled())
return;
platformContext()->setStrokeStyle(stroke);
}
void GraphicsContext::setPlatformStrokeThickness(float thickness)
{
if (paintingDisabled())
return;
platformContext()->setStrokeThickness(thickness);
}
void GraphicsContext::setPlatformStrokeGradient(Gradient* gradient)
{
if (paintingDisabled())
return;
platformContext()->setStrokeShader(gradient->platformGradient());
}
void GraphicsContext::setPlatformStrokePattern(Pattern* pattern)
{
if (paintingDisabled())
return;
platformContext()->setStrokeShader(pattern->platformPattern(getCTM()));
}
void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode)
{
if (paintingDisabled())
return;
platformContext()->setTextDrawingMode(mode);
}
void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
{
}
void GraphicsContext::setPlatformShouldAntialias(bool enable)
{
if (paintingDisabled())
return;
platformContext()->setUseAntialiasing(enable);
}
void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan)
{
if (paintingDisabled())
return;
platformContext()->prepareForSoftwareDraw();
SkPaint paint;
SkRect oval = r;
if (strokeStyle() == NoStroke) {
platformContext()->setupPaintForFilling(&paint);
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(WebCoreFloatToSkScalar(strokeThickness()));
} else
platformContext()->setupPaintForStroking(&paint, 0, 0);
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::strokePath(const Path& pathToStroke)
{
if (paintingDisabled())
return;
SkPath path = *pathToStroke.platformPath();
if (!isPathSkiaSafe(getCTM(), path))
return;
platformContext()->prepareForSoftwareDraw();
SkPaint paint;
platformContext()->setupPaintForStroking(&paint, 0, 0);
platformContext()->canvas()->drawPath(path, paint);
}
void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
{
if (paintingDisabled())
return;
if (!isRectSkiaSafe(getCTM(), rect))
return;
platformContext()->prepareForSoftwareDraw();
SkPaint paint;
platformContext()->setupPaintForStroking(&paint, 0, 0);
paint.setStrokeWidth(WebCoreFloatToSkScalar(lineWidth));
platformContext()->canvas()->drawRect(rect, paint);
}
void GraphicsContext::rotate(float angleInRadians)
{
if (paintingDisabled())
return;
if (platformContext()->useGPU())
platformContext()->gpuCanvas()->rotate(angleInRadians);
platformContext()->canvas()->rotate(WebCoreFloatToSkScalar(
angleInRadians * (180.0f / 3.14159265f)));
}
void GraphicsContext::translate(float w, float h)
{
if (paintingDisabled())
return;
if (platformContext()->useGPU())
platformContext()->gpuCanvas()->translate(w, h);
platformContext()->canvas()->translate(WebCoreFloatToSkScalar(w),
WebCoreFloatToSkScalar(h));
}
void GraphicsContext::syncSoftwareCanvas()
{
platformContext()->syncSoftwareCanvas();
}
void GraphicsContext::setSharedGraphicsContext3D(SharedGraphicsContext3D* context, DrawingBuffer* framebuffer, const IntSize& size)
{
platformContext()->setSharedGraphicsContext3D(context, framebuffer, size);
}
void GraphicsContext::markDirtyRect(const IntRect& rect)
{
platformContext()->markDirtyRect(rect);
}
}