summaryrefslogtreecommitdiffstats
path: root/Source/WebCore
diff options
context:
space:
mode:
authorJohn Reck <jreck@google.com>2012-03-19 13:10:25 -0700
committerJohn Reck <jreck@google.com>2012-03-23 13:24:43 -0700
commit5fc5e1f3883ecadd4fd00df28225a17d7d3a37e9 (patch)
tree15d283973e858fc589c7fbe4af34e27684194e94 /Source/WebCore
parenta83257eb9d324048471edcf2974b54c20894a940 (diff)
downloadexternal_webkit-5fc5e1f3883ecadd4fd00df28225a17d7d3a37e9.zip
external_webkit-5fc5e1f3883ecadd4fd00df28225a17d7d3a37e9.tar.gz
external_webkit-5fc5e1f3883ecadd4fd00df28225a17d7d3a37e9.tar.bz2
Platform graphics refactor
Push the bulk of the work to PlatformGraphicsContext PlatformGraphicsContext does not depend on having a GraphicsContext Get ImageAndroid::drawPattern off of mCanvas Get BitmapImage::draw off of mCanvas Get WebFrameView off of mCanvas Cleanup GradientAndroid and remove mCanvas usage Change-Id: I3c8ad10c030cbc384436463e197ca1c0a69d34eb
Diffstat (limited to 'Source/WebCore')
-rw-r--r--Source/WebCore/platform/graphics/Gradient.h8
-rw-r--r--Source/WebCore/platform/graphics/GraphicsContext.cpp4
-rw-r--r--Source/WebCore/platform/graphics/GraphicsContext.h6
-rw-r--r--Source/WebCore/platform/graphics/android/GradientAndroid.cpp63
-rw-r--r--Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp938
-rw-r--r--Source/WebCore/platform/graphics/android/ImageAndroid.cpp74
-rw-r--r--Source/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp1011
-rw-r--r--Source/WebCore/platform/graphics/android/PlatformGraphicsContext.h111
8 files changed, 1272 insertions, 943 deletions
diff --git a/Source/WebCore/platform/graphics/Gradient.h b/Source/WebCore/platform/graphics/Gradient.h
index 7595896..ec22efe 100644
--- a/Source/WebCore/platform/graphics/Gradient.h
+++ b/Source/WebCore/platform/graphics/Gradient.h
@@ -58,14 +58,9 @@ typedef QGradient* PlatformGradient;
typedef struct _cairo_pattern cairo_pattern_t;
typedef cairo_pattern_t* PlatformGradient;
#elif USE(SKIA)
-#if PLATFORM(ANDROID)
-#include "SkShader.h"
-typedef class PlatformGradientRec* PlatformGradient;
-#else
class SkShader;
typedef class SkShader* PlatformGradient;
typedef class SkShader* PlatformPattern;
-#endif
#elif PLATFORM(HAIKU)
class BGradient;
typedef BGradient* PlatformGradient;
@@ -116,9 +111,6 @@ namespace WebCore {
#if OS(WINCE) && !PLATFORM(QT)
const Vector<ColorStop, 2>& getStops() const;
#else
-#if PLATFORM(ANDROID)
- SkShader* getShader(SkShader::TileMode);
-#endif
PlatformGradient platformGradient();
#endif
diff --git a/Source/WebCore/platform/graphics/GraphicsContext.cpp b/Source/WebCore/platform/graphics/GraphicsContext.cpp
index e032714..d8ea160 100644
--- a/Source/WebCore/platform/graphics/GraphicsContext.cpp
+++ b/Source/WebCore/platform/graphics/GraphicsContext.cpp
@@ -662,7 +662,7 @@ CompositeOperator GraphicsContext::compositeOperation() const
return m_state.compositeOperator;
}
-#if !(USE(SKIA) && !PLATFORM(ANDROID))
+#if !USE(SKIA)
void GraphicsContext::setPlatformFillGradient(Gradient*)
{
}
@@ -688,7 +688,7 @@ void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode)
}
#endif
-#if !PLATFORM(QT) && !USE(CAIRO) && !(USE(SKIA) && !PLATFORM(ANDROID)) && !PLATFORM(HAIKU) && !PLATFORM(OPENVG)
+#if !PLATFORM(QT) && !USE(CAIRO) && !USE(SKIA) && !PLATFORM(OPENVG)
void GraphicsContext::setPlatformStrokeStyle(StrokeStyle)
{
}
diff --git a/Source/WebCore/platform/graphics/GraphicsContext.h b/Source/WebCore/platform/graphics/GraphicsContext.h
index ed43cf0..5c60e98 100644
--- a/Source/WebCore/platform/graphics/GraphicsContext.h
+++ b/Source/WebCore/platform/graphics/GraphicsContext.h
@@ -287,8 +287,6 @@ namespace WebCore {
#endif
#if PLATFORM(ANDROID)
- // initialize a paint for bitmaps
- void setupBitmapPaint(SkPaint*);
// initialize a paint for filling
void setupFillPaint(SkPaint*);
// initialize a paint for stroking
@@ -301,10 +299,6 @@ namespace WebCore {
// returns true if there is a valid (non-transparent) stroke color
bool willStroke() const;
- // may return NULL, since we lazily allocate the path. This is the path
- // that is drawn by drawPath()
- const SkPath* getCurrPath() const;
-
/** platform-specific factory method to return a bitmap graphicscontext,
called by <canvas> when we need to draw offscreen. Caller is responsible for
deleting the context. Use drawOffscreenContext() to draw the context's image
diff --git a/Source/WebCore/platform/graphics/android/GradientAndroid.cpp b/Source/WebCore/platform/graphics/android/GradientAndroid.cpp
index 6007a0a..7bc69c5 100644
--- a/Source/WebCore/platform/graphics/android/GradientAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/GradientAndroid.cpp
@@ -26,7 +26,6 @@
#include "config.h"
#include "Gradient.h"
-#include "android_graphics.h"
#include "CSSParser.h"
#include "GraphicsContext.h"
#include "NotImplemented.h"
@@ -35,16 +34,6 @@
#include "SkGradientShader.h"
#include "SkPaint.h"
-class PlatformGradientRec {
-public:
- PlatformGradientRec() : m_shader(NULL) {}
- ~PlatformGradientRec() { SkSafeUnref(m_shader); }
-
- SkShader* m_shader;
- SkShader::TileMode m_tileMode;
- int m_colorCountWhenShaderWasBuilt;
-};
-
namespace WebCore {
void Gradient::platformDestroy()
@@ -58,12 +47,10 @@ static U8CPU F2B(float x)
return (int)(x * 255);
}
-SkShader* Gradient::getShader(SkShader::TileMode mode)
+SkShader* Gradient::platformGradient()
{
- if (NULL == m_gradient)
- m_gradient = new PlatformGradientRec;
- else if (mode == m_gradient->m_tileMode)
- return m_gradient->m_shader;
+ if (m_gradient)
+ return m_gradient;
// need to ensure that the m_stops array is sorted. We call getColor()
// which, as a side effect, does the sort.
@@ -73,6 +60,19 @@ SkShader* Gradient::getShader(SkShader::TileMode mode)
this->getColor(0, &r, &g, &b, &a);
}
+ SkShader::TileMode mode = SkShader::kClamp_TileMode;
+ switch (m_spreadMethod) {
+ case SpreadMethodReflect:
+ mode = SkShader::kMirror_TileMode;
+ break;
+ case SpreadMethodRepeat:
+ mode = SkShader::kRepeat_TileMode;
+ break;
+ case SpreadMethodPad:
+ mode = SkShader::kClamp_TileMode;
+ break;
+ }
+
SkPoint pts[2] = { m_p0, m_p1 }; // convert to SkPoint
const size_t count = m_stops.size();
@@ -88,39 +88,28 @@ SkShader* Gradient::getShader(SkShader::TileMode mode)
++iter;
}
- SkShader* s;
- if (m_radial)
- s = SkGradientShader::CreateTwoPointRadial(pts[0],
+ if (m_radial) {
+ m_gradient = SkGradientShader::CreateTwoPointRadial(pts[0],
SkFloatToScalar(m_r0),
pts[1],
SkFloatToScalar(m_r1),
colors, pos, count, mode);
- else
- s = SkGradientShader::CreateLinear(pts, colors, pos, count, mode);
+ } else
+ m_gradient = SkGradientShader::CreateLinear(pts, colors, pos, count, mode);
- if (NULL == s)
- s = new SkColorShader(0);
+ if (!m_gradient)
+ m_gradient = new SkColorShader(0);
- // zap our previous shader, if present
- SkSafeUnref(m_gradient->m_shader);
- m_gradient->m_shader = s;
- m_gradient->m_tileMode = mode;
SkMatrix matrix = m_gradientSpaceTransformation;
- s->setLocalMatrix(matrix);
+ m_gradient->setLocalMatrix(matrix);
- return s;
+ return m_gradient;
}
void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
{
- SkPaint paint;
- // we don't care about the mode, so try to use the existing one
- SkShader::TileMode mode = m_gradient ? m_gradient->m_tileMode :
- SkShader::kClamp_TileMode;
-
- paint.setAntiAlias(true);
- paint.setShader(this->getShader(mode));
- android_gc2canvas(context)->drawRect(rect, paint);
+ context->setFillGradient(this);
+ context->fillRect(rect);
}
diff --git a/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
index 0aa1ae6..bdc8005 100644
--- a/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
@@ -49,376 +49,36 @@
using namespace std;
-#define GC2CANVAS(ctx) (ctx)->m_data->getPlatformGfxCtx()->mCanvas
-
namespace WebCore {
-static int RoundToInt(float x)
-{
- return (int)roundf(x);
-}
-
-template <typename T> T* deepCopyPtr(const T* src)
-{
- return src ? new T(*src) : 0;
-}
-
-// Set a bitmap shader that mimics dashing by width-on, width-off.
-// Returns false if it could not succeed (e.g. there was an existing shader)
-static bool setBitmapDash(SkPaint* paint, int width) {
- if (width <= 0 || paint->getShader())
- return false;
-
- SkColor c = paint->getColor();
-
- SkBitmap bm;
- bm.setConfig(SkBitmap::kARGB_8888_Config, 2, 1);
- bm.allocPixels();
- bm.lockPixels();
-
- // set the ON pixel
- *bm.getAddr32(0, 0) = SkPreMultiplyARGB(0xFF, SkColorGetR(c),
- SkColorGetG(c), SkColorGetB(c));
- // set the OFF pixel
- *bm.getAddr32(1, 0) = 0;
- bm.unlockPixels();
-
- SkMatrix matrix;
- matrix.setScale(SkIntToScalar(width), SK_Scalar1);
-
- SkShader* s = SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode,
- SkShader::kClamp_TileMode);
- s->setLocalMatrix(matrix);
-
- paint->setShader(s)->unref();
- return true;
-}
-
-// TODO / questions
-
-// alpha: how does this interact with the alpha in Color? multiply them together?
-// mode: do I always respect this? If so, then
-// the rgb() & 0xFF000000 check will abort drawing too often
-// Is Color premultiplied or not? If it is, then I can't blindly pass it to paint.setColor()
-
-struct ShadowRec {
- SkScalar blur;
- SkScalar dx;
- SkScalar dy;
- SkColor color; // alpha>0 means valid shadow
- ShadowRec(SkScalar b = 0,
- SkScalar x = 0,
- SkScalar y = 0,
- SkColor c = 0) // by default, alpha=0, so no shadow
- : blur(b), dx(x), dy(y), color(c)
- {};
-};
-
+// This class just holds onto a PlatformContextSkia for GraphicsContext.
class GraphicsContextPlatformPrivate {
+ WTF_MAKE_NONCOPYABLE(GraphicsContextPlatformPrivate);
public:
- struct State {
- SkPathEffect* pathEffect;
- float miterLimit;
- float alpha;
- float strokeThickness;
- SkPaint::Cap lineCap;
- SkPaint::Join lineJoin;
- SkXfermode::Mode mode;
- int dashRatio; // Ratio of the length of a dash to its width
- ShadowRec shadow;
- SkColor fillColor;
- SkColor strokeColor;
- bool useAA;
-
- State()
- : pathEffect(0)
- , miterLimit(4)
- , alpha(1)
- , strokeThickness(0) // Same as default in GraphicsContextPrivate.h
- , lineCap(SkPaint::kDefault_Cap)
- , lineJoin(SkPaint::kDefault_Join)
- , mode(SkXfermode::kSrcOver_Mode)
- , dashRatio(3)
- , fillColor(SK_ColorBLACK)
- , strokeColor(SK_ColorBLACK)
- , useAA(true)
- {
- }
-
- State(const State& other)
- : pathEffect(other.pathEffect)
- , miterLimit(other.miterLimit)
- , alpha(other.alpha)
- , strokeThickness(other.strokeThickness)
- , lineCap(other.lineCap)
- , lineJoin(other.lineJoin)
- , mode(other.mode)
- , dashRatio(other.dashRatio)
- , shadow(other.shadow)
- , fillColor(other.fillColor)
- , strokeColor(other.strokeColor)
- , useAA(other.useAA)
- {
- SkSafeRef(pathEffect);
- }
-
- ~State()
- {
- SkSafeUnref(pathEffect);
- }
-
- void setShadow(int radius, int dx, int dy, SkColor c)
- {
- // Cut the radius in half, to visually match the effect seen in
- // safari browser
- shadow.blur = SkScalarHalf(SkIntToScalar(radius));
- shadow.dx = SkIntToScalar(dx);
- shadow.dy = SkIntToScalar(dy);
- shadow.color = c;
- }
-
- bool setupShadowPaint(GraphicsContext* ctx, SkPaint* paint, SkPoint* offset)
- {
- paint->setAntiAlias(true);
- paint->setDither(true);
- paint->setXfermodeMode(mode);
- paint->setColor(shadow.color);
- offset->set(shadow.dx, shadow.dy);
-
- // Currently, only GraphicsContexts associated with the
- // HTMLCanvasElement have shadows ignore transforms set. This
- // allows us to distinguish between CSS and Canvas shadows which
- // have different rendering specifications.
- uint32_t flags = SkBlurMaskFilter::kHighQuality_BlurFlag;
- if (ctx->shadowsIgnoreTransforms()) {
- offset->fY = -offset->fY;
- flags |= SkBlurMaskFilter::kIgnoreTransform_BlurFlag;
- }
-
- if (shadow.blur > 0) {
- paint->setMaskFilter(SkBlurMaskFilter::Create(shadow.blur,
- SkBlurMaskFilter::kNormal_BlurStyle))->unref();
- }
- return SkColorGetA(shadow.color) && (shadow.blur || shadow.dx || shadow.dy);
- }
-
- SkColor applyAlpha(SkColor c) const
- {
- int s = RoundToInt(alpha * 256);
- if (s >= 256)
- return c;
- if (s < 0)
- return 0;
-
- int a = SkAlphaMul(SkColorGetA(c), s);
- return (c & 0x00FFFFFF) | (a << 24);
- }
- };
+ GraphicsContextPlatformPrivate(PlatformGraphicsContext* platformContext)
+ : m_context(platformContext) { }
+
+ PlatformGraphicsContext* context() { return m_context; }
- GraphicsContextPlatformPrivate(GraphicsContext* gfxCtx, PlatformGraphicsContext* platformGfxCtx)
- : m_parentGfxCtx(gfxCtx)
- , m_platformGfxCtx(platformGfxCtx)
- , m_stateStack(sizeof(State))
- {
- State* state = static_cast<State*>(m_stateStack.push_back());
- new (state) State();
- m_state = state;
- }
-
- ~GraphicsContextPlatformPrivate()
- {
- // We force restores so we don't leak any subobjects owned by our
- // stack of State records.
- while (m_stateStack.count() > 0)
- this->restore();
-
- if (m_platformGfxCtx && m_platformGfxCtx->deleteUs())
- delete m_platformGfxCtx;
- }
-
- void save()
- {
- State* newState = static_cast<State*>(m_stateStack.push_back());
- new (newState) State(*m_state);
- m_state = newState;
- }
-
- void restore()
- {
- m_state->~State();
- m_stateStack.pop_back();
- m_state = static_cast<State*>(m_stateStack.back());
- }
-
- void setFillColor(const Color& c)
- {
- m_state->fillColor = c.rgb();
- }
-
- void setStrokeColor(const Color& c)
- {
- m_state->strokeColor = c.rgb();
- }
-
- void setStrokeThickness(float f)
- {
- m_state->strokeThickness = f;
- }
-
- void setupPaintCommon(SkPaint* paint) const
- {
- paint->setAntiAlias(m_state->useAA);
- paint->setDither(true);
- paint->setXfermodeMode(m_state->mode);
- if (SkColorGetA(m_state->shadow.color) > 0) {
-
- // Currently, only GraphicsContexts associated with the
- // HTMLCanvasElement have shadows ignore transforms set. This
- // allows us to distinguish between CSS and Canvas shadows which
- // have different rendering specifications.
- SkScalar dy = m_state->shadow.dy;
- uint32_t flags = SkBlurDrawLooper::kHighQuality_BlurFlag;
- if (m_parentGfxCtx->shadowsIgnoreTransforms()) {
- dy = -dy;
- flags |= SkBlurDrawLooper::kIgnoreTransform_BlurFlag;
- flags |= SkBlurDrawLooper::kOverrideColor_BlurFlag;
- }
-
- SkDrawLooper* looper = new SkBlurDrawLooper(m_state->shadow.blur,
- m_state->shadow.dx,
- dy,
- m_state->shadow.color,
- flags);
- paint->setLooper(looper)->unref();
- }
- }
-
- void setupPaintFill(SkPaint* paint) const
- {
- this->setupPaintCommon(paint);
- paint->setColor(m_state->applyAlpha(m_state->fillColor));
- }
-
- void setupPaintBitmap(SkPaint* paint) const
- {
- this->setupPaintCommon(paint);
- // We only want the global alpha for bitmaps,
- // so just give applyAlpha opaque black
- paint->setColor(m_state->applyAlpha(0xFF000000));
- }
-
- // Sets up the paint for stroking. Returns true if the style is really
- // just a dash of squares (the size of the paint's stroke-width.
- bool setupPaintStroke(SkPaint* paint, SkRect* rect, bool isHLine = false)
- {
- this->setupPaintCommon(paint);
- paint->setColor(m_state->applyAlpha(m_state->strokeColor));
-
- float width = m_state->strokeThickness;
-
- // This allows dashing and dotting to work properly for hairline strokes
- // FIXME: Should we only do this for dashed and dotted strokes?
- if (!width)
- width = 1;
-
- paint->setStyle(SkPaint::kStroke_Style);
- paint->setStrokeWidth(SkFloatToScalar(width));
- paint->setStrokeCap(m_state->lineCap);
- paint->setStrokeJoin(m_state->lineJoin);
- paint->setStrokeMiter(SkFloatToScalar(m_state->miterLimit));
-
- if (rect && (RoundToInt(width) & 1))
- rect->inset(-SK_ScalarHalf, -SK_ScalarHalf);
-
- SkPathEffect* pe = m_state->pathEffect;
- if (pe) {
- paint->setPathEffect(pe);
- return false;
- }
- switch (m_parentGfxCtx->strokeStyle()) {
- case NoStroke:
- case SolidStroke:
- width = 0;
- break;
- case DashedStroke:
- width = m_state->dashRatio * width;
- break;
- // No break
- case DottedStroke:
- break;
- }
-
- if (width > 0) {
- // Return true if we're basically a dotted dash of squares
- bool justSqrs = RoundToInt(width) == RoundToInt(paint->getStrokeWidth());
-
- if (justSqrs || !isHLine || !setBitmapDash(paint, width)) {
-#if 0
- // this is slow enough that we just skip it for now
- // see http://b/issue?id=4163023
- SkScalar intervals[] = { width, width };
- pe = new SkDashPathEffect(intervals, 2, 0);
- paint->setPathEffect(pe)->unref();
-#endif
- }
- return justSqrs;
- }
- return false;
- }
-
- PlatformGraphicsContext* getPlatformGfxCtx()
- {
- return m_platformGfxCtx;
- }
-
- State* getState()
- {
- return m_state;
- }
private:
- State* m_state;
- GraphicsContext* m_parentGfxCtx; // Back-ptr to our parent
- PlatformGraphicsContext* m_platformGfxCtx;
- SkDeque m_stateStack;
- // Not supported yet
- State& operator=(const State&);
+ // Non-owning pointer to the PlatformContext.
+ PlatformGraphicsContext* m_context;
};
-static SkShader::TileMode SpreadMethod2TileMode(GradientSpreadMethod sm)
+static SkShader* extractShader(Pattern* pat, Gradient* grad)
{
- SkShader::TileMode mode = SkShader::kClamp_TileMode;
-
- switch (sm) {
- case SpreadMethodPad:
- mode = SkShader::kClamp_TileMode;
- break;
- case SpreadMethodReflect:
- mode = SkShader::kMirror_TileMode;
- break;
- case SpreadMethodRepeat:
- mode = SkShader::kRepeat_TileMode;
- break;
- }
- return mode;
-}
-
-static void extactShader(SkPaint* paint, Pattern* pat, Gradient* grad)
-{
- if (pat) {
- // platformPattern() returns a cached obj
- paint->setShader(pat->platformPattern(AffineTransform()));
- } else if (grad) {
- // grad->getShader() returns a cached obj
- GradientSpreadMethod sm = grad->spreadMethod();
- paint->setShader(grad->getShader(SpreadMethod2TileMode(sm)));
- }
+ if (pat)
+ return pat->platformPattern(AffineTransform());
+ else if (grad)
+ return grad->platformGradient();
+ return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////
GraphicsContext* GraphicsContext::createOffscreenContext(int width, int height)
{
- PlatformGraphicsContext* pgc = new PlatformGraphicsContext();
+ PlatformGraphicsContext* pgc = new PlatformGraphicsContext(new SkCanvas, true);
SkBitmap bitmap;
@@ -435,7 +95,9 @@ GraphicsContext* GraphicsContext::createOffscreenContext(int width, int height)
void GraphicsContext::platformInit(PlatformGraphicsContext* gc)
{
- m_data = new GraphicsContextPlatformPrivate(this, gc);
+ if (gc)
+ gc->setGraphicsContext(this);
+ m_data = new GraphicsContextPlatformPrivate(gc);
setPaintingDisabled(!gc || !gc->mCanvas);
}
@@ -446,28 +108,22 @@ void GraphicsContext::platformDestroy()
void GraphicsContext::savePlatformState()
{
- // Save our private State
- m_data->save();
- // Save our native canvas
- GC2CANVAS(this)->save();
+ platformContext()->save();
}
void GraphicsContext::restorePlatformState()
{
- // Restore our private State
- m_data->restore();
- // Restore our native canvas
- GC2CANVAS(this)->restore();
+ platformContext()->restore();
}
bool GraphicsContext::willFill() const
{
- return m_data->getState()->fillColor;
+ return m_state.fillColor.rgb();
}
bool GraphicsContext::willStroke() const
{
- return m_data->getState()->strokeColor;
+ return m_state.strokeColor.rgb();
}
// Draws a filled rectangle with a stroked border.
@@ -476,24 +132,7 @@ void GraphicsContext::drawRect(const IntRect& rect)
if (paintingDisabled())
return;
- SkPaint paint;
- SkRect r(rect);
-
- if (fillColor().alpha()) {
- m_data->setupPaintFill(&paint);
- GC2CANVAS(this)->drawRect(r, paint);
- }
-
- // According to GraphicsContext.h, stroking inside drawRect always means
- // a stroke of 1 inside the rect.
- if (strokeStyle() != NoStroke && strokeColor().alpha()) {
- paint.reset();
- m_data->setupPaintStroke(&paint, &r);
- paint.setPathEffect(0); // No dashing please
- paint.setStrokeWidth(SK_Scalar1); // Always just 1.0 width
- r.inset(SK_ScalarHalf, SK_ScalarHalf); // Ensure we're "inside"
- GC2CANVAS(this)->drawRect(r, paint);
- }
+ platformContext()->drawRect(rect);
}
// This is only used to draw borders.
@@ -502,119 +141,24 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
if (paintingDisabled())
return;
- StrokeStyle style = strokeStyle();
- if (style == NoStroke)
- return;
-
- SkPaint paint;
- SkCanvas* canvas = GC2CANVAS(this);
- const int idx = SkAbs32(point2.x() - point1.x());
- const int idy = SkAbs32(point2.y() - point1.y());
-
- // Special-case horizontal and vertical lines that are really just dots
- if (m_data->setupPaintStroke(&paint, 0, !idy) && (!idx || !idy)) {
- const SkScalar diameter = paint.getStrokeWidth();
- const SkScalar radius = SkScalarHalf(diameter);
- SkScalar x = SkIntToScalar(SkMin32(point1.x(), point2.x()));
- SkScalar y = SkIntToScalar(SkMin32(point1.y(), point2.y()));
- SkScalar dx, dy;
- int count;
- SkRect bounds;
-
- if (!idy) { // Horizontal
- bounds.set(x, y - radius, x + SkIntToScalar(idx), y + radius);
- x += radius;
- dx = diameter * 2;
- dy = 0;
- count = idx;
- } else { // Vertical
- bounds.set(x - radius, y, x + radius, y + SkIntToScalar(idy));
- y += radius;
- dx = 0;
- dy = diameter * 2;
- count = idy;
- }
-
- // The actual count is the number of ONs we hit alternating
- // ON(diameter), OFF(diameter), ...
- {
- SkScalar width = SkScalarDiv(SkIntToScalar(count), diameter);
- // Now compute the number of cells (ON and OFF)
- count = SkScalarRound(width);
- // Now compute the number of ONs
- count = (count + 1) >> 1;
- }
-
- SkAutoMalloc storage(count * sizeof(SkPoint));
- SkPoint* verts = (SkPoint*)storage.get();
- // Now build the array of vertices to past to drawPoints
- for (int i = 0; i < count; i++) {
- verts[i].set(x, y);
- x += dx;
- y += dy;
- }
-
- paint.setStyle(SkPaint::kFill_Style);
- paint.setPathEffect(0);
-
- // Clipping to bounds is not required for correctness, but it does
- // allow us to reject the entire array of points if we are completely
- // offscreen. This is common in a webpage for android, where most of
- // the content is clipped out. If drawPoints took an (optional) bounds
- // parameter, that might even be better, as we would *just* use it for
- // culling, and not both wacking the canvas' save/restore stack.
- canvas->save(SkCanvas::kClip_SaveFlag);
- canvas->clipRect(bounds);
- canvas->drawPoints(SkCanvas::kPoints_PointMode, count, verts, paint);
- canvas->restore();
- } else {
- SkPoint pts[2] = { point1, point2 };
- canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
- }
-}
-
-static void setrectForUnderline(SkRect* r, GraphicsContext* context, const FloatPoint& point, int yOffset, float width)
-{
- float lineThickness = context->strokeThickness();
-#if 0
- if (lineThickness < 1) // Do we really need/want this?
- lineThickness = 1;
-#endif
- r->fLeft = point.x();
- r->fTop = point.y() + yOffset;
- r->fRight = r->fLeft + width;
- r->fBottom = r->fTop + lineThickness;
+ platformContext()->drawLine(point1, point2);
}
-void GraphicsContext::drawLineForText(const FloatPoint& pt, float width, bool)
+void GraphicsContext::drawLineForText(const FloatPoint& pt, float width, bool /* printing */)
{
if (paintingDisabled())
return;
- SkRect r;
- setrectForUnderline(&r, this, pt, 0, width);
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setColor(this->strokeColor().rgb());
-
- GC2CANVAS(this)->drawRect(r, paint);
+ platformContext()->drawLineForText(pt, width);
}
-// TODO: Should we draw different based on TextCheckingLineStyle?
-void GraphicsContext::drawLineForTextChecking(const FloatPoint& pt, float width, TextCheckingLineStyle)
+void GraphicsContext::drawLineForTextChecking(const FloatPoint& pt, float width,
+ TextCheckingLineStyle style)
{
if (paintingDisabled())
return;
- SkRect r;
- setrectForUnderline(&r, this, pt, 0, width);
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setColor(SK_ColorRED); // Is this specified somewhere?
-
- GC2CANVAS(this)->drawRect(r, paint);
+ platformContext()->drawLineForTextChecking(pt, width, style);
}
// This method is only used to draw the little circles used in lists.
@@ -623,28 +167,7 @@ void GraphicsContext::drawEllipse(const IntRect& rect)
if (paintingDisabled())
return;
- SkPaint paint;
- SkRect oval(rect);
-
- if (fillColor().rgb() & 0xFF000000) {
- m_data->setupPaintFill(&paint);
- GC2CANVAS(this)->drawOval(oval, paint);
- }
- if (strokeStyle() != NoStroke) {
- paint.reset();
- m_data->setupPaintStroke(&paint, &oval);
- GC2CANVAS(this)->drawOval(oval, paint);
- }
-}
-
-static inline int fastMod(int value, int max)
-{
- int sign = SkExtractSign(value);
-
- value = SkApplySign(value, sign);
- if (value >= max)
- value %= max;
- return SkApplySign(value, sign);
+ platformContext()->drawEllipse(rect);
}
void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan)
@@ -652,138 +175,43 @@ void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan)
if (paintingDisabled())
return;
- SkPath path;
- SkPaint paint;
- SkRect oval(r);
-
- if (strokeStyle() == NoStroke) {
- m_data->setupPaintFill(&paint); // We want the fill color
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setStrokeWidth(SkFloatToScalar(this->strokeThickness()));
- } else
- m_data->setupPaintStroke(&paint, 0);
-
- // We do this before converting to scalar, so we don't overflow SkFixed
- startAngle = fastMod(startAngle, 360);
- angleSpan = fastMod(angleSpan, 360);
-
- path.addArc(oval, SkIntToScalar(-startAngle), SkIntToScalar(-angleSpan));
- GC2CANVAS(this)->drawPath(path, paint);
+ platformContext()->strokeArc(r, startAngle, angleSpan);
}
-void GraphicsContext::drawConvexPolygon(size_t numPoints, const FloatPoint* points, bool shouldAntialias)
+void GraphicsContext::drawConvexPolygon(size_t numPoints, const FloatPoint* points,
+ bool shouldAntialias)
{
if (paintingDisabled())
return;
- if (numPoints <= 1)
- return;
-
- SkPaint paint;
- SkPath path;
-
- path.incReserve(numPoints);
- path.moveTo(SkFloatToScalar(points[0].x()), SkFloatToScalar(points[0].y()));
- for (size_t i = 1; i < numPoints; i++)
- path.lineTo(SkFloatToScalar(points[i].x()), SkFloatToScalar(points[i].y()));
-
- if (GC2CANVAS(this)->quickReject(path, shouldAntialias ?
- SkCanvas::kAA_EdgeType : SkCanvas::kBW_EdgeType)) {
- return;
- }
-
- if (fillColor().rgb() & 0xFF000000) {
- m_data->setupPaintFill(&paint);
- paint.setAntiAlias(shouldAntialias);
- GC2CANVAS(this)->drawPath(path, paint);
- }
-
- if (strokeStyle() != NoStroke) {
- paint.reset();
- m_data->setupPaintStroke(&paint, 0);
- paint.setAntiAlias(shouldAntialias);
- GC2CANVAS(this)->drawPath(path, paint);
- }
+ platformContext()->drawConvexPolygon(numPoints, points, shouldAntialias);
}
void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
- const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace)
+ const IntSize& bottomLeft, const IntSize& bottomRight,
+ const Color& color, ColorSpace colorSpace)
{
if (paintingDisabled())
return;
- SkPaint paint;
- SkPath path;
- SkScalar radii[8];
-
- radii[0] = SkIntToScalar(topLeft.width());
- radii[1] = SkIntToScalar(topLeft.height());
- radii[2] = SkIntToScalar(topRight.width());
- radii[3] = SkIntToScalar(topRight.height());
- radii[4] = SkIntToScalar(bottomRight.width());
- radii[5] = SkIntToScalar(bottomRight.height());
- radii[6] = SkIntToScalar(bottomLeft.width());
- radii[7] = SkIntToScalar(bottomLeft.height());
- path.addRoundRect(rect, radii);
-
- m_data->setupPaintFill(&paint);
- paint.setColor(color.rgb());
- GC2CANVAS(this)->drawPath(path, paint);
+ platformContext()->fillRoundedRect(rect, topLeft, topRight,
+ bottomLeft, bottomRight, color, colorSpace);
}
void GraphicsContext::fillRect(const FloatRect& rect)
{
- save();
- SkPaint paint;
-
- m_data->setupPaintFill(&paint);
-
- extactShader(&paint,
- m_state.fillPattern.get(),
- m_state.fillGradient.get());
+ if (paintingDisabled())
+ return;
- GC2CANVAS(this)->drawRect(rect, paint);
- restore();
+ platformContext()->fillRect(rect);
}
-void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace)
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
{
if (paintingDisabled())
return;
- if (color.rgb() & 0xFF000000) {
- save();
- SkPaint paint;
-
- m_data->setupPaintCommon(&paint);
- paint.setColor(color.rgb()); // Punch in the specified color
- paint.setShader(0); // In case we had one set
-
- // Sometimes we record and draw portions of the page, using clips
- // for each portion. The problem with this is that webkit, sometimes,
- // sees that we're only recording a portion, and they adjust some of
- // their rectangle coordinates accordingly (e.g.
- // RenderBoxModelObject::paintFillLayerExtended() which calls
- // rect.intersect(paintInfo.rect) and then draws the bg with that
- // rect. The result is that we end up drawing rects that are meant to
- // seam together (one for each portion), but if the rects have
- // fractional coordinates (e.g. we are zoomed by a fractional amount)
- // we will double-draw those edges, resulting in visual cracks or
- // artifacts.
-
- // The fix seems to be to just turn off antialasing for rects (this
- // entry-point in GraphicsContext seems to have been sufficient,
- // though perhaps we'll find we need to do this as well in fillRect(r)
- // as well.) Currently setupPaintCommon() enables antialiasing.
-
- // Since we never show the page rotated at a funny angle, disabling
- // antialiasing seems to have no real down-side, and it does fix the
- // bug when we're zoomed (and drawing portions that need to seam).
- paint.setAntiAlias(false);
-
- GC2CANVAS(this)->drawRect(rect, paint);
- restore();
- }
+ platformContext()->fillRect(rect, color, colorSpace);
}
void GraphicsContext::clip(const FloatRect& rect)
@@ -791,7 +219,7 @@ void GraphicsContext::clip(const FloatRect& rect)
if (paintingDisabled())
return;
- GC2CANVAS(this)->clipRect(rect);
+ platformContext()->clip(rect);
}
void GraphicsContext::clip(const Path& path)
@@ -799,7 +227,7 @@ void GraphicsContext::clip(const Path& path)
if (paintingDisabled())
return;
- GC2CANVAS(this)->clipPath(*path.platformPath(), SkRegion::kIntersect_Op, true);
+ platformContext()->clip(path);
}
void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
@@ -807,24 +235,15 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness
if (paintingDisabled())
return;
- SkPath path;
- SkRect r(rect);
-
- path.addOval(r, SkPath::kCW_Direction);
- // Only perform the inset if we won't invert r
- if (2 * thickness < rect.width() && 2 * thickness < rect.height()) {
- // Adding one to the thickness doesn't make the border too thick as
- // it's painted over afterwards. But without this adjustment the
- // border appears a little anemic after anti-aliasing.
- r.inset(SkIntToScalar(thickness + 1), SkIntToScalar(thickness + 1));
- path.addOval(r, SkPath::kCCW_Direction);
- }
- GC2CANVAS(this)->clipPath(path, SkRegion::kIntersect_Op, true);
+ platformContext()->addInnerRoundedRectClip(rect, thickness);
}
void GraphicsContext::canvasClip(const Path& path)
{
- clip(path);
+ if (paintingDisabled())
+ return;
+
+ platformContext()->canvasClip(path);
}
void GraphicsContext::clipOut(const IntRect& r)
@@ -832,7 +251,7 @@ void GraphicsContext::clipOut(const IntRect& r)
if (paintingDisabled())
return;
- GC2CANVAS(this)->clipRect(r, SkRegion::kDifference_Op);
+ platformContext()->clipOut(r);
}
#if ENABLE(SVG)
@@ -841,9 +260,7 @@ void GraphicsContext::clipPath(const Path& pathToClip, WindRule clipRule)
if (paintingDisabled())
return;
- SkPath path = *pathToClip.platformPath();
- path.setFillType(clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
- GC2CANVAS(this)->clipPath(path);
+ platformContext()->clipPath(pathToClip, clipRule);
}
#endif
@@ -852,7 +269,7 @@ void GraphicsContext::clipOut(const Path& p)
if (paintingDisabled())
return;
- GC2CANVAS(this)->clipPath(*p.platformPath(), SkRegion::kDifference_Op);
+ platformContext()->clipOut(p);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
@@ -864,20 +281,12 @@ KRenderingDeviceContext* GraphicsContext::createRenderingDeviceContext()
}
#endif
-// These are the flags we need when we call saveLayer for transparency.
-// Since it does not appear that webkit intends this to also save/restore
-// the matrix or clip, I do not give those flags (for performance)
-#define TRANSPARENCY_SAVEFLAGS \
- (SkCanvas::SaveFlags)(SkCanvas::kHasAlphaLayer_SaveFlag | \
- SkCanvas::kFullColorLayer_SaveFlag)
-
void GraphicsContext::beginTransparencyLayer(float opacity)
{
if (paintingDisabled())
return;
- SkCanvas* canvas = GC2CANVAS(this);
- canvas->saveLayerAlpha(0, (int)(opacity * 255), TRANSPARENCY_SAVEFLAGS);
+ platformContext()->beginTransparencyLayer(opacity);
}
void GraphicsContext::endTransparencyLayer()
@@ -885,44 +294,44 @@ void GraphicsContext::endTransparencyLayer()
if (paintingDisabled())
return;
- GC2CANVAS(this)->restore();
+ platformContext()->endTransparencyLayer();
}
///////////////////////////////////////////////////////////////////////////
-void GraphicsContext::setupBitmapPaint(SkPaint* paint)
-{
- m_data->setupPaintBitmap(paint);
-}
-
void GraphicsContext::setupFillPaint(SkPaint* paint)
{
- m_data->setupPaintFill(paint);
+ platformContext()->setupPaintFill(paint);
}
void GraphicsContext::setupStrokePaint(SkPaint* paint)
{
- m_data->setupPaintStroke(paint, 0);
+ platformContext()->setupPaintStroke(paint, 0);
}
bool GraphicsContext::setupShadowPaint(SkPaint* paint, SkPoint* offset)
{
- return m_data->getState()->setupShadowPaint(this, paint, offset);
+ return platformContext()->setupPaintShadow(paint, offset);
}
void GraphicsContext::setPlatformStrokeColor(const Color& c, ColorSpace)
{
- m_data->setStrokeColor(c);
+ platformContext()->setStrokeColor(c);
}
void GraphicsContext::setPlatformStrokeThickness(float f)
{
- m_data->setStrokeThickness(f);
+ platformContext()->setStrokeThickness(f);
+}
+
+void GraphicsContext::setPlatformStrokeStyle(StrokeStyle style)
+{
+ platformContext()->setStrokeStyle(style);
}
void GraphicsContext::setPlatformFillColor(const Color& c, ColorSpace)
{
- m_data->setFillColor(c);
+ platformContext()->setFillColor(c);
}
void GraphicsContext::setPlatformShadow(const FloatSize& size, float blur, const Color& color, ColorSpace)
@@ -938,7 +347,7 @@ void GraphicsContext::setPlatformShadow(const FloatSize& size, float blur, const
c = color.rgb();
else
c = SkColorSetARGB(0xFF / 3, 0, 0, 0); // "std" Apple shadow color
- m_data->getState()->setShadow(blur, size.width(), size.height(), c);
+ platformContext()->setShadow(blur, size.width(), size.height(), c);
}
void GraphicsContext::clearPlatformShadow()
@@ -946,38 +355,17 @@ void GraphicsContext::clearPlatformShadow()
if (paintingDisabled())
return;
- m_data->getState()->setShadow(0, 0, 0, 0);
+ platformContext()->setShadow(0, 0, 0, 0);
}
///////////////////////////////////////////////////////////////////////////////
-void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int /* width */, int /* offset */, const Color& color)
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
{
if (paintingDisabled())
return;
- unsigned rectCount = rects.size();
- if (!rectCount)
- return;
-
- SkRegion focusRingRegion;
- const SkScalar focusRingOutset = WebCoreFloatToSkScalar(0.8);
- 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()->mCanvas->drawPath(path, paint);
+ platformContext()->drawFocusRing(rects, width, offset, color);
}
void GraphicsContext::drawFocusRing(const Path&, int, int, const Color&)
@@ -988,22 +376,28 @@ void GraphicsContext::drawFocusRing(const Path&, int, int, const Color&)
PlatformGraphicsContext* GraphicsContext::platformContext() const
{
ASSERT(!paintingDisabled());
- return m_data->getPlatformGfxCtx();
+ return m_data->context();
}
void GraphicsContext::setMiterLimit(float limit)
{
- m_data->getState()->miterLimit = limit;
+ if (paintingDisabled())
+ return;
+ platformContext()->setMiterLimit(limit);
}
void GraphicsContext::setAlpha(float alpha)
{
- m_data->getState()->alpha = alpha;
+ if (paintingDisabled())
+ return;
+ platformContext()->setAlpha(alpha);
}
void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
{
- m_data->getState()->mode = WebCoreCompositeToSkiaComposite(op);
+ if (paintingDisabled())
+ return;
+ platformContext()->setCompositeOperation(op);
}
void GraphicsContext::clearRect(const FloatRect& rect)
@@ -1011,11 +405,7 @@ void GraphicsContext::clearRect(const FloatRect& rect)
if (paintingDisabled())
return;
- SkPaint paint;
-
- m_data->setupPaintFill(&paint);
- paint.setXfermodeMode(SkXfermode::kClear_Mode);
- GC2CANVAS(this)->drawRect(rect, paint);
+ platformContext()->clearRect(rect);
}
void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
@@ -1023,29 +413,14 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
if (paintingDisabled())
return;
- SkPaint paint;
-
- m_data->setupPaintStroke(&paint, 0);
- paint.setStrokeWidth(SkFloatToScalar(lineWidth));
- GC2CANVAS(this)->drawRect(rect, paint);
+ platformContext()->strokeRect(rect, lineWidth);
}
void GraphicsContext::setLineCap(LineCap cap)
{
- switch (cap) {
- case ButtCap:
- m_data->getState()->lineCap = SkPaint::kButt_Cap;
- break;
- case RoundCap:
- m_data->getState()->lineCap = SkPaint::kRound_Cap;
- break;
- case SquareCap:
- m_data->getState()->lineCap = SkPaint::kSquare_Cap;
- break;
- default:
- SkDEBUGF(("GraphicsContext::setLineCap: unknown LineCap %d\n", cap));
- break;
- }
+ if (paintingDisabled())
+ return;
+ platformContext()->setLineCap(cap);
}
#if ENABLE(SVG)
@@ -1054,67 +429,43 @@ void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
if (paintingDisabled())
return;
- size_t dashLength = dashes.size();
- if (!dashLength)
- return;
-
- size_t count = !(dashLength % 2) ? dashLength : dashLength * 2;
- SkScalar* intervals = new SkScalar[count];
-
- for (unsigned int i = 0; i < count; i++)
- intervals[i] = SkFloatToScalar(dashes[i % dashLength]);
- SkPathEffect **effectPtr = &m_data->getState()->pathEffect;
- SkSafeUnref(*effectPtr);
- *effectPtr = new SkDashPathEffect(intervals, count, SkFloatToScalar(dashOffset));
-
- delete[] intervals;
+ platformContext()->setLineDash(dashes, dashOffset);
}
#endif
void GraphicsContext::setLineJoin(LineJoin join)
{
- switch (join) {
- case MiterJoin:
- m_data->getState()->lineJoin = SkPaint::kMiter_Join;
- break;
- case RoundJoin:
- m_data->getState()->lineJoin = SkPaint::kRound_Join;
- break;
- case BevelJoin:
- m_data->getState()->lineJoin = SkPaint::kBevel_Join;
- break;
- default:
- SkDEBUGF(("GraphicsContext::setLineJoin: unknown LineJoin %d\n", join));
- break;
- }
+ if (paintingDisabled())
+ return;
+ platformContext()->setLineJoin(join);
}
void GraphicsContext::scale(const FloatSize& size)
{
if (paintingDisabled())
return;
- GC2CANVAS(this)->scale(SkFloatToScalar(size.width()), SkFloatToScalar(size.height()));
+ platformContext()->scale(size);
}
void GraphicsContext::rotate(float angleInRadians)
{
if (paintingDisabled())
return;
- GC2CANVAS(this)->rotate(SkFloatToScalar(angleInRadians * (180.0f / 3.14159265f)));
+ platformContext()->rotate(angleInRadians);
}
void GraphicsContext::translate(float x, float y)
{
if (paintingDisabled())
return;
- GC2CANVAS(this)->translate(SkFloatToScalar(x), SkFloatToScalar(y));
+ platformContext()->translate(x, y);
}
void GraphicsContext::concatCTM(const AffineTransform& affine)
{
if (paintingDisabled())
return;
- GC2CANVAS(this)->concat(affine);
+ platformContext()->concatCTM(affine);
}
// This is intended to round the rect to device pixels (through the CTM)
@@ -1139,39 +490,42 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect, RoundingMo
void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
{
// Appears to be PDF specific, so we ignore it
-#if 0
-if (paintingDisabled())
- return;
-
-CFURLRef urlRef = link.createCFURL();
-if (urlRef) {
- CGContextRef context = platformContext();
-
- // Get the bounding box to handle clipping.
- CGRect box = CGContextGetClipBoundingBox(context);
+}
- IntRect intBox((int)box.origin.x, (int)box.origin.y, (int)box.size.width, (int)box.size.height);
- IntRect rect = destRect;
- rect.intersect(intBox);
+void GraphicsContext::setPlatformShouldAntialias(bool useAA)
+{
+ if (paintingDisabled())
+ return;
+ platformContext()->setShouldAntialias(useAA);
+}
- CGPDFContextSetURLForRect(context, urlRef,
- CGRectApplyAffineTransform(rect, CGContextGetCTM(context)));
+void GraphicsContext::setPlatformFillGradient(Gradient* fillGradient)
+{
+ SkShader* shader = extractShader(0, fillGradient);
+ platformContext()->setFillShader(shader);
+}
- CFRelease(urlRef);
+void GraphicsContext::setPlatformFillPattern(Pattern* fillPattern)
+{
+ SkShader* shader = extractShader(fillPattern, 0);
+ platformContext()->setFillShader(shader);
}
-#endif
+
+void GraphicsContext::setPlatformStrokeGradient(Gradient* strokeGradient)
+{
+ SkShader* shader = extractShader(0, strokeGradient);
+ platformContext()->setStrokeShader(shader);
}
-void GraphicsContext::setPlatformShouldAntialias(bool useAA)
+void GraphicsContext::setPlatformStrokePattern(Pattern* strokePattern)
{
- if (paintingDisabled())
- return;
- m_data->getState()->useAA = useAA;
+ SkShader* shader = extractShader(strokePattern, 0);
+ platformContext()->setStrokeShader(shader);
}
AffineTransform GraphicsContext::getCTM() const
{
- const SkMatrix& m = GC2CANVAS(this)->getTotalMatrix();
+ const SkMatrix& m = platformContext()->getTotalMatrix();
return AffineTransform(SkScalarToDouble(m.getScaleX()), // a
SkScalarToDouble(m.getSkewY()), // b
SkScalarToDouble(m.getSkewX()), // c
@@ -1193,43 +547,18 @@ void GraphicsContext::setCTM(const AffineTransform& transform)
void GraphicsContext::fillPath(const Path& pathToFill)
{
- SkPath* path = pathToFill.platformPath();
- if (paintingDisabled() || !path)
+ if (paintingDisabled())
return;
- switch (this->fillRule()) {
- case RULE_NONZERO:
- path->setFillType(SkPath::kWinding_FillType);
- break;
- case RULE_EVENODD:
- path->setFillType(SkPath::kEvenOdd_FillType);
- break;
- }
-
- SkPaint paint;
- m_data->setupPaintFill(&paint);
-
- extactShader(&paint,
- m_state.fillPattern.get(),
- m_state.fillGradient.get());
-
- GC2CANVAS(this)->drawPath(*path, paint);
+ platformContext()->fillPath(pathToFill, fillRule());
}
void GraphicsContext::strokePath(const Path& pathToStroke)
{
- const SkPath* path = pathToStroke.platformPath();
- if (paintingDisabled() || !path)
+ if (paintingDisabled())
return;
- SkPaint paint;
- m_data->setupPaintStroke(&paint, 0);
-
- extactShader(&paint,
- m_state.strokePattern.get(),
- m_state.strokeGradient.get());
-
- GC2CANVAS(this)->drawPath(*path, paint);
+ platformContext()->strokePath(pathToStroke);
}
InterpolationQuality GraphicsContext::imageInterpolationQuality() const
@@ -1255,7 +584,8 @@ void GraphicsContext::setImageInterpolationQuality(InterpolationQuality mode)
// Certainly safe to do nothing for the present.
}
-void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint*, bool antialias)
+void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint*,
+ bool antialias)
{
if (paintingDisabled())
return;
@@ -1266,23 +596,17 @@ void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint*, boo
// FIXME: IMPLEMENT!
}
-void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const FloatPoint& point, int h, const Color& backgroundColor, ColorSpace colorSpace, int from, int to, bool isActive)
+void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run,
+ const FloatPoint& point, int h,
+ const Color& backgroundColor,
+ ColorSpace colorSpace, int from,
+ int to, bool isActive)
{
if (paintingDisabled())
return;
- IntRect rect = (IntRect)font.selectionRectForText(run, point, h, from, to);
- if (isActive)
- fillRect(rect, backgroundColor, colorSpace);
- else {
- int x = rect.x(), y = rect.y(), w = rect.width(), h = rect.height();
- const int t = 3, t2 = t * 2;
-
- fillRect(IntRect(x, y, w, t), backgroundColor, colorSpace);
- fillRect(IntRect(x, y+h-t, w, t), backgroundColor, colorSpace);
- fillRect(IntRect(x, y+t, t, h-t2), backgroundColor, colorSpace);
- fillRect(IntRect(x+w-t, y+t, t, h-t2), backgroundColor, colorSpace);
- }
+ platformContext()->drawHighlightForText(font, run, point, h, backgroundColor,
+ colorSpace, from, to, isActive);
}
} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/ImageAndroid.cpp b/Source/WebCore/platform/graphics/android/ImageAndroid.cpp
index 8e0c112..08f72e0 100644
--- a/Source/WebCore/platform/graphics/android/ImageAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/ImageAndroid.cpp
@@ -172,20 +172,7 @@ static void round_scaled(SkIRect* dst, const WebCore::FloatRect& src,
SkScalarRound(SkFloatToScalar((src.y() + src.height()) * sy)));
}
-static inline void fixPaintForBitmapsThatMaySeam(SkPaint* paint) {
- /* Bitmaps may be drawn to seem next to other images. If we are drawn
- zoomed, or at fractional coordinates, we may see cracks/edges if
- we antialias, because that will cause us to draw the same pixels
- more than once (e.g. from the left and right bitmaps that share
- an edge).
-
- Disabling antialiasing fixes this, and since so far we are never
- rotated at non-multiple-of-90 angles, this seems to do no harm
- */
- paint->setAntiAlias(false);
-}
-
-void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
+void BitmapImage::draw(GraphicsContext* gc, const FloatRect& dstRect,
const FloatRect& srcRect, ColorSpace,
CompositeOperator compositeOp)
{
@@ -222,14 +209,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
return;
}
- SkCanvas* canvas = ctxt->platformContext()->mCanvas;
- SkPaint paint;
-
- ctxt->setupBitmapPaint(&paint); // need global alpha among other things
- paint.setFilterBitmap(true);
- paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp));
- fixPaintForBitmapsThatMaySeam(&paint);
- canvas->drawBitmapRect(bitmap, &srcR, dstR, &paint);
+ gc->platformContext()->drawBitmapRect(bitmap, &srcR, dstR, compositeOp);
#ifdef TRACE_SUBSAMPLED_BITMAPS
if (bitmap.width() != image->origWidth() ||
@@ -248,26 +228,19 @@ void BitmapImage::setURL(const String& str)
///////////////////////////////////////////////////////////////////////////////
-void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect,
+void Image::drawPattern(GraphicsContext* gc, const FloatRect& srcRect,
const AffineTransform& patternTransform,
const FloatPoint& phase, ColorSpace,
CompositeOperator compositeOp, const FloatRect& destRect)
{
SkBitmapRef* image = this->nativeImageForCurrentFrame();
- if (!image) { // If it's too early we won't have an image yet.
+ if (!image || destRect.isEmpty())
return;
- }
// in case we get called with an incomplete bitmap
const SkBitmap& origBitmap = image->bitmap();
- if (origBitmap.getPixels() == NULL && origBitmap.pixelRef() == NULL) {
+ if (origBitmap.getPixels() == NULL && origBitmap.pixelRef() == NULL)
return;
- }
-
- SkRect dstR(destRect);
- if (dstR.isEmpty()) {
- return;
- }
SkIRect srcR;
// we may have to scale if the image has been subsampled (so save RAM)
@@ -278,11 +251,9 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect,
if (imageIsSubSampled) {
scaleX = (float)image->origWidth() / origBitmap.width();
scaleY = (float)image->origHeight() / origBitmap.height();
-// SkDebugf("----- subsampled %g %g\n", scaleX, scaleY);
round_scaled(&srcR, srcRect, 1 / scaleX, 1 / scaleY);
- } else {
+ } else
round(&srcR, srcRect);
- }
// now extract the proper subset of the src image
SkBitmap bitmap;
@@ -291,19 +262,6 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect,
return;
}
- SkCanvas* canvas = ctxt->platformContext()->mCanvas;
- SkPaint paint;
- ctxt->setupBitmapPaint(&paint); // need global alpha among other things
-
- SkShader* shader = SkShader::CreateBitmapShader(bitmap,
- SkShader::kRepeat_TileMode,
- SkShader::kRepeat_TileMode);
- paint.setShader(shader)->unref();
- // now paint is the only owner of shader
- paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp));
- paint.setFilterBitmap(true);
- fixPaintForBitmapsThatMaySeam(&paint);
-
SkMatrix matrix(patternTransform);
if (imageIsSubSampled) {
@@ -316,26 +274,8 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect,
float tx = phase.x() + srcRect.x() * patternTransform.a();
float ty = phase.y() + srcRect.y() * patternTransform.d();
matrix.postTranslate(SkFloatToScalar(tx), SkFloatToScalar(ty));
- shader->setLocalMatrix(matrix);
-#if 0
- SkDebugf("--- drawPattern: src [%g %g %g %g] dst [%g %g %g %g] transform [%g %g %g %g %g %g] matrix [%g %g %g %g %g %g]\n",
- srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height(),
- destRect.x(), destRect.y(), destRect.width(), destRect.height(),
- patternTransform.a(), patternTransform.b(), patternTransform.c(),
- patternTransform.d(), patternTransform.e(), patternTransform.f(),
- matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
-#endif
- canvas->drawRect(dstR, paint);
-#ifdef TRACE_SUBSAMPLED_BITMAPS
- if (bitmap.width() != image->origWidth() ||
- bitmap.height() != image->origHeight()) {
- SkDebugf("--- Image::drawPattern [%d %d] orig [%d %d] dst [%g %g]\n",
- bitmap.width(), bitmap.height(),
- image->origWidth(), image->origHeight(),
- SkScalarToFloat(dstR.width()), SkScalarToFloat(dstR.height()));
- }
-#endif
+ gc->platformContext()->drawBitmapPattern(bitmap, matrix, compositeOp, destRect);
}
// missingImage, textAreaResizeCorner
diff --git a/Source/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp b/Source/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp
index 098534c..3c8ea3c 100644
--- a/Source/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp
+++ b/Source/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp
@@ -24,28 +24,1025 @@
*/
#include "config.h"
-#include "Node.h"
#include "PlatformGraphicsContext.h"
+
+#include "AffineTransform.h"
+#include "Font.h"
+#include "Gradient.h"
+#include "GraphicsContext.h"
+#include "Node.h"
+#include "NotImplemented.h"
+#include "Path.h"
+#include "Pattern.h"
+#include "SkBitmapRef.h"
+#include "SkBlurDrawLooper.h"
+#include "SkBlurMaskFilter.h"
#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkCornerPathEffect.h"
+#include "SkDashPathEffect.h"
+#include "SkDevice.h"
+#include "SkGradientShader.h"
+#include "SkPaint.h"
+#include "SkString.h"
+#include "SkiaUtils.h"
+#include "TransformationMatrix.h"
+#include "android_graphics.h"
namespace WebCore {
-PlatformGraphicsContext::PlatformGraphicsContext(SkCanvas* canvas)
- : mCanvas(canvas), m_deleteCanvas(false)
+// These are the flags we need when we call saveLayer for transparency.
+// Since it does not appear that webkit intends this to also save/restore
+// the matrix or clip, I do not give those flags (for performance)
+#define TRANSPARENCY_SAVEFLAGS \
+ (SkCanvas::SaveFlags)(SkCanvas::kHasAlphaLayer_SaveFlag | \
+ SkCanvas::kFullColorLayer_SaveFlag)
+
+//**************************************
+// Helper functions
+//**************************************
+
+static int RoundToInt(float x)
+{
+ return (int)roundf(x);
+}
+
+template <typename T> T* deepCopyPtr(const T* src)
+{
+ return src ? new T(*src) : 0;
+}
+
+// Set a bitmap shader that mimics dashing by width-on, width-off.
+// Returns false if it could not succeed (e.g. there was an existing shader)
+static bool setBitmapDash(SkPaint* paint, int width) {
+ if (width <= 0 || paint->getShader())
+ return false;
+
+ SkColor c = paint->getColor();
+
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, 2, 1);
+ bm.allocPixels();
+ bm.lockPixels();
+
+ // set the ON pixel
+ *bm.getAddr32(0, 0) = SkPreMultiplyARGB(0xFF, SkColorGetR(c),
+ SkColorGetG(c), SkColorGetB(c));
+ // set the OFF pixel
+ *bm.getAddr32(1, 0) = 0;
+ bm.unlockPixels();
+
+ SkMatrix matrix;
+ matrix.setScale(SkIntToScalar(width), SK_Scalar1);
+
+ SkShader* s = SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode,
+ SkShader::kClamp_TileMode);
+ s->setLocalMatrix(matrix);
+
+ paint->setShader(s)->unref();
+ return true;
+}
+
+static void setrectForUnderline(SkRect* r, float lineThickness,
+ const FloatPoint& point, int yOffset, float width)
+{
+#if 0
+ if (lineThickness < 1) // Do we really need/want this?
+ lineThickness = 1;
+#endif
+ r->fLeft = point.x();
+ r->fTop = point.y() + yOffset;
+ r->fRight = r->fLeft + width;
+ r->fBottom = r->fTop + lineThickness;
+}
+
+static inline int fastMod(int value, int max)
+{
+ int sign = SkExtractSign(value);
+
+ value = SkApplySign(value, sign);
+ if (value >= max)
+ value %= max;
+ return SkApplySign(value, sign);
+}
+
+static inline void fixPaintForBitmapsThatMaySeam(SkPaint* paint) {
+ /* Bitmaps may be drawn to seem next to other images. If we are drawn
+ zoomed, or at fractional coordinates, we may see cracks/edges if
+ we antialias, because that will cause us to draw the same pixels
+ more than once (e.g. from the left and right bitmaps that share
+ an edge).
+
+ Disabling antialiasing fixes this, and since so far we are never
+ rotated at non-multiple-of-90 angles, this seems to do no harm
+ */
+ paint->setAntiAlias(false);
+}
+
+//**************************************
+// State structs
+//**************************************
+
+struct ShadowRec {
+ SkScalar blur;
+ SkScalar dx;
+ SkScalar dy;
+ SkColor color; // alpha>0 means valid shadow
+ ShadowRec(SkScalar b = 0,
+ SkScalar x = 0,
+ SkScalar y = 0,
+ SkColor c = 0) // by default, alpha=0, so no shadow
+ : blur(b), dx(x), dy(y), color(c)
+ {};
+};
+
+struct PlatformGraphicsContext::State {
+ SkPathEffect* pathEffect;
+ float miterLimit;
+ float alpha;
+ float strokeThickness;
+ SkPaint::Cap lineCap;
+ SkPaint::Join lineJoin;
+ SkXfermode::Mode mode;
+ int dashRatio; // Ratio of the length of a dash to its width
+ ShadowRec shadow;
+ SkColor fillColor;
+ SkShader* fillShader;
+ SkColor strokeColor;
+ SkShader* strokeShader;
+ bool useAA;
+ StrokeStyle strokeStyle;
+
+ State()
+ : pathEffect(0)
+ , miterLimit(4)
+ , alpha(1)
+ , strokeThickness(0) // Same as default in GraphicsContextPrivate.h
+ , lineCap(SkPaint::kDefault_Cap)
+ , lineJoin(SkPaint::kDefault_Join)
+ , mode(SkXfermode::kSrcOver_Mode)
+ , dashRatio(3)
+ , fillColor(SK_ColorBLACK)
+ , fillShader(0)
+ , strokeColor(SK_ColorBLACK)
+ , strokeShader(0)
+ , useAA(true)
+ , strokeStyle(SolidStroke)
+ {
+ }
+
+ State(const State& other)
+ : pathEffect(other.pathEffect)
+ , miterLimit(other.miterLimit)
+ , alpha(other.alpha)
+ , strokeThickness(other.strokeThickness)
+ , lineCap(other.lineCap)
+ , lineJoin(other.lineJoin)
+ , mode(other.mode)
+ , dashRatio(other.dashRatio)
+ , shadow(other.shadow)
+ , fillColor(other.fillColor)
+ , fillShader(other.fillShader)
+ , strokeColor(other.strokeColor)
+ , strokeShader(other.strokeShader)
+ , useAA(other.useAA)
+ , strokeStyle(other.strokeStyle)
+ {
+ SkSafeRef(pathEffect);
+ SkSafeRef(fillShader);
+ SkSafeRef(strokeShader);
+ }
+
+ ~State()
+ {
+ SkSafeUnref(pathEffect);
+ SkSafeUnref(fillShader);
+ SkSafeUnref(strokeShader);
+ }
+
+ void setShadow(int radius, int dx, int dy, SkColor c)
+ {
+ // Cut the radius in half, to visually match the effect seen in
+ // safari browser
+ shadow.blur = SkScalarHalf(SkIntToScalar(radius));
+ shadow.dx = SkIntToScalar(dx);
+ shadow.dy = SkIntToScalar(dy);
+ shadow.color = c;
+ }
+
+ bool setupShadowPaint(SkPaint* paint, SkPoint* offset,
+ bool shadowsIgnoreTransforms)
+ {
+ paint->setAntiAlias(true);
+ paint->setDither(true);
+ paint->setXfermodeMode(mode);
+ paint->setColor(shadow.color);
+ offset->set(shadow.dx, shadow.dy);
+
+ // Currently, only GraphicsContexts associated with the
+ // HTMLCanvasElement have shadows ignore transforms set. This
+ // allows us to distinguish between CSS and Canvas shadows which
+ // have different rendering specifications.
+ uint32_t flags = SkBlurMaskFilter::kHighQuality_BlurFlag;
+ if (shadowsIgnoreTransforms) {
+ offset->fY = -offset->fY;
+ flags |= SkBlurMaskFilter::kIgnoreTransform_BlurFlag;
+ }
+
+ if (shadow.blur > 0) {
+ paint->setMaskFilter(SkBlurMaskFilter::Create(shadow.blur,
+ SkBlurMaskFilter::kNormal_BlurStyle))->unref();
+ }
+ return SkColorGetA(shadow.color) && (shadow.blur || shadow.dx || shadow.dy);
+ }
+
+ SkColor applyAlpha(SkColor c) const
+ {
+ int s = RoundToInt(alpha * 256);
+ if (s >= 256)
+ return c;
+ if (s < 0)
+ return 0;
+
+ int a = SkAlphaMul(SkColorGetA(c), s);
+ return (c & 0x00FFFFFF) | (a << 24);
+ }
+
+ PlatformGraphicsContext::State cloneInheritedProperties();
+private:
+ // Not supported.
+ void operator=(const State&);
+};
+
+// Returns a new State with all of this object's inherited properties copied.
+PlatformGraphicsContext::State PlatformGraphicsContext::State::cloneInheritedProperties()
{
+ return PlatformGraphicsContext::State(*this);
}
-PlatformGraphicsContext::PlatformGraphicsContext()
- : mCanvas(new SkCanvas), m_deleteCanvas(true)
+//**************************************
+// PlatformGraphicsContext
+//**************************************
+
+PlatformGraphicsContext::PlatformGraphicsContext(SkCanvas* canvas,
+ bool takeCanvasOwnership)
+ : mCanvas(canvas)
+ , m_deleteCanvas(takeCanvasOwnership)
+ , m_stateStack(sizeof(State))
+ , m_gc(0)
{
+ m_stateStack.append(State());
+ m_state = &m_stateStack.last();
}
PlatformGraphicsContext::~PlatformGraphicsContext()
{
- if (m_deleteCanvas) {
-// printf("-------------------- deleting offscreen canvas\n");
+ if (m_deleteCanvas)
delete mCanvas;
+}
+
+//**************************************
+// State management
+//**************************************
+
+void PlatformGraphicsContext::beginTransparencyLayer(float opacity)
+{
+ SkCanvas* canvas = mCanvas;
+ canvas->saveLayerAlpha(0, (int)(opacity * 255), TRANSPARENCY_SAVEFLAGS);
+}
+
+void PlatformGraphicsContext::endTransparencyLayer()
+{
+ mCanvas->restore();
+}
+
+void PlatformGraphicsContext::save()
+{
+ m_stateStack.append(m_state->cloneInheritedProperties());
+ m_state = &m_stateStack.last();
+
+ // Save our native canvas.
+ mCanvas->save();
+}
+
+void PlatformGraphicsContext::restore()
+{
+ m_stateStack.removeLast();
+ m_state = &m_stateStack.last();
+
+ // Restore our native canvas.
+ mCanvas->restore();
+}
+
+//**************************************
+// State setters
+//**************************************
+
+void PlatformGraphicsContext::setAlpha(float alpha)
+{
+ m_state->alpha = alpha;
+}
+
+void PlatformGraphicsContext::setCompositeOperation(CompositeOperator op)
+{
+ m_state->mode = WebCoreCompositeToSkiaComposite(op);
+}
+
+void PlatformGraphicsContext::setFillColor(const Color& c)
+{
+ m_state->fillColor = c.rgb();
+ setFillShader(0);
+}
+
+void PlatformGraphicsContext::setFillShader(SkShader* fillShader)
+{
+ if (fillShader)
+ m_state->fillColor = Color::black;
+
+ if (fillShader != m_state->fillShader) {
+ SkSafeUnref(m_state->fillShader);
+ m_state->fillShader = fillShader;
+ SkSafeRef(m_state->fillShader);
+ }
+}
+
+void PlatformGraphicsContext::setLineCap(LineCap cap)
+{
+ switch (cap) {
+ case ButtCap:
+ m_state->lineCap = SkPaint::kButt_Cap;
+ break;
+ case RoundCap:
+ m_state->lineCap = SkPaint::kRound_Cap;
+ break;
+ case SquareCap:
+ m_state->lineCap = SkPaint::kSquare_Cap;
+ break;
+ default:
+ SkDEBUGF(("PlatformGraphicsContext::setLineCap: unknown LineCap %d\n", cap));
+ break;
+ }
+}
+
+void PlatformGraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
+{
+ size_t dashLength = dashes.size();
+ if (!dashLength)
+ return;
+
+ size_t count = !(dashLength % 2) ? dashLength : dashLength * 2;
+ SkScalar* intervals = new SkScalar[count];
+
+ for (unsigned int i = 0; i < count; i++)
+ intervals[i] = SkFloatToScalar(dashes[i % dashLength]);
+ SkPathEffect **effectPtr = &m_state->pathEffect;
+ SkSafeUnref(*effectPtr);
+ *effectPtr = new SkDashPathEffect(intervals, count, SkFloatToScalar(dashOffset));
+
+ delete[] intervals;
+}
+
+void PlatformGraphicsContext::setLineJoin(LineJoin join)
+{
+ switch (join) {
+ case MiterJoin:
+ m_state->lineJoin = SkPaint::kMiter_Join;
+ break;
+ case RoundJoin:
+ m_state->lineJoin = SkPaint::kRound_Join;
+ break;
+ case BevelJoin:
+ m_state->lineJoin = SkPaint::kBevel_Join;
+ break;
+ default:
+ SkDEBUGF(("PlatformGraphicsContext::setLineJoin: unknown LineJoin %d\n", join));
+ break;
+ }
+}
+
+void PlatformGraphicsContext::setMiterLimit(float limit)
+{
+ m_state->miterLimit = limit;
+}
+
+void PlatformGraphicsContext::setShadow(int radius, int dx, int dy, SkColor c)
+{
+ m_state->setShadow(radius, dx, dy, c);
+}
+
+void PlatformGraphicsContext::setShouldAntialias(bool useAA)
+{
+ m_state->useAA = useAA;
+}
+
+void PlatformGraphicsContext::setStrokeColor(const Color& c)
+{
+ m_state->strokeColor = c.rgb();
+ setStrokeShader(0);
+}
+
+void PlatformGraphicsContext::setStrokeShader(SkShader* strokeShader)
+{
+ if (strokeShader)
+ m_state->strokeColor = Color::black;
+
+ if (strokeShader != m_state->strokeShader) {
+ SkSafeUnref(m_state->strokeShader);
+ m_state->strokeShader = strokeShader;
+ SkSafeRef(m_state->strokeShader);
+ }
+}
+
+void PlatformGraphicsContext::setStrokeStyle(StrokeStyle style)
+{
+ m_state->strokeStyle = style;
+}
+
+void PlatformGraphicsContext::setStrokeThickness(float f)
+{
+ m_state->strokeThickness = f;
+}
+
+//**************************************
+// Paint setup
+//**************************************
+
+void PlatformGraphicsContext::setupPaintCommon(SkPaint* paint) const
+{
+ paint->setAntiAlias(m_state->useAA);
+ paint->setDither(true);
+ paint->setXfermodeMode(m_state->mode);
+ if (SkColorGetA(m_state->shadow.color) > 0) {
+
+ // Currently, only GraphicsContexts associated with the
+ // HTMLCanvasElement have shadows ignore transforms set. This
+ // allows us to distinguish between CSS and Canvas shadows which
+ // have different rendering specifications.
+ SkScalar dy = m_state->shadow.dy;
+ uint32_t flags = SkBlurDrawLooper::kHighQuality_BlurFlag;
+ if (shadowsIgnoreTransforms()) {
+ dy = -dy;
+ flags |= SkBlurDrawLooper::kIgnoreTransform_BlurFlag;
+ flags |= SkBlurDrawLooper::kOverrideColor_BlurFlag;
+ }
+
+ SkDrawLooper* looper = new SkBlurDrawLooper(m_state->shadow.blur,
+ m_state->shadow.dx,
+ dy,
+ m_state->shadow.color,
+ flags);
+ paint->setLooper(looper)->unref();
+ }
+ paint->setFilterBitmap(true);
+}
+
+void PlatformGraphicsContext::setupPaintFill(SkPaint* paint) const
+{
+ this->setupPaintCommon(paint);
+ paint->setColor(m_state->applyAlpha(m_state->fillColor));
+ paint->setShader(m_state->fillShader);
+}
+
+bool PlatformGraphicsContext::setupPaintShadow(SkPaint* paint, SkPoint* offset) const
+{
+ return m_state->setupShadowPaint(paint, offset, shadowsIgnoreTransforms());
+}
+
+bool PlatformGraphicsContext::setupPaintStroke(SkPaint* paint, SkRect* rect,
+ bool isHLine)
+{
+ this->setupPaintCommon(paint);
+ paint->setColor(m_state->applyAlpha(m_state->strokeColor));
+ paint->setShader(m_state->strokeShader);
+
+ float width = m_state->strokeThickness;
+
+ // This allows dashing and dotting to work properly for hairline strokes
+ // FIXME: Should we only do this for dashed and dotted strokes?
+ if (!width)
+ width = 1;
+
+ paint->setStyle(SkPaint::kStroke_Style);
+ paint->setStrokeWidth(SkFloatToScalar(width));
+ paint->setStrokeCap(m_state->lineCap);
+ paint->setStrokeJoin(m_state->lineJoin);
+ paint->setStrokeMiter(SkFloatToScalar(m_state->miterLimit));
+
+ if (rect && (RoundToInt(width) & 1))
+ rect->inset(-SK_ScalarHalf, -SK_ScalarHalf);
+
+ SkPathEffect* pe = m_state->pathEffect;
+ if (pe) {
+ paint->setPathEffect(pe);
+ return false;
+ }
+ switch (m_state->strokeStyle) {
+ case NoStroke:
+ case SolidStroke:
+ width = 0;
+ break;
+ case DashedStroke:
+ width = m_state->dashRatio * width;
+ break;
+ // No break
+ case DottedStroke:
+ break;
+ }
+
+ if (width > 0) {
+ // Return true if we're basically a dotted dash of squares
+ bool justSqrs = RoundToInt(width) == RoundToInt(paint->getStrokeWidth());
+
+ if (justSqrs || !isHLine || !setBitmapDash(paint, width)) {
+#if 0
+ // this is slow enough that we just skip it for now
+ // see http://b/issue?id=4163023
+ SkScalar intervals[] = { width, width };
+ pe = new SkDashPathEffect(intervals, 2, 0);
+ paint->setPathEffect(pe)->unref();
+#endif
+ }
+ return justSqrs;
+ }
+ return false;
+}
+
+//**************************************
+// Matrix operations
+//**************************************
+
+void PlatformGraphicsContext::concatCTM(const AffineTransform& affine)
+{
+ mCanvas->concat(affine);
+}
+
+void PlatformGraphicsContext::rotate(float angleInRadians)
+{
+ mCanvas->rotate(SkFloatToScalar(angleInRadians * (180.0f / 3.14159265f)));
+}
+
+void PlatformGraphicsContext::scale(const FloatSize& size)
+{
+ mCanvas->scale(SkFloatToScalar(size.width()), SkFloatToScalar(size.height()));
+}
+
+void PlatformGraphicsContext::translate(float x, float y)
+{
+ mCanvas->translate(SkFloatToScalar(x), SkFloatToScalar(y));
+}
+
+//**************************************
+// Clipping
+//**************************************
+
+void PlatformGraphicsContext::addInnerRoundedRectClip(const IntRect& rect,
+ int thickness)
+{
+ SkPath path;
+ SkRect r(rect);
+
+ path.addOval(r, SkPath::kCW_Direction);
+ // Only perform the inset if we won't invert r
+ if (2 * thickness < rect.width() && 2 * thickness < rect.height()) {
+ // Adding one to the thickness doesn't make the border too thick as
+ // it's painted over afterwards. But without this adjustment the
+ // border appears a little anemic after anti-aliasing.
+ r.inset(SkIntToScalar(thickness + 1), SkIntToScalar(thickness + 1));
+ path.addOval(r, SkPath::kCCW_Direction);
+ }
+ mCanvas->clipPath(path, SkRegion::kIntersect_Op, true);
+}
+
+void PlatformGraphicsContext::canvasClip(const Path& path)
+{
+ clip(path);
+}
+
+void PlatformGraphicsContext::clip(const FloatRect& rect)
+{
+ mCanvas->clipRect(rect);
+}
+
+void PlatformGraphicsContext::clip(const Path& path)
+{
+ mCanvas->clipPath(*path.platformPath(), SkRegion::kIntersect_Op, true);
+}
+
+void PlatformGraphicsContext::clipConvexPolygon(size_t numPoints,
+ const FloatPoint*, bool antialias)
+{
+ if (numPoints <= 1)
+ return;
+
+ // This is only used if HAVE_PATH_BASED_BORDER_RADIUS_DRAWING is defined
+ // in RenderObject.h which it isn't for us. TODO: Support that :)
+}
+
+void PlatformGraphicsContext::clipOut(const IntRect& r)
+{
+ mCanvas->clipRect(r, SkRegion::kDifference_Op);
+}
+
+void PlatformGraphicsContext::clipOut(const Path& p)
+{
+ mCanvas->clipPath(*p.platformPath(), SkRegion::kDifference_Op);
+}
+
+void PlatformGraphicsContext::clipPath(const Path& pathToClip, WindRule clipRule)
+{
+ SkPath path = *pathToClip.platformPath();
+ path.setFillType(clipRule == RULE_EVENODD
+ ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
+ mCanvas->clipPath(path);
+}
+void PlatformGraphicsContext::clearRect(const FloatRect& rect)
+{
+ SkPaint paint;
+
+ setupPaintFill(&paint);
+ paint.setXfermodeMode(SkXfermode::kClear_Mode);
+ mCanvas->drawRect(rect, paint);
+}
+
+//**************************************
+// Drawing
+//**************************************
+
+void PlatformGraphicsContext::drawBitmapPattern(
+ const SkBitmap& bitmap, const SkMatrix& matrix,
+ CompositeOperator compositeOp, const FloatRect& destRect)
+{
+ SkShader* shader = SkShader::CreateBitmapShader(bitmap,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+ shader->setLocalMatrix(matrix);
+ SkPaint paint;
+ setupPaintFill(&paint);
+ paint.setShader(shader);
+ paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp));
+ fixPaintForBitmapsThatMaySeam(&paint);
+ mCanvas->drawRect(destRect, paint);
+}
+
+void PlatformGraphicsContext::drawBitmapRect(const SkBitmap& bitmap,
+ const SkIRect* src, const SkRect& dst,
+ CompositeOperator op)
+{
+ SkPaint paint;
+ setupPaintFill(&paint);
+ paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(op));
+ fixPaintForBitmapsThatMaySeam(&paint);
+ mCanvas->drawBitmapRect(bitmap, src, dst, &paint);
+}
+
+void PlatformGraphicsContext::drawConvexPolygon(size_t numPoints,
+ const FloatPoint* points,
+ bool shouldAntialias)
+{
+ if (numPoints <= 1)
+ return;
+
+ SkPaint paint;
+ SkPath path;
+
+ path.incReserve(numPoints);
+ path.moveTo(SkFloatToScalar(points[0].x()), SkFloatToScalar(points[0].y()));
+ for (size_t i = 1; i < numPoints; i++)
+ path.lineTo(SkFloatToScalar(points[i].x()), SkFloatToScalar(points[i].y()));
+
+ if (mCanvas->quickReject(path, shouldAntialias ?
+ SkCanvas::kAA_EdgeType : SkCanvas::kBW_EdgeType)) {
+ return;
+ }
+
+ if (m_state->fillColor & 0xFF000000) {
+ setupPaintFill(&paint);
+ paint.setAntiAlias(shouldAntialias);
+ mCanvas->drawPath(path, paint);
+ }
+
+ if (m_state->strokeStyle != NoStroke) {
+ paint.reset();
+ setupPaintStroke(&paint, 0);
+ paint.setAntiAlias(shouldAntialias);
+ mCanvas->drawPath(path, paint);
+ }
+}
+
+void PlatformGraphicsContext::drawEllipse(const IntRect& rect)
+{
+ SkPaint paint;
+ SkRect oval(rect);
+
+ if (m_state->fillColor & 0xFF000000) {
+ setupPaintFill(&paint);
+ mCanvas->drawOval(oval, paint);
+ }
+ if (m_state->strokeStyle != NoStroke) {
+ paint.reset();
+ setupPaintStroke(&paint, &oval);
+ mCanvas->drawOval(oval, paint);
+ }
+}
+
+void PlatformGraphicsContext::drawFocusRing(const Vector<IntRect>& rects,
+ int /* width */, int /* offset */,
+ const Color& color)
+{
+ unsigned rectCount = rects.size();
+ if (!rectCount)
+ return;
+
+ SkRegion focusRingRegion;
+ const SkScalar focusRingOutset = WebCoreFloatToSkScalar(0.8);
+ 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);
+ mCanvas->drawPath(path, paint);
+}
+
+void PlatformGraphicsContext::drawHighlightForText(
+ const Font& font, const TextRun& run, const FloatPoint& point, int h,
+ const Color& backgroundColor, ColorSpace colorSpace, int from,
+ int to, bool isActive)
+{
+ IntRect rect = (IntRect)font.selectionRectForText(run, point, h, from, to);
+ if (isActive)
+ fillRect(rect, backgroundColor, colorSpace);
+ else {
+ int x = rect.x(), y = rect.y(), w = rect.width(), h = rect.height();
+ const int t = 3, t2 = t * 2;
+
+ fillRect(IntRect(x, y, w, t), backgroundColor, colorSpace);
+ fillRect(IntRect(x, y+h-t, w, t), backgroundColor, colorSpace);
+ fillRect(IntRect(x, y+t, t, h-t2), backgroundColor, colorSpace);
+ fillRect(IntRect(x+w-t, y+t, t, h-t2), backgroundColor, colorSpace);
+ }
+}
+
+void PlatformGraphicsContext::drawLine(const IntPoint& point1,
+ const IntPoint& point2)
+{
+ StrokeStyle style = m_state->strokeStyle;
+ if (style == NoStroke)
+ return;
+
+ SkPaint paint;
+ SkCanvas* canvas = mCanvas;
+ const int idx = SkAbs32(point2.x() - point1.x());
+ const int idy = SkAbs32(point2.y() - point1.y());
+
+ // Special-case horizontal and vertical lines that are really just dots
+ if (setupPaintStroke(&paint, 0, !idy) && (!idx || !idy)) {
+ const SkScalar diameter = paint.getStrokeWidth();
+ const SkScalar radius = SkScalarHalf(diameter);
+ SkScalar x = SkIntToScalar(SkMin32(point1.x(), point2.x()));
+ SkScalar y = SkIntToScalar(SkMin32(point1.y(), point2.y()));
+ SkScalar dx, dy;
+ int count;
+ SkRect bounds;
+
+ if (!idy) { // Horizontal
+ bounds.set(x, y - radius, x + SkIntToScalar(idx), y + radius);
+ x += radius;
+ dx = diameter * 2;
+ dy = 0;
+ count = idx;
+ } else { // Vertical
+ bounds.set(x - radius, y, x + radius, y + SkIntToScalar(idy));
+ y += radius;
+ dx = 0;
+ dy = diameter * 2;
+ count = idy;
+ }
+
+ // The actual count is the number of ONs we hit alternating
+ // ON(diameter), OFF(diameter), ...
+ {
+ SkScalar width = SkScalarDiv(SkIntToScalar(count), diameter);
+ // Now compute the number of cells (ON and OFF)
+ count = SkScalarRound(width);
+ // Now compute the number of ONs
+ count = (count + 1) >> 1;
+ }
+
+ SkAutoMalloc storage(count * sizeof(SkPoint));
+ SkPoint* verts = (SkPoint*)storage.get();
+ // Now build the array of vertices to past to drawPoints
+ for (int i = 0; i < count; i++) {
+ verts[i].set(x, y);
+ x += dx;
+ y += dy;
+ }
+
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setPathEffect(0);
+
+ // Clipping to bounds is not required for correctness, but it does
+ // allow us to reject the entire array of points if we are completely
+ // offscreen. This is common in a webpage for android, where most of
+ // the content is clipped out. If drawPoints took an (optional) bounds
+ // parameter, that might even be better, as we would *just* use it for
+ // culling, and not both wacking the canvas' save/restore stack.
+ canvas->save(SkCanvas::kClip_SaveFlag);
+ canvas->clipRect(bounds);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, count, verts, paint);
+ canvas->restore();
+ } else {
+ SkPoint pts[2] = { point1, point2 };
+ canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
+ }
+}
+
+void PlatformGraphicsContext::drawLineForText(const FloatPoint& pt, float width)
+{
+ SkRect r;
+ setrectForUnderline(&r, m_state->strokeThickness, pt, 0, width);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(m_state->strokeColor);
+
+ mCanvas->drawRect(r, paint);
+}
+
+void PlatformGraphicsContext::drawLineForTextChecking(const FloatPoint& pt,
+ float width, GraphicsContext::TextCheckingLineStyle)
+{
+ // TODO: Should we draw different based on TextCheckingLineStyle?
+ SkRect r;
+ setrectForUnderline(&r, m_state->strokeThickness, pt, 0, width);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(SK_ColorRED); // Is this specified somewhere?
+
+ mCanvas->drawRect(r, paint);
+}
+
+void PlatformGraphicsContext::drawRect(const IntRect& rect)
+{
+ SkPaint paint;
+ SkRect r(rect);
+
+ if (m_state->fillColor & 0xFF000000) {
+ setupPaintFill(&paint);
+ mCanvas->drawRect(r, paint);
+ }
+
+ // According to GraphicsContext.h, stroking inside drawRect always means
+ // a stroke of 1 inside the rect.
+ if (m_state->strokeStyle != NoStroke && (m_state->strokeColor & 0xFF000000)) {
+ paint.reset();
+ setupPaintStroke(&paint, &r);
+ paint.setPathEffect(0); // No dashing please
+ paint.setStrokeWidth(SK_Scalar1); // Always just 1.0 width
+ r.inset(SK_ScalarHalf, SK_ScalarHalf); // Ensure we're "inside"
+ mCanvas->drawRect(r, paint);
+ }
+}
+
+void PlatformGraphicsContext::fillPath(const Path& pathToFill, WindRule fillRule)
+{
+ SkPath* path = pathToFill.platformPath();
+ if (!path)
+ return;
+
+ switch (fillRule) {
+ case RULE_NONZERO:
+ path->setFillType(SkPath::kWinding_FillType);
+ break;
+ case RULE_EVENODD:
+ path->setFillType(SkPath::kEvenOdd_FillType);
+ break;
+ }
+
+ SkPaint paint;
+ setupPaintFill(&paint);
+
+ mCanvas->drawPath(*path, paint);
+}
+
+void PlatformGraphicsContext::fillRect(const FloatRect& rect)
+{
+ SkPaint paint;
+ setupPaintFill(&paint);
+ mCanvas->drawRect(rect, paint);
+}
+
+void PlatformGraphicsContext::fillRect(const FloatRect& rect,
+ const Color& color, ColorSpace)
+{
+ if (color.rgb() & 0xFF000000) {
+ SkPaint paint;
+
+ setupPaintCommon(&paint);
+ paint.setColor(color.rgb()); // Punch in the specified color
+ paint.setShader(0); // In case we had one set
+
+ // Sometimes we record and draw portions of the page, using clips
+ // for each portion. The problem with this is that webkit, sometimes,
+ // sees that we're only recording a portion, and they adjust some of
+ // their rectangle coordinates accordingly (e.g.
+ // RenderBoxModelObject::paintFillLayerExtended() which calls
+ // rect.intersect(paintInfo.rect) and then draws the bg with that
+ // rect. The result is that we end up drawing rects that are meant to
+ // seam together (one for each portion), but if the rects have
+ // fractional coordinates (e.g. we are zoomed by a fractional amount)
+ // we will double-draw those edges, resulting in visual cracks or
+ // artifacts.
+
+ // The fix seems to be to just turn off antialasing for rects (this
+ // entry-point in GraphicsContext seems to have been sufficient,
+ // though perhaps we'll find we need to do this as well in fillRect(r)
+ // as well.) Currently setupPaintCommon() enables antialiasing.
+
+ // Since we never show the page rotated at a funny angle, disabling
+ // antialiasing seems to have no real down-side, and it does fix the
+ // bug when we're zoomed (and drawing portions that need to seam).
+ paint.setAntiAlias(false);
+
+ mCanvas->drawRect(rect, paint);
}
}
+void PlatformGraphicsContext::fillRoundedRect(
+ const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
+ const IntSize& bottomLeft, const IntSize& bottomRight,
+ const Color& color, ColorSpace)
+{
+ SkPaint paint;
+ SkPath path;
+ SkScalar radii[8];
+
+ radii[0] = SkIntToScalar(topLeft.width());
+ radii[1] = SkIntToScalar(topLeft.height());
+ radii[2] = SkIntToScalar(topRight.width());
+ radii[3] = SkIntToScalar(topRight.height());
+ radii[4] = SkIntToScalar(bottomRight.width());
+ radii[5] = SkIntToScalar(bottomRight.height());
+ radii[6] = SkIntToScalar(bottomLeft.width());
+ radii[7] = SkIntToScalar(bottomLeft.height());
+ path.addRoundRect(rect, radii);
+
+ setupPaintFill(&paint);
+ paint.setColor(color.rgb());
+ mCanvas->drawPath(path, paint);
+}
+
+void PlatformGraphicsContext::strokeArc(const IntRect& r, int startAngle,
+ int angleSpan)
+{
+ SkPath path;
+ SkPaint paint;
+ SkRect oval(r);
+
+ if (m_state->strokeStyle == NoStroke) {
+ setupPaintFill(&paint); // We want the fill color
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkFloatToScalar(m_state->strokeThickness));
+ } else
+ setupPaintStroke(&paint, 0);
+
+ // We do this before converting to scalar, so we don't overflow SkFixed
+ startAngle = fastMod(startAngle, 360);
+ angleSpan = fastMod(angleSpan, 360);
+
+ path.addArc(oval, SkIntToScalar(-startAngle), SkIntToScalar(-angleSpan));
+ mCanvas->drawPath(path, paint);
+}
+
+void PlatformGraphicsContext::strokePath(const Path& pathToStroke)
+{
+ const SkPath* path = pathToStroke.platformPath();
+ if (!path)
+ return;
+
+ SkPaint paint;
+ setupPaintStroke(&paint, 0);
+
+ mCanvas->drawPath(*path, paint);
+}
+
+void PlatformGraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
+{
+ SkPaint paint;
+
+ setupPaintStroke(&paint, 0);
+ paint.setStrokeWidth(SkFloatToScalar(lineWidth));
+ mCanvas->drawRect(rect, paint);
+}
+
} // WebCore
diff --git a/Source/WebCore/platform/graphics/android/PlatformGraphicsContext.h b/Source/WebCore/platform/graphics/android/PlatformGraphicsContext.h
index 80ea5d6..ce126a4 100644
--- a/Source/WebCore/platform/graphics/android/PlatformGraphicsContext.h
+++ b/Source/WebCore/platform/graphics/android/PlatformGraphicsContext.h
@@ -27,30 +27,123 @@
#define platform_graphics_context_h
#include "IntRect.h"
+#include "GraphicsContext.h"
#include "RenderSkinAndroid.h"
#include "SkCanvas.h"
#include "SkPicture.h"
#include "SkTDArray.h"
+#include <wtf/Vector.h>
class SkCanvas;
namespace WebCore {
-
- class GraphicsContext;
class PlatformGraphicsContext {
public:
- PlatformGraphicsContext();
- // Pass in a recording canvas, and an array of button information to be
- // updated.
- PlatformGraphicsContext(SkCanvas* canvas);
+ PlatformGraphicsContext(SkCanvas* canvas, bool takeCanvasOwnership = false);
~PlatformGraphicsContext();
-
+
+ void setGraphicsContext(GraphicsContext* gc) { m_gc = gc; }
+
+ // FIXME: Make mCanvas private
SkCanvas* mCanvas;
-
+ // FIXME: This is used by ImageBufferAndroid, which should really be
+ // managing the canvas lifecycle itself
bool deleteUs() const { return m_deleteCanvas; }
+
+ // State management
+ void beginTransparencyLayer(float opacity);
+ void endTransparencyLayer();
+ void save();
+ void restore();
+
+ // State values
+ void setAlpha(float alpha);
+ void setCompositeOperation(CompositeOperator op);
+ void setFillColor(const Color& c);
+ void setFillShader(SkShader* fillShader);
+ void setLineCap(LineCap cap);
+ void setLineDash(const DashArray& dashes, float dashOffset);
+ void setLineJoin(LineJoin join);
+ void setMiterLimit(float limit);
+ void setShadow(int radius, int dx, int dy, SkColor c);
+ void setShouldAntialias(bool useAA);
+ void setStrokeColor(const Color& c);
+ void setStrokeShader(SkShader* strokeShader);
+ void setStrokeStyle(StrokeStyle style);
+ void setStrokeThickness(float f);
+
+ // FIXME: These setupPaint* should be private, but
+ // they are used by FontAndroid currently
+ void setupPaintFill(SkPaint* paint) const;
+ bool setupPaintShadow(SkPaint* paint, SkPoint* offset) const;
+ // Sets up the paint for stroking. Returns true if the style is really
+ // just a dash of squares (the size of the paint's stroke-width.
+ bool setupPaintStroke(SkPaint* paint, SkRect* rect, bool isHLine = false);
+
+ // Matrix operations
+ void concatCTM(const AffineTransform& affine);
+ void rotate(float angleInRadians);
+ void scale(const FloatSize& size);
+ void translate(float x, float y);
+ const SkMatrix& getTotalMatrix() { return mCanvas->getTotalMatrix(); }
+
+ // Clipping
+ void addInnerRoundedRectClip(const IntRect& rect, int thickness);
+ void canvasClip(const Path& path);
+ void clip(const FloatRect& rect);
+ void clip(const Path& path);
+ void clipConvexPolygon(size_t numPoints, const FloatPoint*, bool antialias);
+ void clipOut(const IntRect& r);
+ void clipOut(const Path& p);
+ void clipPath(const Path& pathToClip, WindRule clipRule);
+
+ // Drawing
+ void clearRect(const FloatRect& rect);
+ void drawBitmapPattern(const SkBitmap& bitmap, const SkMatrix& matrix,
+ CompositeOperator compositeOp, const FloatRect& destRect);
+ void drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
+ const SkRect& dst, CompositeOperator op);
+ void drawConvexPolygon(size_t numPoints, const FloatPoint* points,
+ bool shouldAntialias);
+ void drawEllipse(const IntRect& rect);
+ void drawFocusRing(const Vector<IntRect>& rects, int /* width */,
+ int /* offset */, const Color& color);
+ void drawHighlightForText(const Font& font, const TextRun& run,
+ const FloatPoint& point, int h,
+ const Color& backgroundColor, ColorSpace colorSpace,
+ int from, int to, bool isActive);
+ void drawLine(const IntPoint& point1, const IntPoint& point2);
+ void drawLineForText(const FloatPoint& pt, float width);
+ void drawLineForTextChecking(const FloatPoint& pt, float width,
+ GraphicsContext::TextCheckingLineStyle);
+ void drawRect(const IntRect& rect);
+ void fillPath(const Path& pathToFill, WindRule fillRule);
+ void fillRect(const FloatRect& rect);
+ void fillRect(const FloatRect& rect, const Color& color, ColorSpace);
+ void fillRoundedRect(const IntRect& rect, const IntSize& topLeft,
+ const IntSize& topRight, const IntSize& bottomLeft,
+ const IntSize& bottomRight, const Color& color,
+ ColorSpace);
+ void strokeArc(const IntRect& r, int startAngle, int angleSpan);
+ void strokePath(const Path& pathToStroke);
+ void strokeRect(const FloatRect& rect, float lineWidth);
+
private:
- bool m_deleteCanvas;
+
+ // shadowsIgnoreTransforms is only true for canvas's ImageBuffer, which will
+ // have a GraphicsContext
+ bool shadowsIgnoreTransforms() const {
+ return m_gc && m_gc->shadowsIgnoreTransforms();
+ }
+
+ void setupPaintCommon(SkPaint* paint) const;
+
+ bool m_deleteCanvas;
+ struct State;
+ WTF::Vector<State> m_stateStack;
+ State* m_state;
+ GraphicsContext* m_gc; // Back-ptr to our parent
};
}