Index: Source/core/html/canvas/CanvasRenderingContext2DState.cpp |
diff --git a/Source/core/html/canvas/CanvasRenderingContext2DState.cpp b/Source/core/html/canvas/CanvasRenderingContext2DState.cpp |
index 3aebf600c88993927f2fe9cd2ac93a86f6a0894f..dc77357cabec7e132c14b6283ed64371f451ff34 100644 |
--- a/Source/core/html/canvas/CanvasRenderingContext2DState.cpp |
+++ b/Source/core/html/canvas/CanvasRenderingContext2DState.cpp |
@@ -7,15 +7,22 @@ |
#include "core/html/canvas/CanvasRenderingContext2DState.h" |
#include "core/css/CSSFontSelector.h" |
+#include "core/css/resolver/FilterOperationResolver.h" |
+#include "core/css/resolver/StyleBuilder.h" |
+#include "core/css/resolver/StyleResolverState.h" |
#include "core/html/canvas/CanvasGradient.h" |
#include "core/html/canvas/CanvasPattern.h" |
#include "core/html/canvas/CanvasStyle.h" |
+#include "core/paint/FilterEffectBuilder.h" |
+#include "core/style/ComputedStyle.h" |
#include "platform/graphics/DrawLooperBuilder.h" |
+#include "platform/graphics/filters/SkiaImageFilterBuilder.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"; |
+static const char defaultFilter[] = "none"; |
namespace blink { |
@@ -28,6 +35,7 @@ CanvasRenderingContext2DState::CanvasRenderingContext2DState() |
, m_globalAlpha(1) |
, m_lineDashOffset(0) |
, m_unparsedFont(defaultFont) |
+ , m_unparsedFilter(defaultFilter) |
, m_textAlign(StartTextAlign) |
, m_textBaseline(AlphabeticTextBaseline) |
, m_direction(DirectionInherit) |
@@ -75,6 +83,9 @@ CanvasRenderingContext2DState::CanvasRenderingContext2DState(const CanvasRenderi |
, m_lineDashOffset(other.m_lineDashOffset) |
, m_unparsedFont(other.m_unparsedFont) |
, m_font(other.m_font) |
+ , m_unparsedFilter(other.m_unparsedFilter) |
+ , m_filterValue(other.m_filterValue) |
+ , m_resolvedFilter(other.m_resolvedFilter) |
, m_textAlign(other.m_textAlign) |
, m_textBaseline(other.m_textBaseline) |
, m_direction(other.m_direction) |
@@ -156,6 +167,9 @@ void CanvasRenderingContext2DState::fontsNeedUpdate(CSSFontSelector* fontSelecto |
ASSERT(m_realizedFont); |
m_font.update(fontSelector); |
+ // FIXME: We only really need to invalidate the resolved filter if the font |
+ // update above changed anything and the filter uses font-dependent units. |
+ m_resolvedFilter.clear(); |
} |
DEFINE_TRACE(CanvasRenderingContext2DState) |
@@ -286,6 +300,9 @@ void CanvasRenderingContext2DState::setFont(const Font& font, CSSFontSelector* s |
m_font.update(selector); |
m_realizedFont = true; |
selector->registerForInvalidationCallbacks(this); |
+ // FIXME: We only really need to invalidate the resolved filter if it |
+ // uses font-relative units. |
+ m_resolvedFilter.clear(); |
} |
const Font& CanvasRenderingContext2DState::font() const |
@@ -306,6 +323,34 @@ void CanvasRenderingContext2DState::resetTransform() |
m_isTransformInvertible = true; |
} |
+SkImageFilter* CanvasRenderingContext2DState::getFilter(Element* styleResolutionHost, const Font& font) const |
+{ |
+ if (!m_filterValue) |
+ return nullptr; |
+ |
+ if (!m_resolvedFilter) { |
+ RefPtr<ComputedStyle> filterStyle = ComputedStyle::create(); |
+ // Must set font in case the filter uses any font-relative units (em, ex) |
+ filterStyle->setFont(font); |
+ |
+ StyleResolverState resolverState(styleResolutionHost->document(), styleResolutionHost, filterStyle.get()); |
+ resolverState.setStyle(filterStyle); |
+ |
+ // TODO(junov): crbug.com/502877 Feed m_fillStyle and m_strokeStyle into FillPaint and |
+ // StrokePaint respectively for filters that reference SVG. |
+ StyleBuilder::applyProperty(CSSPropertyWebkitFilter, resolverState, m_filterValue.get()); |
+ RefPtrWillBeRawPtr<FilterEffectBuilder> filterEffectBuilder = FilterEffectBuilder::create(); |
+ const float effectiveZoom = 1.0f; // Deliberately ignore zoom on the canvas element |
+ filterEffectBuilder->build(styleResolutionHost, filterStyle->filter(), effectiveZoom); |
+ |
+ SkiaImageFilterBuilder imageFilterBuilder; |
+ RefPtrWillBeRawPtr<FilterEffect> lastEffect = filterEffectBuilder->lastEffect(); |
+ m_resolvedFilter = imageFilterBuilder.build(lastEffect.get(), ColorSpaceDeviceRGB); |
+ } |
+ |
+ return m_resolvedFilter.get(); |
+} |
+ |
SkDrawLooper* CanvasRenderingContext2DState::emptyDrawLooper() const |
{ |
if (!m_emptyDrawLooper) { |
@@ -386,6 +431,12 @@ void CanvasRenderingContext2DState::setShadowColor(SkColor shadowColor) |
shadowParameterChanged(); |
} |
+void CanvasRenderingContext2DState::setFilter(PassRefPtrWillBeRawPtr<CSSValue> filterValue) |
+{ |
+ m_filterValue = filterValue; |
+ m_resolvedFilter.clear(); |
+} |
+ |
void CanvasRenderingContext2DState::setGlobalComposite(SkXfermode::Mode mode) |
{ |
m_strokePaint.setXfermodeMode(mode); |
@@ -454,7 +505,7 @@ const SkPaint* CanvasRenderingContext2DState::getPaint(PaintType paintType, Shad |
} |
if (shadowMode == DrawShadowOnly) { |
- if (imageType == NonOpaqueImage) { |
+ if (imageType == NonOpaqueImage || m_filterValue) { |
paint->setLooper(0); |
paint->setImageFilter(shadowOnlyImageFilter()); |
return paint; |