Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(802)

Unified Diff: Source/core/html/canvas/CanvasRenderingContext2D.cpp

Issue 1093673002: Removing the dependency on GraphicsContext for drawing images in 2D canvas (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: fix for overdraw optimization failures and fix for mac build Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Source/core/html/canvas/CanvasRenderingContext2D.cpp
diff --git a/Source/core/html/canvas/CanvasRenderingContext2D.cpp b/Source/core/html/canvas/CanvasRenderingContext2D.cpp
index c65edef46ed276cf94356eea8b31d70242ba9cfc..3081cbff583f2e3625bf34563040aab11dcb8cb4 100644
--- a/Source/core/html/canvas/CanvasRenderingContext2D.cpp
+++ b/Source/core/html/canvas/CanvasRenderingContext2D.cpp
@@ -61,10 +61,13 @@
#include "platform/geometry/FloatQuad.h"
#include "platform/graphics/DrawLooperBuilder.h"
#include "platform/graphics/ExpensiveCanvasHeuristicParameters.h"
-#include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/ImageBuffer.h"
+#include "platform/graphics/StrokeData.h"
+#include "platform/graphics/skia/SkiaUtils.h"
#include "platform/text/BidiTextRun.h"
#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkImageFilter.h"
+#include "third_party/skia/include/effects/SkCornerPathEffect.h"
#include "wtf/ArrayBufferContents.h"
#include "wtf/CheckedArithmetic.h"
#include "wtf/MathExtras.h"
@@ -158,7 +161,7 @@ void CanvasRenderingContext2D::validateStateStack()
CanvasRenderingContext2DState& CanvasRenderingContext2D::modifiableState()
{
- ASSERT(!state().hasUnrealizedSaves());
+ realizeSaves();
return *m_stateStack.last();
}
@@ -300,7 +303,7 @@ void CanvasRenderingContext2D::restoreCanvasMatrixClipStack()
}
}
-void CanvasRenderingContext2D::realizeSaves(SkCanvas* canvas)
+void CanvasRenderingContext2D::realizeSaves()
{
validateStateStack();
if (state().hasUnrealizedSaves()) {
@@ -314,8 +317,7 @@ void CanvasRenderingContext2D::realizeSaves(SkCanvas* canvas)
// by the Vector operations copy the unrealized count from the previous state (in
// turn necessary to support correct resizing and unwinding of the stack).
m_stateStack.last()->resetUnrealizedSaveCount();
- if (!canvas)
- canvas = drawingCanvas();
+ SkCanvas* canvas = drawingCanvas();
if (canvas)
canvas->save();
validateStateStack();
@@ -345,16 +347,6 @@ void CanvasRenderingContext2D::restore()
if (c)
c->restore();
- // Temporary code while crbug.com/453113 is a WIP: GraphicsContext state stack
- // is no longer exercised so state stored still stored in GC must be re-installed
- // after a restore.
- GraphicsContext* gc = drawingContext();
- if (gc) {
- gc->setAlphaAsFloat(state().globalAlpha());
- gc->setCompositeOperation(state().globalComposite());
- gc->setImageInterpolationQuality(state().imageSmoothingEnabled() ? CanvasDefaultInterpolationQuality : InterpolationNone);
- }
-
validateStateStack();
}
@@ -390,7 +382,6 @@ void CanvasRenderingContext2D::setStrokeStyle(const StringOrCanvasGradientOrCanv
if (!parseColorOrCurrentColor(parsedColor, colorString, canvas()))
return;
if (state().strokeStyle()->isEquivalentRGBA(parsedColor)) {
- realizeSaves(nullptr);
modifiableState().setUnparsedStrokeColor(colorString);
return;
}
@@ -408,11 +399,7 @@ void CanvasRenderingContext2D::setStrokeStyle(const StringOrCanvasGradientOrCanv
ASSERT(canvasStyle);
- SkCanvas* c = drawingCanvas();
- realizeSaves(c);
modifiableState().setStrokeStyle(canvasStyle.release());
- if (!c)
- return;
modifiableState().setUnparsedStrokeColor(colorString);
}
@@ -435,7 +422,6 @@ void CanvasRenderingContext2D::setFillStyle(const StringOrCanvasGradientOrCanvas
if (!parseColorOrCurrentColor(parsedColor, colorString, canvas()))
return;
if (state().fillStyle()->isEquivalentRGBA(parsedColor)) {
- realizeSaves(nullptr);
modifiableState().setUnparsedFillColor(colorString);
return;
}
@@ -452,11 +438,6 @@ void CanvasRenderingContext2D::setFillStyle(const StringOrCanvasGradientOrCanvas
}
ASSERT(canvasStyle);
- SkCanvas* c = drawingCanvas();
- if (!c)
- return;
- realizeSaves(c);
-
modifiableState().setFillStyle(canvasStyle.release());
modifiableState().setUnparsedFillColor(colorString);
}
@@ -472,11 +453,7 @@ void CanvasRenderingContext2D::setLineWidth(float width)
return;
if (state().lineWidth() == width)
return;
- SkCanvas* c = drawingCanvas();
- realizeSaves(c);
modifiableState().setLineWidth(width);
- if (!c)
- return;
}
String CanvasRenderingContext2D::lineCap() const
@@ -491,11 +468,7 @@ void CanvasRenderingContext2D::setLineCap(const String& s)
return;
if (state().lineCap() == cap)
return;
- SkCanvas* c = drawingCanvas();
- realizeSaves(c);
modifiableState().setLineCap(cap);
- if (!c)
- return;
}
String CanvasRenderingContext2D::lineJoin() const
@@ -510,11 +483,7 @@ void CanvasRenderingContext2D::setLineJoin(const String& s)
return;
if (state().lineJoin() == join)
return;
- SkCanvas* c = drawingCanvas();
- realizeSaves(c);
modifiableState().setLineJoin(join);
- if (!c)
- return;
}
float CanvasRenderingContext2D::miterLimit() const
@@ -528,11 +497,7 @@ void CanvasRenderingContext2D::setMiterLimit(float limit)
return;
if (state().miterLimit() == limit)
return;
- SkCanvas* c = drawingCanvas();
- realizeSaves(c);
modifiableState().setMiterLimit(limit);
- if (!c)
- return;
}
float CanvasRenderingContext2D::shadowOffsetX() const
@@ -546,7 +511,6 @@ void CanvasRenderingContext2D::setShadowOffsetX(float x)
return;
if (state().shadowOffset().width() == x)
return;
- realizeSaves(nullptr);
modifiableState().setShadowOffsetX(x);
}
@@ -561,7 +525,6 @@ void CanvasRenderingContext2D::setShadowOffsetY(float y)
return;
if (state().shadowOffset().height() == y)
return;
- realizeSaves(nullptr);
modifiableState().setShadowOffsetY(y);
}
@@ -576,7 +539,6 @@ void CanvasRenderingContext2D::setShadowBlur(float blur)
return;
if (state().shadowBlur() == blur)
return;
- realizeSaves(nullptr);
modifiableState().setShadowBlur(blur);
}
@@ -592,7 +554,6 @@ void CanvasRenderingContext2D::setShadowColor(const String& color)
return;
if (state().shadowColor() == rgba)
return;
- realizeSaves(nullptr);
modifiableState().setShadowColor(rgba);
}
@@ -614,8 +575,6 @@ void CanvasRenderingContext2D::setLineDash(const Vector<float>& dash)
{
if (!lineDashSequenceIsValid(dash))
return;
-
- realizeSaves(nullptr);
modifiableState().setLineDash(dash);
}
@@ -628,8 +587,6 @@ void CanvasRenderingContext2D::setLineDashOffset(float offset)
{
if (!std::isfinite(offset) || state().lineDashOffset() == offset)
return;
-
- realizeSaves(nullptr);
modifiableState().setLineDashOffset(offset);
}
@@ -644,12 +601,7 @@ void CanvasRenderingContext2D::setGlobalAlpha(float alpha)
return;
if (state().globalAlpha() == alpha)
return;
- SkCanvas* c = drawingCanvas();
- realizeSaves(c);
modifiableState().setGlobalAlpha(alpha);
- if (!c)
- return;
- drawingContext()->setAlphaAsFloat(alpha);
}
String CanvasRenderingContext2D::globalCompositeOperation() const
@@ -673,12 +625,7 @@ void CanvasRenderingContext2D::setGlobalCompositeOperation(const String& operati
SkXfermode::Mode xfermode = WebCoreCompositeToSkiaComposite(op, blendMode);
if (state().globalComposite() == xfermode)
return;
- SkCanvas* c = drawingCanvas();
- realizeSaves(c);
modifiableState().setGlobalComposite(xfermode);
- if (!c)
- return;
- drawingContext()->setCompositeOperation(xfermode);
}
PassRefPtrWillBeRawPtr<SVGMatrixTearOff> CanvasRenderingContext2D::currentTransform() const
@@ -707,8 +654,6 @@ void CanvasRenderingContext2D::scale(float sx, float sy)
if (state().transform() == newTransform)
return;
- realizeSaves(c);
-
modifiableState().setTransform(newTransform);
if (!state().isTransformInvertible())
return;
@@ -731,8 +676,6 @@ void CanvasRenderingContext2D::rotate(float angleInRadians)
if (state().transform() == newTransform)
return;
- realizeSaves(c);
-
modifiableState().setTransform(newTransform);
if (!state().isTransformInvertible())
return;
@@ -756,8 +699,6 @@ void CanvasRenderingContext2D::translate(float tx, float ty)
if (state().transform() == newTransform)
return;
- realizeSaves(c);
-
modifiableState().setTransform(newTransform);
if (!state().isTransformInvertible())
return;
@@ -779,8 +720,6 @@ void CanvasRenderingContext2D::transform(float m11, float m12, float m21, float
if (state().transform() == newTransform)
return;
- realizeSaves(c);
-
modifiableState().setTransform(newTransform);
if (!state().isTransformInvertible())
return;
@@ -802,7 +741,6 @@ void CanvasRenderingContext2D::resetTransform()
if (ctm.isIdentity() && invertibleCTM)
return;
- realizeSaves(c);
// resetTransform() resolves the non-invertible CTM state.
modifiableState().resetTransform();
c->setMatrix(affineTransformToSkMatrix(canvas()->baseTransform()));
@@ -899,9 +837,12 @@ bool CanvasRenderingContext2D::draw(const DrawFunc& drawFunc, const ContainsFunc
return false;
// If gradient size is zero, then paint nothing.
- CanvasGradient* gradient = state().style(paintType)->canvasGradient();
- if (gradient && gradient->gradient()->isZeroSize())
- return false;
+ CanvasStyle* style = state().style(paintType);
+ if (style) {
+ CanvasGradient* gradient = style->canvasGradient();
+ if (gradient && gradient->gradient()->isZeroSize())
+ return false;
+ }
if (isFullCanvasCompositeMode(state().globalComposite())) {
fullCanvasCompositedDraw(drawFunc, paintType, imageType);
@@ -915,7 +856,7 @@ bool CanvasRenderingContext2D::draw(const DrawFunc& drawFunc, const ContainsFunc
SkIRect dirtyRect;
if (computeDirtyRect(bounds, clipBounds, &dirtyRect)) {
const SkPaint* paint = state().getPaint(paintType, DrawShadowAndForeground, imageType);
- if (paintType == CanvasRenderingContext2DState::FillPaintType && drawCoversClipBounds(clipBounds))
+ if (paintType != CanvasRenderingContext2DState::StrokePaintType && drawCoversClipBounds(clipBounds))
checkOverdraw(bounds, paint, imageType, ClipFill);
drawFunc(paint);
didDraw(dirtyRect);
@@ -1064,8 +1005,6 @@ void CanvasRenderingContext2D::clipInternal(const Path& path, const String& wind
return;
}
- realizeSaves(c);
-
SkPath skPath = path.skPath();
skPath.setFillType(parseWinding(windingRuleString));
modifiableState().clipPath(skPath, m_clipAntialiasing);
@@ -1222,20 +1161,6 @@ void CanvasRenderingContext2D::clearRect(float x, float y, float width, float he
}
}
-void CanvasRenderingContext2D::applyShadow(ShadowMode shadowMode)
-{
- GraphicsContext* c = drawingContext();
- if (!c)
- return;
-
- if (state().shouldDrawShadows()) {
- c->setShadow(state().shadowOffset(), state().shadowBlur(), state().shadowColor(),
- DrawLooperBuilder::ShadowIgnoresTransforms, DrawLooperBuilder::ShadowRespectsAlpha, shadowMode);
- } else {
- c->clearShadow();
- }
-}
-
static inline FloatRect normalizeRect(const FloatRect& rect)
{
return FloatRect(std::min(rect.x(), rect.maxX()),
@@ -1301,45 +1226,49 @@ void CanvasRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSour
drawImage(imageSourceInternal, sx, sy, sw, sh, dx, dy, dw, dh, exceptionState);
}
-void CanvasRenderingContext2D::drawVideo(CanvasImageSource* imageSource, const FloatRect& srcRect, const FloatRect& dstRect)
+void CanvasRenderingContext2D::drawImageInternal(CanvasImageSource* imageSource, Image* image, const FloatRect& srcRect, const FloatRect& dstRect, const SkPaint* paint)
{
- HTMLVideoElement* video = static_cast<HTMLVideoElement*>(imageSource);
- ASSERT(video);
SkCanvas* c = drawingCanvas();
- if (!c)
- return;
- c->save();
- c->clipRect(WebCoreFloatRectToSKRect(dstRect));
- c->translate(dstRect.x(), dstRect.y());
- c->scale(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.height());
- c->translate(-srcRect.x(), -srcRect.y());
- video->paintCurrentFrameInContext(drawingContext(), IntRect(IntPoint(), IntSize(video->videoWidth(), video->videoHeight())));
- // In case the paint propagated a queued context loss signal
- if (drawingCanvas())
- drawingCanvas()->restore();
-}
+ ASSERT(c);
-void CanvasRenderingContext2D::drawImageOnContext(CanvasImageSource* imageSource, Image* image, const FloatRect& srcRect, const FloatRect& dstRect, const SkPaint* paint)
-{
- SkXfermode::Mode mode;
- if (!SkXfermode::AsMode(paint->getXfermode(), &mode))
- mode = SkXfermode::kSrcOver_Mode;
+ int initialSaveCount = c->getSaveCount();
+ SkPaint imagePaint = *paint;
- RefPtr<SkImageFilter> imageFilter(paint->getImageFilter());
- drawingContext()->setDropShadowImageFilter(imageFilter.release());
- RefPtr<SkDrawLooper> drawLooper(paint->getLooper());
- drawingContext()->setDrawLooper(drawLooper.release());
+ if (paint->getImageFilter()) {
+ SkMatrix ctm = c->getTotalMatrix();
+ SkMatrix invCtm;
+ if (!ctm.invert(&invCtm)) {
+ ASSERT_NOT_REACHED(); // There is an earlier check for invertibility
+ }
+ c->save();
+ c->concat(invCtm);
+ SkRect bounds = dstRect;
+ ctm.mapRect(&bounds);
+ SkRect filteredBounds;
+ paint->getImageFilter()->computeFastBounds(bounds, &filteredBounds);
Stephen White 2015/04/17 15:14:56 Nit: I realize this is just moving code from elsew
+ SkPaint layerPaint;
+ layerPaint.setXfermode(paint->getXfermode());
+ layerPaint.setImageFilter(paint->getImageFilter());
+ c->saveLayer(&filteredBounds, &layerPaint);
Stephen White 2015/04/17 15:14:56 It seems unfortunate to have to call saveLayer() y
+ c->concat(ctm);
+ imagePaint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
+ imagePaint.setImageFilter(nullptr);
+ }
if (!imageSource->isVideoElement()) {
- drawingContext()->drawImage(image, dstRect, srcRect, mode);
+ // TODO: Find a way to pass SkCanvas::kBleed_DrawBitmapRectFlag
+ image->draw(c, imagePaint, dstRect, srcRect, DoNotRespectImageOrientation);
} else {
- SkXfermode::Mode oldMode = drawingContext()->compositeOperation();
- drawingContext()->setCompositeOperation(mode);
- drawVideo(imageSource, srcRect, dstRect);
- // Must re-check drawingContext() in case drawVideo propagated a pending context loss signal
- if (drawingContext())
- drawingContext()->setCompositeOperation(oldMode);
+ c->save();
+ c->clipRect(WebCoreFloatRectToSKRect(dstRect));
+ c->translate(dstRect.x(), dstRect.y());
+ c->scale(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.height());
+ c->translate(-srcRect.x(), -srcRect.y());
+ HTMLVideoElement* video = static_cast<HTMLVideoElement*>(imageSource);
+ video->paintCurrentFrame(c, IntRect(IntPoint(), IntSize(video->videoWidth(), video->videoHeight())), &imagePaint);
}
+
+ c->restoreToCount(initialSaveCount);
}
void CanvasRenderingContext2D::drawImage(CanvasImageSource* imageSource,
@@ -1389,15 +1318,14 @@ void CanvasRenderingContext2D::drawImage(CanvasImageSource* imageSource,
draw(
[this, &imageSource, &image, &srcRect, dstRect](const SkPaint* paint) // draw lambda
{
- if (drawingCanvas())
- drawImageOnContext(imageSource, image.get(), srcRect, dstRect, paint);
+ drawImageInternal(imageSource, image.get(), srcRect, dstRect, paint);
},
[this, &dstRect](const SkIRect& clipBounds) // overdraw test lambda
{
return rectContainsTransformedRect(dstRect, clipBounds);
},
dstRect,
- CanvasRenderingContext2DState::FillPaintType,
+ CanvasRenderingContext2DState::ImagePaintType,
imageSource->isOpaque() ? CanvasRenderingContext2DState::OpaqueImage : CanvasRenderingContext2DState::NonOpaqueImage);
validateStateStack();
@@ -1535,13 +1463,6 @@ SkCanvas* CanvasRenderingContext2D::drawingCanvas() const
return canvas()->drawingCanvas();
}
-GraphicsContext* CanvasRenderingContext2D::drawingContext() const
-{
- if (isContextLost())
- return nullptr;
- return canvas()->drawingContext();
-}
-
PassRefPtrWillBeRawPtr<ImageData> CanvasRenderingContext2D::createImageData(PassRefPtrWillBeRawPtr<ImageData> imageData) const
{
return ImageData::create(imageData->size());
@@ -1719,7 +1640,6 @@ void CanvasRenderingContext2D::setFont(const String& newFont)
// The parse succeeded.
String newFontSafeCopy(newFont); // Create a string copy since newFont can be deleted inside realizeSaves.
- realizeSaves(nullptr);
modifiableState().setUnparsedFont(newFontSafeCopy);
// Map the <canvas> font into the text style. If the font uses keywords like larger/smaller, these will work
@@ -1762,7 +1682,6 @@ void CanvasRenderingContext2D::setTextAlign(const String& s)
return;
if (state().textAlign() == align)
return;
- realizeSaves(nullptr);
modifiableState().setTextAlign(align);
}
@@ -1778,7 +1697,6 @@ void CanvasRenderingContext2D::setTextBaseline(const String& s)
return;
if (state().textBaseline() == baseline)
return;
- realizeSaves(nullptr);
modifiableState().setTextBaseline(baseline);
}
@@ -1821,7 +1739,6 @@ void CanvasRenderingContext2D::setDirection(const String& directionString)
if (state().direction() == direction)
return;
- realizeSaves(nullptr);
modifiableState().setDirection(direction);
}
@@ -1995,8 +1912,6 @@ void CanvasRenderingContext2D::inflateStrokeRect(FloatRect& rect) const
const Font& CanvasRenderingContext2D::accessFont()
{
- // This needs style to be up to date, but can't assert so because drawTextInternal
- // can invalidate style before this is called (e.g. drawingContext invalidates style).
if (!state().hasRealizedFont())
setFont(state().unparsedFont());
return state().font();
@@ -2050,11 +1965,7 @@ void CanvasRenderingContext2D::setImageSmoothingEnabled(bool enabled)
if (enabled == state().imageSmoothingEnabled())
return;
- SkCanvas* c = drawingCanvas();
- realizeSaves(c);
modifiableState().setImageSmoothingEnabled(enabled);
- if (c)
- drawingContext()->setImageInterpolationQuality(enabled ? CanvasDefaultInterpolationQuality : InterpolationNone);
}
void CanvasRenderingContext2D::getContextAttributes(Canvas2DContextAttributes& attrs) const
@@ -2104,14 +2015,12 @@ bool CanvasRenderingContext2D::focusRingCallIsValid(const Path& path, Element* e
void CanvasRenderingContext2D::drawFocusRing(const Path& path)
{
- GraphicsContext* c = drawingContext();
- if (!c)
+ if (!drawingCanvas())
return;
// These should match the style defined in html.css.
Color focusRingColor = LayoutTheme::theme().focusRingColor();
const int focusRingWidth = 5;
- const int focusRingOutline = 0;
// We need to add focusRingWidth to dirtyRect.
StrokeData strokeData;
@@ -2121,14 +2030,31 @@ void CanvasRenderingContext2D::drawFocusRing(const Path& path)
if (!computeDirtyRect(path.strokeBoundingRect(strokeData), &dirtyRect))
return;
- c->setAlphaAsFloat(1.0);
- c->clearShadow();
- c->setCompositeOperation(SkXfermode::kSrcOver_Mode);
- c->drawFocusRing(path, focusRingWidth, focusRingOutline, focusRingColor);
- c->setAlphaAsFloat(state().globalAlpha());
- c->setCompositeOperation(state().globalComposite());
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setColor(focusRingColor.rgb());
+ paint.setStrokeWidth(focusRingWidth);
+
+#if OS(MACOSX)
Stephen White 2015/04/17 15:14:56 Nit: I wonder if we should keep this stuff in plat
+ paint.setAlpha(64);
+ float cornerRadius = (focusRingWidth - 1) * 0.5f;
+#else
+ const float cornerRadius = 1;
+#endif
+
+ paint.setPathEffect(SkCornerPathEffect::Create(SkFloatToScalar(cornerRadius)))->unref();
+
+ // Outer path
+ drawingCanvas()->drawPath(path.skPath(), paint);
+
+#if OS(MACOSX)
+ // Inner path
+ paint.setAlpha(128);
+ paint.setStrokeWidth(paint.getStrokeWidth() * 0.5f);
+ drawingCanvas()->drawPath(path.skPath(), paint);
+#endif
- validateStateStack();
didDraw(dirtyRect);
}

Powered by Google App Engine
This is Rietveld 408576698