Chromium Code Reviews| Index: Source/core/html/canvas/CanvasRenderingContext2D.cpp |
| diff --git a/Source/core/html/canvas/CanvasRenderingContext2D.cpp b/Source/core/html/canvas/CanvasRenderingContext2D.cpp |
| index 9f3346a862e6e8964aa072a165c91ade2dd36a4f..440f70848a547f891dbe15a18935402f8d46b9b6 100644 |
| --- a/Source/core/html/canvas/CanvasRenderingContext2D.cpp |
| +++ b/Source/core/html/canvas/CanvasRenderingContext2D.cpp |
| @@ -283,6 +283,7 @@ CanvasRenderingContext2D::State::State() |
| , m_unparsedFont(defaultFont) |
| , m_realizedFont(false) |
| , m_hasClip(false) |
| + , m_hasComplexClip(false) |
| { |
| } |
| @@ -313,6 +314,7 @@ CanvasRenderingContext2D::State::State(const State& other, ClipListCopyMode mode |
| , m_font(other.m_font) |
| , m_realizedFont(other.m_realizedFont) |
| , m_hasClip(other.m_hasClip) |
| + , m_hasComplexClip(other.m_hasComplexClip) |
| { |
| if (mode == CopyClipList) { |
| m_clipList = other.m_clipList; |
| @@ -355,6 +357,7 @@ CanvasRenderingContext2D::State& CanvasRenderingContext2D::State::operator=(cons |
| m_font = other.m_font; |
| m_realizedFont = other.m_realizedFont; |
| m_hasClip = other.m_hasClip; |
| + m_hasComplexClip = other.m_hasComplexClip; |
| m_clipList = other.m_clipList; |
| if (m_realizedFont) |
| @@ -1122,7 +1125,7 @@ void CanvasRenderingContext2D::clipInternal(const Path& path, const String& wind |
| c->clipPath(skPath, SkRegion::kIntersect_Op, m_clipAntialiasing == AntiAliased); |
| if (!skPath.isRect(0)) |
| - drawingContext()->setHasComplexClip(); |
| + modifiableState().m_hasComplexClip = true; |
| modifiableState().m_hasClip = true; |
| } |
| @@ -1236,31 +1239,25 @@ void CanvasRenderingContext2D::clearRect(float x, float y, float width, float he |
| { |
| if (!validateRectForCanvas(x, y, width, height)) |
| return; |
| - GraphicsContext* context = drawingContext(); |
| - if (!context) |
| - return; |
| - if (!state().m_invertibleCTM) |
| - return; |
| - FloatRect rect(x, y, width, height); |
| - FloatRect dirtyRect; |
| - if (!computeDirtyRect(rect, &dirtyRect)) |
| + GraphicsContext* c = drawingContext(); |
| + if (!c) |
| return; |
| - context->clearShadow(); |
| - context->setAlphaAsFloat(1); |
| - context->setCompositeOperation(SkXfermode::kSrcOver_Mode); |
| + c->clearShadow(); |
| + c->setAlphaAsFloat(1); |
| + c->setCompositeOperation(SkXfermode::kClear_Mode); |
| - context->clearRect(rect); |
| - if (m_hitRegionManager) |
| - m_hitRegionManager->removeHitRegionsInRect(rect, state().m_transform); |
| + fillRect(x, y, width, height); |
| applyShadow(DrawShadowAndForeground); |
| - context->setAlphaAsFloat(state().m_globalAlpha); |
| - context->setCompositeOperation(state().m_globalComposite); |
| + c->setAlphaAsFloat(state().m_globalAlpha); |
| + c->setCompositeOperation(state().m_globalComposite); |
| - validateStateStack(); |
| - didDraw(dirtyRect); |
| + if (m_hitRegionManager) { |
| + FloatRect rect(x, y, width, height); |
| + m_hitRegionManager->removeHitRegionsInRect(rect, state().m_transform); |
|
Ken Russell (switch to Gerrit)
2015/02/11 10:11:44
Why was the check removed above of whether the sta
Justin Novosad
2015/02/11 18:59:54
Good catch, my thinking was that we already check
|
| + } |
|
dshwang
2015/02/11 08:37:52
why didDraw is removed?
Justin Novosad
2015/02/11 18:59:54
didDraw is taken care of by fillRect now. I'll add
|
| } |
| // FIXME(crbug.com/425531): Funtional.h cannot handle override function signature. |
| @@ -1297,6 +1294,7 @@ void CanvasRenderingContext2D::fillRect(float x, float y, float width, float hei |
| FloatRect rect(x, y, width, height); |
| if (rectContainsTransformedRect(rect, clipBounds)) { |
| + checkOverdraw(rect, &c->fillPaint(), NoImage, ClipFill); |
| c->fillRect(rect); |
| didDraw(clipBounds); |
| } else if (isFullCanvasCompositeMode(state().m_globalComposite)) { |
| @@ -1304,7 +1302,7 @@ void CanvasRenderingContext2D::fillRect(float x, float y, float width, float hei |
| didDraw(clipBounds); |
| } else if (state().m_globalComposite == SkXfermode::kSrc_Mode) { |
| clearCanvas(); |
| - c->clearShadow(); |
| + c->clearShadow(); // Takes care of signaling the overdraw |
| c->fillRect(rect); |
| applyShadow(DrawShadowAndForeground); |
| didDraw(clipBounds); |
| @@ -1425,7 +1423,7 @@ void CanvasRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSour |
| CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource); |
| FloatSize sourceRectSize = imageSourceInternal->sourceSize(); |
| FloatSize destRectSize = imageSourceInternal->defaultDestinationSize(); |
| - drawImageInternal(imageSourceInternal, 0, 0, sourceRectSize.width(), sourceRectSize.height(), x, y, destRectSize.width(), destRectSize.height(), exceptionState); |
| + drawImage(imageSourceInternal, 0, 0, sourceRectSize.width(), sourceRectSize.height(), x, y, destRectSize.width(), destRectSize.height(), exceptionState); |
| } |
| void CanvasRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSource, |
| @@ -1433,7 +1431,7 @@ void CanvasRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSour |
| { |
| CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource); |
| FloatSize sourceRectSize = imageSourceInternal->sourceSize(); |
| - drawImageInternal(imageSourceInternal, 0, 0, sourceRectSize.width(), sourceRectSize.height(), x, y, width, height, exceptionState); |
| + drawImage(imageSourceInternal, 0, 0, sourceRectSize.width(), sourceRectSize.height(), x, y, width, height, exceptionState); |
| } |
| void CanvasRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSource, |
| @@ -1441,7 +1439,7 @@ void CanvasRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSour |
| float dx, float dy, float dw, float dh, ExceptionState& exceptionState) |
| { |
| CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource); |
| - drawImageInternal(imageSourceInternal, sx, sy, sw, sh, dx, dy, dw, dh, exceptionState); |
| + drawImage(imageSourceInternal, sx, sy, sw, sh, dx, dy, dw, dh, exceptionState); |
| } |
| static void drawVideo(SkCanvas* c, GraphicsContext* gc, CanvasImageSource* imageSource, FloatRect srcRect, FloatRect dstRect) |
| @@ -1465,7 +1463,7 @@ static void drawImageOnContext(SkCanvas* c, GraphicsContext* gc, CanvasImageSour |
| } |
| } |
| -void CanvasRenderingContext2D::drawImageInternal(CanvasImageSource* imageSource, |
| +void CanvasRenderingContext2D::drawImage(CanvasImageSource* imageSource, |
| float sx, float sy, float sw, float sh, |
| float dx, float dy, float dw, float dh, ExceptionState& exceptionState) |
| { |
| @@ -1518,13 +1516,14 @@ void CanvasRenderingContext2D::drawImageInternal(CanvasImageSource* imageSource, |
| canvas()->buffer()->willAccessPixels(); |
| if (rectContainsTransformedRect(dstRect, clipBounds)) { |
| + checkOverdraw(dstRect, &c->fillPaint(), imageSource->isOpaque() ? OpaqueImage : NonOpaqueImage, ClipFill); |
| drawImageOnContext(drawingCanvas(), c, imageSource, image.get(), srcRect, dstRect); |
| didDraw(clipBounds); |
| } else if (isFullCanvasCompositeMode(state().m_globalComposite)) { |
| fullCanvasCompositedDraw(bind(&drawImageOnContext, drawingCanvas(), c, imageSource, image.get(), srcRect, dstRect)); |
| didDraw(clipBounds); |
| } else if (state().m_globalComposite == SkXfermode::kSrc_Mode) { |
| - clearCanvas(); |
| + clearCanvas(); // takes care of signaling an overdraw |
| drawImageOnContext(drawingCanvas(), c, imageSource, image.get(), srcRect, dstRect); |
| didDraw(clipBounds); |
| } else { |
| @@ -1551,6 +1550,7 @@ void CanvasRenderingContext2D::clearCanvas() |
| if (!c) |
| return; |
| + checkOverdraw(canvasRect, 0, NoImage, ClipFill); |
| c->clear(m_hasAlpha ? SK_ColorTRANSPARENT : SK_ColorBLACK); |
| } |
| @@ -1791,6 +1791,8 @@ void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, |
| IntRect sourceRect(destRect); |
| sourceRect.move(-destOffset); |
| + checkOverdraw(destRect, 0, NoImage, UntransformedUnclippedFill); |
| + |
| buffer->putByteArray(Unmultiplied, data->data()->data(), IntSize(data->width(), data->height()), sourceRect, IntPoint(destOffset)); |
| didDraw(destRect); |
| @@ -2382,4 +2384,71 @@ unsigned CanvasRenderingContext2D::hitRegionsCount() const |
| return 0; |
| } |
| +void CanvasRenderingContext2D::checkOverdraw(const SkRect& rect, const SkPaint* paint, ImageType imageType, DrawType drawType) |
| +{ |
| + SkCanvas* c = drawingCanvas(); |
| + if (!c || !canvas()->buffer()->isRecording()) |
|
Stephen Chennney
2015/02/11 14:33:20
There's a lot of implicit non-null here. As writte
Justin Novosad
2015/02/11 18:59:54
Those checks are taken care of in drawingCanvas().
Stephen Chennney
2015/02/11 19:29:47
OK.
|
| + return; |
| + |
| + SkRect deviceRect; |
| + if (drawType == UntransformedUnclippedFill) { |
| + deviceRect = rect; |
| + } else { |
| + ASSERT(drawType == ClipFill); |
| + if (state().m_hasComplexClip) |
| + return; |
| + |
| + SkIRect skIBounds; |
| + if (!c->getClipDeviceBounds(&skIBounds)) |
| + return; |
| + deviceRect = SkRect::Make(skIBounds); |
| + } |
| + |
| + const SkImageInfo& imageInfo = c->imageInfo(); |
| + if (!deviceRect.contains(SkRect::MakeWH(imageInfo.width(), imageInfo.height()))) |
| + return; |
| + |
| + bool isSourceOver = true; |
| + unsigned alpha = 0xFF; |
| + if (paint) { |
| + if (paint->getLooper() || paint->getImageFilter() || paint->getMaskFilter()) |
| + return; |
| + |
| + SkXfermode* xfermode = paint->getXfermode(); |
| + if (xfermode) { |
| + SkXfermode::Mode mode; |
| + if (xfermode->asMode(&mode)) { |
| + isSourceOver = mode == SkXfermode::kSrcOver_Mode; |
| + if (!isSourceOver && mode != SkXfermode::kSrc_Mode && mode != SkXfermode::kClear_Mode) |
| + return; // The code below only knows how to handle Src, SrcOver, and Clear |
| + } else { |
| + // unknown xfermode |
| + ASSERT_NOT_REACHED(); |
| + return; |
| + } |
| + } |
| + |
| + alpha = paint->getAlpha(); |
| + |
| + if (isSourceOver && imageType == NoImage) { |
| + SkShader* shader = paint->getShader(); |
| + if (shader) { |
| + if (shader->isOpaque() && alpha == 0xFF) |
| + canvas()->buffer()->willOverwriteCanvas(); |
| + return; |
| + } |
| + } |
| + } |
| + |
| + if (isSourceOver) { |
| + // With source over, we need to certify that alpha == 0xFF for all pixels |
| + if (imageType == NonOpaqueImage) |
| + return; |
| + if (alpha < 0xFF) |
| + return; |
| + } |
| + |
| + canvas()->buffer()->willOverwriteCanvas(); |
| +} |
| + |
| } // namespace blink |