| Index: Source/core/html/canvas/CanvasRenderingContext2DState.cpp
|
| diff --git a/Source/core/html/canvas/CanvasRenderingContext2DState.cpp b/Source/core/html/canvas/CanvasRenderingContext2DState.cpp
|
| index 5eb0ab5e6835166a51fd77dfa0922ae647fd27b5..668ff912474484234551b8e5dd34e0073461bb00 100644
|
| --- a/Source/core/html/canvas/CanvasRenderingContext2DState.cpp
|
| +++ b/Source/core/html/canvas/CanvasRenderingContext2DState.cpp
|
| @@ -10,7 +10,10 @@
|
| #include "core/html/canvas/CanvasGradient.h"
|
| #include "core/html/canvas/CanvasPattern.h"
|
| #include "core/html/canvas/CanvasStyle.h"
|
| +#include "platform/graphics/DrawLooperBuilder.h"
|
| #include "platform/graphics/skia/SkiaUtils.h"
|
| +#include "third_party/skia/include/effects/SkDashPathEffect.h"
|
| +#include "third_party/skia/include/effects/SkDropShadowImageFilter.h"
|
|
|
| static const char defaultFont[] = "10px sans-serif";
|
|
|
| @@ -18,27 +21,33 @@ namespace blink {
|
|
|
| CanvasRenderingContext2DState::CanvasRenderingContext2DState()
|
| : m_unrealizedSaveCount(0)
|
| - , m_strokeStyle(CanvasStyle::createFromRGBA(Color::black))
|
| - , m_fillStyle(CanvasStyle::createFromRGBA(Color::black))
|
| - , m_lineWidth(1)
|
| - , m_lineCap(ButtCap)
|
| - , m_lineJoin(MiterJoin)
|
| - , m_miterLimit(10)
|
| + , m_strokeStyle(CanvasStyle::createFromRGBA(SK_ColorBLACK))
|
| + , m_fillStyle(CanvasStyle::createFromRGBA(SK_ColorBLACK))
|
| , m_shadowBlur(0)
|
| , m_shadowColor(Color::transparent)
|
| , m_globalAlpha(1)
|
| - , m_globalComposite(SkXfermode::kSrcOver_Mode)
|
| - , m_isTransformInvertible(true)
|
| , m_lineDashOffset(0)
|
| - , m_imageSmoothingEnabled(true)
|
| + , m_unparsedFont(defaultFont)
|
| , m_textAlign(StartTextAlign)
|
| , m_textBaseline(AlphabeticTextBaseline)
|
| , m_direction(DirectionInherit)
|
| - , m_unparsedFont(defaultFont)
|
| , m_realizedFont(false)
|
| + , m_isTransformInvertible(true)
|
| , m_hasClip(false)
|
| , m_hasComplexClip(false)
|
| + , m_fillStyleDirty(true)
|
| + , m_strokeStyleDirty(true)
|
| + , m_lineDashDirty(false)
|
| {
|
| + m_fillPaint.setStyle(SkPaint::kFill_Style);
|
| + m_fillPaint.setAntiAlias(true);
|
| + m_strokePaint.setStyle(SkPaint::kStroke_Style);
|
| + m_strokePaint.setStrokeWidth(1);
|
| + m_strokePaint.setStrokeCap(SkPaint::kButt_Cap);
|
| + m_strokePaint.setStrokeMiter(10);
|
| + m_strokePaint.setStrokeJoin(SkPaint::kMiter_Join);
|
| + m_strokePaint.setAntiAlias(true);
|
| + setImageSmoothingEnabled(true);
|
| }
|
|
|
| CanvasRenderingContext2DState::CanvasRenderingContext2DState(const CanvasRenderingContext2DState& other, ClipListCopyMode mode)
|
| @@ -48,27 +57,31 @@ CanvasRenderingContext2DState::CanvasRenderingContext2DState(const CanvasRenderi
|
| , m_unparsedFillColor(other.m_unparsedFillColor)
|
| , m_strokeStyle(other.m_strokeStyle)
|
| , m_fillStyle(other.m_fillStyle)
|
| - , m_lineWidth(other.m_lineWidth)
|
| - , m_lineCap(other.m_lineCap)
|
| - , m_lineJoin(other.m_lineJoin)
|
| - , m_miterLimit(other.m_miterLimit)
|
| + , m_strokePaint(other.m_strokePaint)
|
| + , m_fillPaint(other.m_fillPaint)
|
| , m_shadowOffset(other.m_shadowOffset)
|
| , m_shadowBlur(other.m_shadowBlur)
|
| , m_shadowColor(other.m_shadowColor)
|
| + , m_emptyDrawLooper(other.m_emptyDrawLooper)
|
| + , m_shadowOnlyDrawLooper(other.m_shadowOnlyDrawLooper)
|
| + , m_shadowAndForegroundDrawLooper(other.m_shadowAndForegroundDrawLooper)
|
| + , m_shadowOnlyImageFilter(other.m_shadowOnlyImageFilter)
|
| + , m_shadowAndForegroundImageFilter(other.m_shadowAndForegroundImageFilter)
|
| , m_globalAlpha(other.m_globalAlpha)
|
| - , m_globalComposite(other.m_globalComposite)
|
| , m_transform(other.m_transform)
|
| - , m_isTransformInvertible(other.m_isTransformInvertible)
|
| , m_lineDashOffset(other.m_lineDashOffset)
|
| - , m_imageSmoothingEnabled(other.m_imageSmoothingEnabled)
|
| + , m_unparsedFont(other.m_unparsedFont)
|
| + , m_font(other.m_font)
|
| , m_textAlign(other.m_textAlign)
|
| , m_textBaseline(other.m_textBaseline)
|
| , m_direction(other.m_direction)
|
| - , m_unparsedFont(other.m_unparsedFont)
|
| - , m_font(other.m_font)
|
| , m_realizedFont(other.m_realizedFont)
|
| + , m_isTransformInvertible(other.m_isTransformInvertible)
|
| , m_hasClip(other.m_hasClip)
|
| , m_hasComplexClip(other.m_hasComplexClip)
|
| + , m_fillStyleDirty(other.m_fillStyleDirty)
|
| + , m_strokeStyleDirty(other.m_strokeStyleDirty)
|
| + , m_lineDashDirty(other.m_lineDashDirty)
|
| {
|
| if (mode == CopyClipList) {
|
| m_clipList = other.m_clipList;
|
| @@ -92,26 +105,31 @@ CanvasRenderingContext2DState& CanvasRenderingContext2DState::operator=(const Ca
|
| m_unparsedFillColor = other.m_unparsedFillColor;
|
| m_strokeStyle = other.m_strokeStyle;
|
| m_fillStyle = other.m_fillStyle;
|
| - m_lineWidth = other.m_lineWidth;
|
| - m_lineCap = other.m_lineCap;
|
| - m_lineJoin = other.m_lineJoin;
|
| - m_miterLimit = other.m_miterLimit;
|
| + m_strokePaint = other.m_strokePaint;
|
| + m_fillPaint = other.m_fillPaint;
|
| m_shadowOffset = other.m_shadowOffset;
|
| m_shadowBlur = other.m_shadowBlur;
|
| m_shadowColor = other.m_shadowColor;
|
| + m_emptyDrawLooper = other.m_emptyDrawLooper;
|
| + m_shadowOnlyDrawLooper = other.m_shadowOnlyDrawLooper;
|
| + m_shadowAndForegroundDrawLooper = other.m_shadowAndForegroundDrawLooper;
|
| + m_shadowOnlyImageFilter = other.m_shadowOnlyImageFilter;
|
| + m_shadowAndForegroundImageFilter = other.m_shadowAndForegroundImageFilter;
|
| m_globalAlpha = other.m_globalAlpha;
|
| - m_globalComposite = other.m_globalComposite;
|
| m_transform = other.m_transform;
|
| - m_isTransformInvertible = other.m_isTransformInvertible;
|
| - m_imageSmoothingEnabled = other.m_imageSmoothingEnabled;
|
| + m_lineDashOffset = other.m_lineDashOffset;
|
| + m_unparsedFont = other.m_unparsedFont;
|
| + m_font = other.m_font;
|
| m_textAlign = other.m_textAlign;
|
| m_textBaseline = other.m_textBaseline;
|
| m_direction = other.m_direction;
|
| - m_unparsedFont = other.m_unparsedFont;
|
| - m_font = other.m_font;
|
| m_realizedFont = other.m_realizedFont;
|
| + m_isTransformInvertible = other.m_isTransformInvertible;
|
| m_hasClip = other.m_hasClip;
|
| m_hasComplexClip = other.m_hasComplexClip;
|
| + m_fillStyleDirty = other.m_fillStyleDirty;
|
| + m_strokeStyleDirty = other.m_strokeStyleDirty;
|
| + m_lineDashDirty = other.m_lineDashDirty;
|
| m_clipList = other.m_clipList;
|
|
|
| if (m_realizedFont)
|
| @@ -143,6 +161,12 @@ DEFINE_TRACE(CanvasRenderingContext2DState)
|
| CSSFontSelectorClient::trace(visitor);
|
| }
|
|
|
| +void CanvasRenderingContext2DState::setLineDashOffset(float offset)
|
| +{
|
| + m_lineDashOffset = offset;
|
| + m_lineDashDirty = true;
|
| +}
|
| +
|
| void CanvasRenderingContext2DState::setLineDash(const Vector<float>& dash)
|
| {
|
| m_lineDash = dash;
|
| @@ -150,6 +174,65 @@ void CanvasRenderingContext2DState::setLineDash(const Vector<float>& dash)
|
| // number of elements is odd
|
| if (dash.size() % 2)
|
| m_lineDash.appendVector(dash);
|
| +
|
| + m_lineDashDirty = true;
|
| +}
|
| +
|
| +void CanvasRenderingContext2DState::updateLineDash() const
|
| +{
|
| + if (!m_lineDashDirty)
|
| + return;
|
| +
|
| + if (m_lineDash.size() == 0) {
|
| + m_strokePaint.setPathEffect(0);
|
| + } else {
|
| + m_strokePaint.setPathEffect(SkDashPathEffect::Create(m_lineDash.data(), m_lineDash.size(), m_lineDashOffset));
|
| + }
|
| +
|
| + m_lineDashDirty = false;
|
| +}
|
| +
|
| +void CanvasRenderingContext2DState::setStrokeStyle(PassRefPtrWillBeRawPtr<CanvasStyle> style)
|
| +{
|
| + m_strokeStyle = style;
|
| + m_strokeStyleDirty = true;
|
| +}
|
| +
|
| +void CanvasRenderingContext2DState::setFillStyle(PassRefPtrWillBeRawPtr<CanvasStyle> style)
|
| +{
|
| + m_fillStyle = style;
|
| + m_fillStyleDirty = true;
|
| +}
|
| +
|
| +void CanvasRenderingContext2DState::updateStrokeStyle() const
|
| +{
|
| + if (!m_strokeStyleDirty)
|
| + return;
|
| +
|
| + int clampedAlpha = clampedAlphaForBlending(m_globalAlpha);
|
| + ASSERT(m_strokeStyle);
|
| + m_strokePaint.setShader(m_strokeStyle->shader());
|
| + m_strokePaint.setColor(scaleAlpha(m_strokeStyle->paintColor(), clampedAlpha));
|
| + m_strokeStyleDirty = false;
|
| +}
|
| +
|
| +void CanvasRenderingContext2DState::updateFillStyle() const
|
| +{
|
| + if (!m_fillStyleDirty)
|
| + return;
|
| +
|
| + int clampedAlpha = clampedAlphaForBlending(m_globalAlpha);
|
| + ASSERT(m_fillStyle);
|
| + m_fillPaint.setShader(m_fillStyle->shader());
|
| + m_fillPaint.setColor(scaleAlpha(m_fillStyle->paintColor(), clampedAlpha));
|
| + m_fillStyleDirty = false;
|
| +}
|
| +
|
| +void CanvasRenderingContext2DState::setGlobalAlpha(float alpha)
|
| +{
|
| + m_globalAlpha = alpha;
|
| + m_strokeStyleDirty = true;
|
| + m_fillStyleDirty = true;
|
| }
|
|
|
| void CanvasRenderingContext2DState::clipPath(const SkPath& path, AntiAliasingMode antiAliasingMode)
|
| @@ -190,4 +273,163 @@ void CanvasRenderingContext2DState::resetTransform()
|
| m_isTransformInvertible = true;
|
| }
|
|
|
| +SkDrawLooper* CanvasRenderingContext2DState::emptyDrawLooper() const
|
| +{
|
| + if (!m_emptyDrawLooper) {
|
| + OwnPtr<DrawLooperBuilder> drawLooperBuilder = DrawLooperBuilder::create();
|
| + m_emptyDrawLooper = drawLooperBuilder->detachDrawLooper();
|
| + }
|
| + return m_emptyDrawLooper.get();
|
| +}
|
| +
|
| +SkDrawLooper* CanvasRenderingContext2DState::shadowOnlyDrawLooper() const
|
| +{
|
| + if (!m_shadowOnlyDrawLooper) {
|
| + OwnPtr<DrawLooperBuilder> drawLooperBuilder = DrawLooperBuilder::create();
|
| + drawLooperBuilder->addShadow(m_shadowOffset, m_shadowBlur, m_shadowColor, DrawLooperBuilder::ShadowIgnoresTransforms, DrawLooperBuilder::ShadowRespectsAlpha);
|
| + m_shadowOnlyDrawLooper = drawLooperBuilder->detachDrawLooper();
|
| + }
|
| + return m_shadowOnlyDrawLooper.get();
|
| +}
|
| +
|
| +SkDrawLooper* CanvasRenderingContext2DState::shadowAndForegroundDrawLooper() const
|
| +{
|
| + if (!m_shadowAndForegroundDrawLooper) {
|
| + OwnPtr<DrawLooperBuilder> drawLooperBuilder = DrawLooperBuilder::create();
|
| + drawLooperBuilder->addShadow(m_shadowOffset, m_shadowBlur, m_shadowColor, DrawLooperBuilder::ShadowIgnoresTransforms, DrawLooperBuilder::ShadowRespectsAlpha);
|
| + drawLooperBuilder->addUnmodifiedContent();
|
| + m_shadowAndForegroundDrawLooper = drawLooperBuilder->detachDrawLooper();
|
| + }
|
| + return m_shadowAndForegroundDrawLooper.get();
|
| +}
|
| +
|
| +SkImageFilter* CanvasRenderingContext2DState::shadowOnlyImageFilter() const
|
| +{
|
| + if (!m_shadowOnlyImageFilter) {
|
| + float sigma = skBlurRadiusToSigma(m_shadowBlur);
|
| + m_shadowOnlyImageFilter = adoptRef(SkDropShadowImageFilter::Create(m_shadowOffset.width(), m_shadowOffset.height(), sigma, sigma, m_shadowColor, SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode));
|
| + }
|
| + return m_shadowOnlyImageFilter.get();
|
| +}
|
| +
|
| +SkImageFilter* CanvasRenderingContext2DState::shadowAndForegroundImageFilter() const
|
| +{
|
| + if (!m_shadowAndForegroundImageFilter) {
|
| + float sigma = skBlurRadiusToSigma(m_shadowBlur);
|
| + m_shadowAndForegroundImageFilter = adoptRef(SkDropShadowImageFilter::Create(m_shadowOffset.width(), m_shadowOffset.height(), sigma, sigma, m_shadowColor, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode));
|
| + }
|
| + return m_shadowAndForegroundImageFilter.get();
|
| +}
|
| +
|
| +void CanvasRenderingContext2DState::shadowParameterChanged()
|
| +{
|
| + m_shadowOnlyDrawLooper.clear();
|
| + m_shadowAndForegroundDrawLooper.clear();
|
| + m_shadowOnlyImageFilter.clear();
|
| + m_shadowAndForegroundImageFilter.clear();
|
| +}
|
| +
|
| +void CanvasRenderingContext2DState::setShadowOffsetX(float x)
|
| +{
|
| + m_shadowOffset.setWidth(x);
|
| + shadowParameterChanged();
|
| +}
|
| +
|
| +void CanvasRenderingContext2DState::setShadowOffsetY(float y)
|
| +{
|
| + m_shadowOffset.setHeight(y);
|
| + shadowParameterChanged();
|
| +}
|
| +
|
| +void CanvasRenderingContext2DState::setShadowBlur(float shadowBlur)
|
| +{
|
| + m_shadowBlur = shadowBlur;
|
| + shadowParameterChanged();
|
| +}
|
| +
|
| +void CanvasRenderingContext2DState::setShadowColor(SkColor shadowColor)
|
| +{
|
| + m_shadowColor = shadowColor;
|
| + shadowParameterChanged();
|
| +}
|
| +
|
| +void CanvasRenderingContext2DState::setGlobalComposite(SkXfermode::Mode mode)
|
| +{
|
| + m_strokePaint.setXfermodeMode(mode);
|
| + m_fillPaint.setXfermodeMode(mode);
|
| +}
|
| +
|
| +SkXfermode::Mode CanvasRenderingContext2DState::globalComposite() const
|
| +{
|
| + SkXfermode* xferMode = m_strokePaint.getXfermode();
|
| + SkXfermode::Mode mode;
|
| + if (!xferMode || !xferMode->asMode(&mode))
|
| + return SkXfermode::kSrcOver_Mode;
|
| + return mode;
|
| +}
|
| +
|
| +void CanvasRenderingContext2DState::setImageSmoothingEnabled(bool enabled)
|
| +{
|
| + SkFilterQuality filterQuality = enabled ? kLow_SkFilterQuality : kNone_SkFilterQuality;
|
| + m_strokePaint.setFilterQuality(filterQuality);
|
| + m_fillPaint.setFilterQuality(filterQuality);
|
| +}
|
| +
|
| +bool CanvasRenderingContext2DState::imageSmoothingEnabled() const
|
| +{
|
| + return m_strokePaint.getFilterQuality() == kLow_SkFilterQuality;
|
| +}
|
| +
|
| +bool CanvasRenderingContext2DState::shouldDrawShadows() const
|
| +{
|
| + return alphaChannel(m_shadowColor) && (m_shadowBlur || !m_shadowOffset.isZero());
|
| +}
|
| +
|
| +const SkPaint* CanvasRenderingContext2DState::getPaint(PaintType paintType, ShadowMode shadowMode, OpacityMode bitmapOpacity) const
|
| +{
|
| + SkPaint* paint;
|
| + if (paintType == StrokePaintType) {
|
| + updateLineDash();
|
| + updateStrokeStyle();
|
| + paint = &m_strokePaint;
|
| + } else {
|
| + updateFillStyle();
|
| + paint = &m_fillPaint;
|
| + }
|
| +
|
| + if ((!shouldDrawShadows() && shadowMode == DrawShadowAndForeground) || shadowMode == DrawForegroundOnly) {
|
| + paint->setLooper(0);
|
| + paint->setImageFilter(0);
|
| + return paint;
|
| + }
|
| +
|
| + if (!shouldDrawShadows() && shadowMode == DrawShadowOnly) {
|
| + paint->setLooper(emptyDrawLooper()); // draw nothing
|
| + paint->setImageFilter(0);
|
| + return paint;
|
| + }
|
| +
|
| + if (shadowMode == DrawShadowOnly) {
|
| + if (bitmapOpacity == Opaque) {
|
| + paint->setLooper(shadowOnlyDrawLooper());
|
| + paint->setImageFilter(0);
|
| + return paint;
|
| + }
|
| + paint->setLooper(0);
|
| + paint->setImageFilter(shadowOnlyImageFilter());
|
| + return paint;
|
| + }
|
| +
|
| + ASSERT(shadowMode == DrawShadowAndForeground);
|
| + if (bitmapOpacity == Opaque) {
|
| + paint->setLooper(shadowAndForegroundDrawLooper());
|
| + paint->setImageFilter(0);
|
| + return paint;
|
| + }
|
| +
|
| + paint->setLooper(0);
|
| + paint->setImageFilter(shadowAndForegroundImageFilter());
|
| + return paint;
|
| +}
|
| +
|
| } // blink
|
|
|