PlatformContextSkia.cpp [plain text]
#include "config.h"
#include "GraphicsContext.h"
#include "ImageBuffer.h"
#include "NativeImageSkia.h"
#include "PlatformContextSkia.h"
#include "SkiaUtils.h"
#include "skia/ext/image_operations.h"
#include "skia/ext/platform_canvas.h"
#include "SkBitmap.h"
#include "SkColorPriv.h"
#include "SkShader.h"
#include "SkDashPathEffect.h"
#include <wtf/MathExtras.h>
struct PlatformContextSkia::State {
State();
State(const State&);
~State();
float m_alpha;
SkXfermode::Mode m_xferMode;
SkShader* m_gradient;
SkShader* m_pattern;
bool m_useAntialiasing;
SkDrawLooper* m_looper;
SkColor m_fillColor;
WebCore::StrokeStyle m_strokeStyle;
SkColor m_strokeColor;
float m_strokeThickness;
int m_dashRatio; float m_miterLimit;
SkPaint::Cap m_lineCap;
SkPaint::Join m_lineJoin;
SkDashPathEffect* m_dash;
int m_textDrawingMode;
SkColor applyAlpha(SkColor) const;
#if defined(__linux__) || PLATFORM(WIN_OS)
SkBitmap m_imageBufferClip;
WebCore::FloatRect m_clip;
#endif
private:
void operator=(const State&);
};
PlatformContextSkia::State::State()
: m_alpha(1)
, m_xferMode(SkXfermode::kSrcOver_Mode)
, m_gradient(0)
, m_pattern(0)
, m_useAntialiasing(true)
, m_looper(0)
, m_fillColor(0xFF000000)
, m_strokeStyle(WebCore::SolidStroke)
, m_strokeColor(WebCore::Color::black)
, m_strokeThickness(0)
, m_dashRatio(3)
, m_miterLimit(4)
, m_lineCap(SkPaint::kDefault_Cap)
, m_lineJoin(SkPaint::kDefault_Join)
, m_dash(0)
, m_textDrawingMode(WebCore::cTextFill)
{
}
PlatformContextSkia::State::State(const State& other)
: m_alpha(other.m_alpha)
, m_xferMode(other.m_xferMode)
, m_gradient(other.m_gradient)
, m_pattern(other.m_pattern)
, m_useAntialiasing(other.m_useAntialiasing)
, m_looper(other.m_looper)
, m_fillColor(other.m_fillColor)
, m_strokeStyle(other.m_strokeStyle)
, m_strokeColor(other.m_strokeColor)
, m_strokeThickness(other.m_strokeThickness)
, m_dashRatio(other.m_dashRatio)
, m_miterLimit(other.m_miterLimit)
, m_lineCap(other.m_lineCap)
, m_lineJoin(other.m_lineJoin)
, m_dash(other.m_dash)
, m_textDrawingMode(other.m_textDrawingMode)
#if defined(__linux__) || PLATFORM(WIN_OS)
, m_imageBufferClip(other.m_imageBufferClip)
, m_clip(other.m_clip)
#endif
{
m_looper->safeRef();
m_dash->safeRef();
m_gradient->safeRef();
m_pattern->safeRef();
}
PlatformContextSkia::State::~State()
{
m_looper->safeUnref();
m_dash->safeUnref();
m_gradient->safeUnref();
m_pattern->safeUnref();
}
SkColor PlatformContextSkia::State::applyAlpha(SkColor c) const
{
int s = roundf(m_alpha * 256);
if (s >= 256)
return c;
if (s < 0)
return 0;
int a = SkAlphaMul(SkColorGetA(c), s);
return (c & 0x00FFFFFF) | (a << 24);
}
PlatformContextSkia::PlatformContextSkia(skia::PlatformCanvas* canvas)
: m_canvas(canvas)
#if PLATFORM(WIN_OS)
, m_drawingToImageBuffer(false)
#endif
{
m_stateStack.append(State());
m_state = &m_stateStack.last();
}
PlatformContextSkia::~PlatformContextSkia()
{
}
void PlatformContextSkia::setCanvas(skia::PlatformCanvas* canvas)
{
m_canvas = canvas;
}
#if PLATFORM(WIN_OS)
void PlatformContextSkia::setDrawingToImageBuffer(bool value)
{
m_drawingToImageBuffer = value;
}
bool PlatformContextSkia::isDrawingToImageBuffer() const
{
return m_drawingToImageBuffer;
}
#endif
void PlatformContextSkia::save()
{
m_stateStack.append(*m_state);
m_state = &m_stateStack.last();
#if defined(__linux__) || PLATFORM(WIN_OS)
m_state->m_imageBufferClip.reset();
#endif
canvas()->save();
}
#if defined(__linux__) || PLATFORM(WIN_OS)
void PlatformContextSkia::beginLayerClippedToImage(const WebCore::FloatRect& rect,
const WebCore::ImageBuffer* imageBuffer)
{
m_state->m_clip = rect;
SkRect bounds = { SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()),
SkFloatToScalar(rect.right()), SkFloatToScalar(rect.bottom()) };
canvas()->saveLayerAlpha(&bounds, 255,
static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag));
const SkBitmap* bitmap = imageBuffer->context()->platformContext()->bitmap();
if (!bitmap->pixelRef()) {
bitmap->copyTo(&m_state->m_imageBufferClip, SkBitmap::kARGB_8888_Config);
} else {
m_state->m_imageBufferClip = *bitmap;
}
}
#endif
void PlatformContextSkia::restore()
{
#if defined(__linux__) || PLATFORM(WIN_OS)
if (!m_state->m_imageBufferClip.empty()) {
applyClipFromImage(m_state->m_clip, m_state->m_imageBufferClip);
canvas()->restore();
}
#endif
m_stateStack.removeLast();
m_state = &m_stateStack.last();
canvas()->restore();
}
void PlatformContextSkia::drawRect(SkRect rect)
{
SkPaint paint;
int fillcolorNotTransparent = m_state->m_fillColor & 0xFF000000;
if (fillcolorNotTransparent) {
setupPaintForFilling(&paint);
canvas()->drawRect(rect, paint);
}
if (m_state->m_strokeStyle != WebCore::NoStroke &&
(m_state->m_strokeColor & 0xFF000000)) {
SkColor oldFillColor = m_state->m_fillColor;
if (oldFillColor != m_state->m_strokeColor)
setFillColor(m_state->m_strokeColor);
setupPaintForFilling(&paint);
SkRect topBorder = { rect.fLeft, rect.fTop, rect.fRight, rect.fTop + 1 };
canvas()->drawRect(topBorder, paint);
SkRect bottomBorder = { rect.fLeft, rect.fBottom - 1, rect.fRight, rect.fBottom };
canvas()->drawRect(bottomBorder, paint);
SkRect leftBorder = { rect.fLeft, rect.fTop + 1, rect.fLeft + 1, rect.fBottom - 1 };
canvas()->drawRect(leftBorder, paint);
SkRect rightBorder = { rect.fRight - 1, rect.fTop + 1, rect.fRight, rect.fBottom - 1 };
canvas()->drawRect(rightBorder, paint);
if (oldFillColor != m_state->m_strokeColor)
setFillColor(oldFillColor);
}
}
void PlatformContextSkia::setupPaintCommon(SkPaint* paint) const
{
#ifdef SK_DEBUGx
{
SkPaint defaultPaint;
SkASSERT(*paint == defaultPaint);
}
#endif
paint->setAntiAlias(m_state->m_useAntialiasing);
paint->setXfermodeMode(m_state->m_xferMode);
paint->setLooper(m_state->m_looper);
if (m_state->m_gradient)
paint->setShader(m_state->m_gradient);
else if (m_state->m_pattern)
paint->setShader(m_state->m_pattern);
}
void PlatformContextSkia::setupPaintForFilling(SkPaint* paint) const
{
setupPaintCommon(paint);
paint->setColor(m_state->applyAlpha(m_state->m_fillColor));
}
float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, int length) const
{
setupPaintCommon(paint);
float width = m_state->m_strokeThickness;
paint->setColor(m_state->applyAlpha(m_state->m_strokeColor));
paint->setStyle(SkPaint::kStroke_Style);
paint->setStrokeWidth(SkFloatToScalar(width));
paint->setStrokeCap(m_state->m_lineCap);
paint->setStrokeJoin(m_state->m_lineJoin);
paint->setStrokeMiter(SkFloatToScalar(m_state->m_miterLimit));
if (m_state->m_dash)
paint->setPathEffect(m_state->m_dash);
else {
switch (m_state->m_strokeStyle) {
case WebCore::NoStroke:
case WebCore::SolidStroke:
break;
case WebCore::DashedStroke:
width = m_state->m_dashRatio * width;
case WebCore::DottedStroke:
SkScalar dashLength;
if (length) {
float roundedWidth = roundf(width);
int numDashes = roundedWidth ? (length / roundedWidth) : length;
if (!(numDashes & 1))
numDashes++; dashLength = SkScalarDiv(SkIntToScalar(length), SkIntToScalar(numDashes));
} else
dashLength = SkFloatToScalar(width);
SkScalar intervals[2] = { dashLength, dashLength };
paint->setPathEffect(new SkDashPathEffect(intervals, 2, 0))->unref();
}
}
return width;
}
void PlatformContextSkia::setDrawLooper(SkDrawLooper* dl)
{
SkRefCnt_SafeAssign(m_state->m_looper, dl);
}
void PlatformContextSkia::setMiterLimit(float ml)
{
m_state->m_miterLimit = ml;
}
void PlatformContextSkia::setAlpha(float alpha)
{
m_state->m_alpha = alpha;
}
void PlatformContextSkia::setLineCap(SkPaint::Cap lc)
{
m_state->m_lineCap = lc;
}
void PlatformContextSkia::setLineJoin(SkPaint::Join lj)
{
m_state->m_lineJoin = lj;
}
void PlatformContextSkia::setXfermodeMode(SkXfermode::Mode pdm)
{
m_state->m_xferMode = pdm;
}
void PlatformContextSkia::setFillColor(SkColor color)
{
m_state->m_fillColor = color;
}
SkDrawLooper* PlatformContextSkia::getDrawLooper() const
{
return m_state->m_looper;
}
WebCore::StrokeStyle PlatformContextSkia::getStrokeStyle() const
{
return m_state->m_strokeStyle;
}
void PlatformContextSkia::setStrokeStyle(WebCore::StrokeStyle strokeStyle)
{
m_state->m_strokeStyle = strokeStyle;
}
void PlatformContextSkia::setStrokeColor(SkColor strokeColor)
{
m_state->m_strokeColor = strokeColor;
}
float PlatformContextSkia::getStrokeThickness() const
{
return m_state->m_strokeThickness;
}
void PlatformContextSkia::setStrokeThickness(float thickness)
{
m_state->m_strokeThickness = thickness;
}
int PlatformContextSkia::getTextDrawingMode() const
{
return m_state->m_textDrawingMode;
}
float PlatformContextSkia::getAlpha() const
{
return m_state->m_alpha;
}
void PlatformContextSkia::setTextDrawingMode(int mode)
{
ASSERT((mode & WebCore::cTextClip) == 0);
m_state->m_textDrawingMode = mode;
}
void PlatformContextSkia::setUseAntialiasing(bool enable)
{
m_state->m_useAntialiasing = enable;
}
SkColor PlatformContextSkia::effectiveFillColor() const
{
return m_state->applyAlpha(m_state->m_fillColor);
}
SkColor PlatformContextSkia::effectiveStrokeColor() const
{
return m_state->applyAlpha(m_state->m_strokeColor);
}
void PlatformContextSkia::beginPath()
{
m_path.reset();
}
void PlatformContextSkia::addPath(const SkPath& path)
{
m_path.addPath(path, m_canvas->getTotalMatrix());
}
SkPath PlatformContextSkia::currentPathInLocalCoordinates() const
{
SkPath localPath = m_path;
const SkMatrix& matrix = m_canvas->getTotalMatrix();
SkMatrix inverseMatrix;
matrix.invert(&inverseMatrix);
localPath.transform(inverseMatrix);
return localPath;
}
void PlatformContextSkia::setFillRule(SkPath::FillType fr)
{
m_path.setFillType(fr);
}
void PlatformContextSkia::setGradient(SkShader* gradient)
{
if (gradient != m_state->m_gradient) {
m_state->m_gradient->safeUnref();
m_state->m_gradient = gradient;
}
}
void PlatformContextSkia::setPattern(SkShader* pattern)
{
if (pattern != m_state->m_pattern) {
m_state->m_pattern->safeUnref();
m_state->m_pattern = pattern;
}
}
void PlatformContextSkia::setDashPathEffect(SkDashPathEffect* dash)
{
if (dash != m_state->m_dash) {
m_state->m_dash->safeUnref();
m_state->m_dash = dash;
}
}
void PlatformContextSkia::paintSkPaint(const SkRect& rect,
const SkPaint& paint)
{
m_canvas->drawRect(rect, paint);
}
const SkBitmap* PlatformContextSkia::bitmap() const
{
return &m_canvas->getDevice()->accessBitmap(false);
}
bool PlatformContextSkia::isPrinting()
{
return m_canvas->getTopPlatformDevice().IsVectorial();
}
#if defined(__linux__) || PLATFORM(WIN_OS)
void PlatformContextSkia::applyClipFromImage(const WebCore::FloatRect& rect, const SkBitmap& imageBuffer)
{
SkPaint paint;
paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
m_canvas->drawBitmap(imageBuffer, SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()), &paint);
}
#endif