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

Unified Diff: third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp

Issue 1732923002: Revert of Pull up a subset of CanvasRenderingContext2D into BaseRenderingContext2D. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 10 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: third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp
diff --git a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp
deleted file mode 100644
index 7072ec0678cc326f28819648969157fa2994574a..0000000000000000000000000000000000000000
--- a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp
+++ /dev/null
@@ -1,1366 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "modules/canvas2d/BaseRenderingContext2D.h"
-
-#include "bindings/core/v8/ExceptionMessages.h"
-#include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/ExceptionStatePlaceholder.h"
-#include "core/css/parser/CSSParser.h"
-#include "core/frame/ImageBitmap.h"
-#include "core/html/HTMLCanvasElement.h"
-#include "core/html/HTMLImageElement.h"
-#include "core/html/HTMLVideoElement.h"
-#include "core/html/ImageData.h"
-#include "modules/canvas2d/CanvasGradient.h"
-#include "modules/canvas2d/CanvasPattern.h"
-#include "modules/canvas2d/CanvasStyle.h"
-#include "modules/canvas2d/Path2D.h"
-#include "platform/geometry/FloatQuad.h"
-#include "platform/graphics/Color.h"
-#include "platform/graphics/ExpensiveCanvasHeuristicParameters.h"
-#include "platform/graphics/Image.h"
-#include "platform/graphics/ImageBuffer.h"
-#include "platform/graphics/StrokeData.h"
-#include "platform/graphics/skia/SkiaUtils.h"
-#include "third_party/skia/include/core/SkImageFilter.h"
-
-namespace blink {
-
-BaseRenderingContext2D::BaseRenderingContext2D()
- : m_clipAntialiasing(NotAntiAliased)
-{
- m_stateStack.append(CanvasRenderingContext2DState::create());
-}
-
-BaseRenderingContext2D::~BaseRenderingContext2D()
-{
-}
-
-CanvasRenderingContext2DState& BaseRenderingContext2D::modifiableState()
-{
- realizeSaves();
- return *m_stateStack.last();
-}
-
-void BaseRenderingContext2D::realizeSaves()
-{
- validateStateStack();
- if (state().hasUnrealizedSaves()) {
- ASSERT(m_stateStack.size() >= 1);
- // Reduce the current state's unrealized count by one now,
- // to reflect the fact we are saving one state.
- m_stateStack.last()->restore();
- m_stateStack.append(CanvasRenderingContext2DState::create(state(), CanvasRenderingContext2DState::DontCopyClipList));
- // Set the new state's unrealized count to 0, because it has no outstanding saves.
- // We need to do this explicitly because the copy constructor and operator= used
- // 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();
- SkCanvas* canvas = drawingCanvas();
- if (canvas)
- canvas->save();
- validateStateStack();
- }
-}
-
-void BaseRenderingContext2D::save()
-{
- m_stateStack.last()->save();
-}
-
-void BaseRenderingContext2D::restore()
-{
- validateStateStack();
- if (state().hasUnrealizedSaves()) {
- // We never realized the save, so just record that it was unnecessary.
- m_stateStack.last()->restore();
- return;
- }
- ASSERT(m_stateStack.size() >= 1);
- if (m_stateStack.size() <= 1)
- return;
- m_path.transform(state().transform());
- m_stateStack.removeLast();
- m_stateStack.last()->clearResolvedFilter();
- m_path.transform(state().transform().inverse());
- SkCanvas* c = drawingCanvas();
- if (c)
- c->restore();
-
- validateStateStack();
-}
-
-static inline void convertCanvasStyleToUnionType(CanvasStyle* style, StringOrCanvasGradientOrCanvasPattern& returnValue)
-{
- if (CanvasGradient* gradient = style->canvasGradient()) {
- returnValue.setCanvasGradient(gradient);
- return;
- }
- if (CanvasPattern* pattern = style->canvasPattern()) {
- returnValue.setCanvasPattern(pattern);
- return;
- }
- returnValue.setString(style->color());
-}
-
-void BaseRenderingContext2D::strokeStyle(StringOrCanvasGradientOrCanvasPattern& returnValue) const
-{
- convertCanvasStyleToUnionType(state().strokeStyle(), returnValue);
-}
-
-void BaseRenderingContext2D::setStrokeStyle(const StringOrCanvasGradientOrCanvasPattern& style)
-{
- ASSERT(!style.isNull());
-
- String colorString;
- CanvasStyle* canvasStyle = nullptr;
- if (style.isString()) {
- colorString = style.getAsString();
- if (colorString == state().unparsedStrokeColor())
- return;
- Color parsedColor = 0;
- if (!parseColorOrCurrentColor(parsedColor, colorString))
- return;
- if (state().strokeStyle()->isEquivalentRGBA(parsedColor.rgb())) {
- modifiableState().setUnparsedStrokeColor(colorString);
- return;
- }
- canvasStyle = CanvasStyle::createFromRGBA(parsedColor.rgb());
- } else if (style.isCanvasGradient()) {
- canvasStyle = CanvasStyle::createFromGradient(style.getAsCanvasGradient());
- } else if (style.isCanvasPattern()) {
- CanvasPattern* canvasPattern = style.getAsCanvasPattern();
-
- if (originClean() && !canvasPattern->originClean())
- setOriginTainted();
-
- canvasStyle = CanvasStyle::createFromPattern(canvasPattern);
- }
-
- ASSERT(canvasStyle);
-
- modifiableState().setStrokeStyle(canvasStyle);
- modifiableState().setUnparsedStrokeColor(colorString);
- modifiableState().clearResolvedFilter();
-}
-
-void BaseRenderingContext2D::fillStyle(StringOrCanvasGradientOrCanvasPattern& returnValue) const
-{
- convertCanvasStyleToUnionType(state().fillStyle(), returnValue);
-}
-
-void BaseRenderingContext2D::setFillStyle(const StringOrCanvasGradientOrCanvasPattern& style)
-{
- ASSERT(!style.isNull());
- validateStateStack();
- String colorString;
- CanvasStyle* canvasStyle = nullptr;
- if (style.isString()) {
- colorString = style.getAsString();
- if (colorString == state().unparsedFillColor())
- return;
- Color parsedColor = 0;
- if (!parseColorOrCurrentColor(parsedColor, colorString))
- return;
- if (state().fillStyle()->isEquivalentRGBA(parsedColor.rgb())) {
- modifiableState().setUnparsedFillColor(colorString);
- return;
- }
- canvasStyle = CanvasStyle::createFromRGBA(parsedColor.rgb());
- } else if (style.isCanvasGradient()) {
- canvasStyle = CanvasStyle::createFromGradient(style.getAsCanvasGradient());
- } else if (style.isCanvasPattern()) {
- CanvasPattern* canvasPattern = style.getAsCanvasPattern();
-
- if (originClean() && !canvasPattern->originClean())
- setOriginTainted();
- if (canvasPattern->pattern()->isTextureBacked())
- disableDeferral(DisableDeferralReasonUsingTextureBackedPattern);
- canvasStyle = CanvasStyle::createFromPattern(canvasPattern);
- }
-
- ASSERT(canvasStyle);
- modifiableState().setFillStyle(canvasStyle);
- modifiableState().setUnparsedFillColor(colorString);
- modifiableState().clearResolvedFilter();
-}
-
-double BaseRenderingContext2D::lineWidth() const
-{
- return state().lineWidth();
-}
-
-void BaseRenderingContext2D::setLineWidth(double width)
-{
- if (!std::isfinite(width) || width <= 0)
- return;
- if (state().lineWidth() == width)
- return;
- modifiableState().setLineWidth(width);
-}
-
-String BaseRenderingContext2D::lineCap() const
-{
- return lineCapName(state().lineCap());
-}
-
-void BaseRenderingContext2D::setLineCap(const String& s)
-{
- LineCap cap;
- if (!parseLineCap(s, cap))
- return;
- if (state().lineCap() == cap)
- return;
- modifiableState().setLineCap(cap);
-}
-
-String BaseRenderingContext2D::lineJoin() const
-{
- return lineJoinName(state().lineJoin());
-}
-
-void BaseRenderingContext2D::setLineJoin(const String& s)
-{
- LineJoin join;
- if (!parseLineJoin(s, join))
- return;
- if (state().lineJoin() == join)
- return;
- modifiableState().setLineJoin(join);
-}
-
-double BaseRenderingContext2D::miterLimit() const
-{
- return state().miterLimit();
-}
-
-void BaseRenderingContext2D::setMiterLimit(double limit)
-{
- if (!std::isfinite(limit) || limit <= 0)
- return;
- if (state().miterLimit() == limit)
- return;
- modifiableState().setMiterLimit(limit);
-}
-
-double BaseRenderingContext2D::shadowOffsetX() const
-{
- return state().shadowOffset().width();
-}
-
-void BaseRenderingContext2D::setShadowOffsetX(double x)
-{
- if (!std::isfinite(x))
- return;
- if (state().shadowOffset().width() == x)
- return;
- modifiableState().setShadowOffsetX(x);
-}
-
-double BaseRenderingContext2D::shadowOffsetY() const
-{
- return state().shadowOffset().height();
-}
-
-void BaseRenderingContext2D::setShadowOffsetY(double y)
-{
- if (!std::isfinite(y))
- return;
- if (state().shadowOffset().height() == y)
- return;
- modifiableState().setShadowOffsetY(y);
-}
-
-double BaseRenderingContext2D::shadowBlur() const
-{
- return state().shadowBlur();
-}
-
-void BaseRenderingContext2D::setShadowBlur(double blur)
-{
- if (!std::isfinite(blur) || blur < 0)
- return;
- if (state().shadowBlur() == blur)
- return;
- modifiableState().setShadowBlur(blur);
-}
-
-String BaseRenderingContext2D::shadowColor() const
-{
- return Color(state().shadowColor()).serialized();
-}
-
-void BaseRenderingContext2D::setShadowColor(const String& colorString)
-{
- Color color;
- if (!parseColorOrCurrentColor(color, colorString))
- return;
- if (state().shadowColor() == color)
- return;
- modifiableState().setShadowColor(color.rgb());
-}
-
-const Vector<double>& BaseRenderingContext2D::getLineDash() const
-{
- return state().lineDash();
-}
-
-static bool lineDashSequenceIsValid(const Vector<double>& dash)
-{
- for (size_t i = 0; i < dash.size(); i++) {
- if (!std::isfinite(dash[i]) || dash[i] < 0)
- return false;
- }
- return true;
-}
-
-void BaseRenderingContext2D::setLineDash(const Vector<double>& dash)
-{
- if (!lineDashSequenceIsValid(dash))
- return;
- modifiableState().setLineDash(dash);
-}
-
-double BaseRenderingContext2D::lineDashOffset() const
-{
- return state().lineDashOffset();
-}
-
-void BaseRenderingContext2D::setLineDashOffset(double offset)
-{
- if (!std::isfinite(offset) || state().lineDashOffset() == offset)
- return;
- modifiableState().setLineDashOffset(offset);
-}
-
-double BaseRenderingContext2D::globalAlpha() const
-{
- return state().globalAlpha();
-}
-
-void BaseRenderingContext2D::setGlobalAlpha(double alpha)
-{
- if (!(alpha >= 0 && alpha <= 1))
- return;
- if (state().globalAlpha() == alpha)
- return;
- modifiableState().setGlobalAlpha(alpha);
-}
-
-String BaseRenderingContext2D::globalCompositeOperation() const
-{
- return compositeOperatorName(compositeOperatorFromSkia(state().globalComposite()), blendModeFromSkia(state().globalComposite()));
-}
-
-void BaseRenderingContext2D::setGlobalCompositeOperation(const String& operation)
-{
- CompositeOperator op = CompositeSourceOver;
- WebBlendMode blendMode = WebBlendModeNormal;
- if (!parseCompositeAndBlendOperator(operation, op, blendMode))
- return;
- SkXfermode::Mode xfermode = WebCoreCompositeToSkiaComposite(op, blendMode);
- if (state().globalComposite() == xfermode)
- return;
- modifiableState().setGlobalComposite(xfermode);
-}
-
-String BaseRenderingContext2D::filter() const
-{
- return state().unparsedFilter();
-}
-
-void BaseRenderingContext2D::setFilter(const String& filterString)
-{
- if (filterString == state().unparsedFilter())
- return;
-
- RefPtrWillBeRawPtr<CSSValue> filterValue = CSSParser::parseSingleValue(CSSPropertyWebkitFilter, filterString, CSSParserContext(HTMLStandardMode, 0));
-
- if (!filterValue || filterValue->isInitialValue() || filterValue->isInheritedValue())
- return;
-
- modifiableState().setUnparsedFilter(filterString);
- modifiableState().setFilter(filterValue.release());
-}
-
-PassRefPtrWillBeRawPtr<SVGMatrixTearOff> BaseRenderingContext2D::currentTransform() const
-{
- return SVGMatrixTearOff::create(state().transform());
-}
-
-void BaseRenderingContext2D::setCurrentTransform(PassRefPtrWillBeRawPtr<SVGMatrixTearOff> passMatrixTearOff)
-{
- RefPtrWillBeRawPtr<SVGMatrixTearOff> matrixTearOff = passMatrixTearOff;
- const AffineTransform& transform = matrixTearOff->value();
- setTransform(transform.a(), transform.b(), transform.c(), transform.d(), transform.e(), transform.f());
-}
-
-void BaseRenderingContext2D::scale(double sx, double sy)
-{
- SkCanvas* c = drawingCanvas();
- if (!c)
- return;
-
- if (!std::isfinite(sx) || !std::isfinite(sy))
- return;
-
- AffineTransform newTransform = state().transform();
- newTransform.scaleNonUniform(sx, sy);
- if (state().transform() == newTransform)
- return;
-
- modifiableState().setTransform(newTransform);
- if (!state().isTransformInvertible())
- return;
-
- c->scale(sx, sy);
- m_path.transform(AffineTransform().scaleNonUniform(1.0 / sx, 1.0 / sy));
-}
-
-void BaseRenderingContext2D::rotate(double angleInRadians)
-{
- SkCanvas* c = drawingCanvas();
- if (!c)
- return;
-
- if (!std::isfinite(angleInRadians))
- return;
-
- AffineTransform newTransform = state().transform();
- newTransform.rotateRadians(angleInRadians);
- if (state().transform() == newTransform)
- return;
-
- modifiableState().setTransform(newTransform);
- if (!state().isTransformInvertible())
- return;
- c->rotate(angleInRadians * (180.0 / piFloat));
- m_path.transform(AffineTransform().rotateRadians(-angleInRadians));
-}
-
-void BaseRenderingContext2D::translate(double tx, double ty)
-{
- SkCanvas* c = drawingCanvas();
- if (!c)
- return;
- if (!state().isTransformInvertible())
- return;
-
- if (!std::isfinite(tx) || !std::isfinite(ty))
- return;
-
- AffineTransform newTransform = state().transform();
- newTransform.translate(tx, ty);
- if (state().transform() == newTransform)
- return;
-
- modifiableState().setTransform(newTransform);
- if (!state().isTransformInvertible())
- return;
- c->translate(tx, ty);
- m_path.transform(AffineTransform().translate(-tx, -ty));
-}
-
-void BaseRenderingContext2D::transform(double m11, double m12, double m21, double m22, double dx, double dy)
-{
- SkCanvas* c = drawingCanvas();
- if (!c)
- return;
-
- if (!std::isfinite(m11) || !std::isfinite(m21) || !std::isfinite(dx) || !std::isfinite(m12) || !std::isfinite(m22) || !std::isfinite(dy))
- return;
-
- AffineTransform transform(m11, m12, m21, m22, dx, dy);
- AffineTransform newTransform = state().transform() * transform;
- if (state().transform() == newTransform)
- return;
-
- modifiableState().setTransform(newTransform);
- if (!state().isTransformInvertible())
- return;
-
- c->concat(affineTransformToSkMatrix(transform));
- m_path.transform(transform.inverse());
-}
-
-void BaseRenderingContext2D::resetTransform()
-{
- SkCanvas* c = drawingCanvas();
- if (!c)
- return;
-
- AffineTransform ctm = state().transform();
- bool invertibleCTM = state().isTransformInvertible();
- // It is possible that CTM is identity while CTM is not invertible.
- // When CTM becomes non-invertible, realizeSaves() can make CTM identity.
- if (ctm.isIdentity() && invertibleCTM)
- return;
-
- // resetTransform() resolves the non-invertible CTM state.
- modifiableState().resetTransform();
- c->setMatrix(affineTransformToSkMatrix(baseTransform()));
-
- if (invertibleCTM)
- m_path.transform(ctm);
- // When else, do nothing because all transform methods didn't update m_path when CTM became non-invertible.
- // It means that resetTransform() restores m_path just before CTM became non-invertible.
-}
-
-void BaseRenderingContext2D::setTransform(double m11, double m12, double m21, double m22, double dx, double dy)
-{
- SkCanvas* c = drawingCanvas();
- if (!c)
- return;
-
- if (!std::isfinite(m11) || !std::isfinite(m21) || !std::isfinite(dx) || !std::isfinite(m12) || !std::isfinite(m22) || !std::isfinite(dy))
- return;
-
- resetTransform();
- transform(m11, m12, m21, m22, dx, dy);
-}
-
-void BaseRenderingContext2D::beginPath()
-{
- m_path.clear();
-}
-
-static bool validateRectForCanvas(double& x, double& y, double& width, double& height)
-{
- if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(width) || !std::isfinite(height))
- return false;
-
- if (!width && !height)
- return false;
-
- if (width < 0) {
- width = -width;
- x -= width;
- }
-
- if (height < 0) {
- height = -height;
- y -= height;
- }
-
- return true;
-}
-
-bool BaseRenderingContext2D::isFullCanvasCompositeMode(SkXfermode::Mode op)
-{
- // See 4.8.11.1.3 Compositing
- // CompositeSourceAtop and CompositeDestinationOut are not listed here as the platforms already
- // implement the specification's behavior.
- return op == SkXfermode::kSrcIn_Mode || op == SkXfermode::kSrcOut_Mode || op == SkXfermode::kDstIn_Mode || op == SkXfermode::kDstATop_Mode;
-}
-
-static bool isPathExpensive(const Path& path)
-{
- const SkPath& skPath = path.skPath();
- if (ExpensiveCanvasHeuristicParameters::ConcavePathsAreExpensive && !skPath.isConvex())
- return true;
-
- if (skPath.countPoints() > ExpensiveCanvasHeuristicParameters::ExpensivePathPointCount)
- return true;
-
- return false;
-}
-
-void BaseRenderingContext2D::drawPathInternal(const Path& path, CanvasRenderingContext2DState::PaintType paintType, SkPath::FillType fillType)
-{
- if (path.isEmpty())
- return;
-
- SkPath skPath = path.skPath();
- FloatRect bounds = path.boundingRect();
- skPath.setFillType(fillType);
-
- if (paintType == CanvasRenderingContext2DState::StrokePaintType)
- inflateStrokeRect(bounds);
-
- if (!drawingCanvas())
- return;
-
- if (draw(
- [&skPath, this](SkCanvas* c, const SkPaint* paint) // draw lambda
- {
- c->drawPath(skPath, *paint);
- },
- [](const SkIRect& rect) // overdraw test lambda
- {
- return false;
- }, bounds, paintType)) {
- if (isPathExpensive(path)) {
- ImageBuffer* buffer = imageBuffer();
- if (buffer)
- buffer->setHasExpensiveOp();
- }
- }
-}
-
-static SkPath::FillType parseWinding(const String& windingRuleString)
-{
- if (windingRuleString == "nonzero")
- return SkPath::kWinding_FillType;
- if (windingRuleString == "evenodd")
- return SkPath::kEvenOdd_FillType;
-
- ASSERT_NOT_REACHED();
- return SkPath::kEvenOdd_FillType;
-}
-
-void BaseRenderingContext2D::fill(const String& windingRuleString)
-{
- drawPathInternal(m_path, CanvasRenderingContext2DState::FillPaintType, parseWinding(windingRuleString));
-}
-
-void BaseRenderingContext2D::fill(Path2D* domPath, const String& windingRuleString)
-{
- drawPathInternal(domPath->path(), CanvasRenderingContext2DState::FillPaintType, parseWinding(windingRuleString));
-}
-
-void BaseRenderingContext2D::stroke()
-{
- drawPathInternal(m_path, CanvasRenderingContext2DState::StrokePaintType);
-}
-
-void BaseRenderingContext2D::stroke(Path2D* domPath)
-{
- drawPathInternal(domPath->path(), CanvasRenderingContext2DState::StrokePaintType);
-}
-
-void BaseRenderingContext2D::fillRect(double x, double y, double width, double height)
-{
- if (!validateRectForCanvas(x, y, width, height))
- return;
-
- if (!drawingCanvas())
- return;
-
- SkRect rect = SkRect::MakeXYWH(x, y, width, height);
- draw(
- [&rect, this](SkCanvas* c, const SkPaint* paint) // draw lambda
- {
- c->drawRect(rect, *paint);
- },
- [&rect, this](const SkIRect& clipBounds) // overdraw test lambda
- {
- return rectContainsTransformedRect(rect, clipBounds);
- }, rect, CanvasRenderingContext2DState::FillPaintType);
-}
-
-static void strokeRectOnCanvas(const FloatRect& rect, SkCanvas* canvas, const SkPaint* paint)
-{
- ASSERT(paint->getStyle() == SkPaint::kStroke_Style);
- if ((rect.width() > 0) != (rect.height() > 0)) {
- // When stroking, we must skip the zero-dimension segments
- SkPath path;
- path.moveTo(rect.x(), rect.y());
- path.lineTo(rect.maxX(), rect.maxY());
- path.close();
- canvas->drawPath(path, *paint);
- return;
- }
- canvas->drawRect(rect, *paint);
-}
-
-void BaseRenderingContext2D::strokeRect(double x, double y, double width, double height)
-{
- if (!validateRectForCanvas(x, y, width, height))
- return;
-
- if (!drawingCanvas())
- return;
-
- SkRect rect = SkRect::MakeXYWH(x, y, width, height);
- FloatRect bounds = rect;
- inflateStrokeRect(bounds);
- draw(
- [&rect, this](SkCanvas* c, const SkPaint* paint) // draw lambda
- {
- strokeRectOnCanvas(rect, c, paint);
- },
- [](const SkIRect& clipBounds) // overdraw test lambda
- {
- return false;
- }, bounds, CanvasRenderingContext2DState::StrokePaintType);
-}
-
-void BaseRenderingContext2D::clipInternal(const Path& path, const String& windingRuleString)
-{
- SkCanvas* c = drawingCanvas();
- if (!c) {
- return;
- }
- if (!state().isTransformInvertible()) {
- return;
- }
-
- SkPath skPath = path.skPath();
- skPath.setFillType(parseWinding(windingRuleString));
- modifiableState().clipPath(skPath, m_clipAntialiasing);
- c->clipPath(skPath, SkRegion::kIntersect_Op, m_clipAntialiasing == AntiAliased);
- if (ExpensiveCanvasHeuristicParameters::ComplexClipsAreExpensive && !skPath.isRect(0) && hasImageBuffer()) {
- imageBuffer()->setHasExpensiveOp();
- }
-}
-
-void BaseRenderingContext2D::clip(const String& windingRuleString)
-{
- clipInternal(m_path, windingRuleString);
-}
-
-void BaseRenderingContext2D::clip(Path2D* domPath, const String& windingRuleString)
-{
- clipInternal(domPath->path(), windingRuleString);
-}
-
-bool BaseRenderingContext2D::isPointInPath(const double x, const double y, const String& windingRuleString)
-{
- return isPointInPathInternal(m_path, x, y, windingRuleString);
-}
-
-bool BaseRenderingContext2D::isPointInPath(Path2D* domPath, const double x, const double y, const String& windingRuleString)
-{
- return isPointInPathInternal(domPath->path(), x, y, windingRuleString);
-}
-
-bool BaseRenderingContext2D::isPointInPathInternal(const Path& path, const double x, const double y, const String& windingRuleString)
-{
- SkCanvas* c = drawingCanvas();
- if (!c)
- return false;
- if (!state().isTransformInvertible())
- return false;
-
- FloatPoint point(x, y);
- if (!std::isfinite(point.x()) || !std::isfinite(point.y()))
- return false;
- AffineTransform ctm = state().transform();
- FloatPoint transformedPoint = ctm.inverse().mapPoint(point);
-
- return path.contains(transformedPoint, SkFillTypeToWindRule(parseWinding(windingRuleString)));
-}
-
-bool BaseRenderingContext2D::isPointInStroke(const double x, const double y)
-{
- return isPointInStrokeInternal(m_path, x, y);
-}
-
-bool BaseRenderingContext2D::isPointInStroke(Path2D* domPath, const double x, const double y)
-{
- return isPointInStrokeInternal(domPath->path(), x, y);
-}
-
-bool BaseRenderingContext2D::isPointInStrokeInternal(const Path& path, const double x, const double y)
-{
- SkCanvas* c = drawingCanvas();
- if (!c)
- return false;
- if (!state().isTransformInvertible())
- return false;
-
- FloatPoint point(x, y);
- if (!std::isfinite(point.x()) || !std::isfinite(point.y()))
- return false;
- AffineTransform ctm = state().transform();
- FloatPoint transformedPoint = ctm.inverse().mapPoint(point);
-
- StrokeData strokeData;
- strokeData.setThickness(state().lineWidth());
- strokeData.setLineCap(state().lineCap());
- strokeData.setLineJoin(state().lineJoin());
- strokeData.setMiterLimit(state().miterLimit());
- Vector<float> lineDash(state().lineDash().size());
- std::copy(state().lineDash().begin(), state().lineDash().end(), lineDash.begin());
- strokeData.setLineDash(lineDash, state().lineDashOffset());
- return path.strokeContains(transformedPoint, strokeData);
-}
-
-void BaseRenderingContext2D::clearRect(double x, double y, double width, double height)
-{
- if (!validateRectForCanvas(x, y, width, height))
- return;
-
- SkCanvas* c = drawingCanvas();
- if (!c)
- return;
- if (!state().isTransformInvertible())
- return;
-
- SkIRect clipBounds;
- if (!c->getClipDeviceBounds(&clipBounds))
- return;
-
- SkPaint clearPaint;
- clearPaint.setXfermodeMode(SkXfermode::kClear_Mode);
- clearPaint.setStyle(SkPaint::kFill_Style);
- FloatRect rect(x, y, width, height);
-
- if (rectContainsTransformedRect(rect, clipBounds)) {
- checkOverdraw(rect, &clearPaint, CanvasRenderingContext2DState::NoImage, ClipFill);
- if (drawingCanvas())
- drawingCanvas()->drawRect(rect, clearPaint);
- didDraw(clipBounds);
- } else {
- SkIRect dirtyRect;
- if (computeDirtyRect(rect, clipBounds, &dirtyRect)) {
- c->drawRect(rect, clearPaint);
- didDraw(dirtyRect);
- }
- }
-}
-
-static inline FloatRect normalizeRect(const FloatRect& rect)
-{
- return FloatRect(std::min(rect.x(), rect.maxX()),
- std::min(rect.y(), rect.maxY()),
- std::max(rect.width(), -rect.width()),
- std::max(rect.height(), -rect.height()));
-}
-
-static inline void clipRectsToImageRect(const FloatRect& imageRect, FloatRect* srcRect, FloatRect* dstRect)
-{
- if (imageRect.contains(*srcRect))
- return;
-
- // Compute the src to dst transform
- FloatSize scale(dstRect->size().width() / srcRect->size().width(), dstRect->size().height() / srcRect->size().height());
- FloatPoint scaledSrcLocation = srcRect->location();
- scaledSrcLocation.scale(scale.width(), scale.height());
- FloatSize offset = dstRect->location() - scaledSrcLocation;
-
- srcRect->intersect(imageRect);
-
- // To clip the destination rectangle in the same proportion, transform the clipped src rect
- *dstRect = *srcRect;
- dstRect->scale(scale.width(), scale.height());
- dstRect->move(offset);
-}
-
-static inline CanvasImageSource* toImageSourceInternal(const CanvasImageSourceUnion& value)
-{
- if (value.isHTMLImageElement())
- return value.getAsHTMLImageElement().get();
- if (value.isHTMLVideoElement())
- return value.getAsHTMLVideoElement().get();
- if (value.isHTMLCanvasElement())
- return value.getAsHTMLCanvasElement().get();
- if (value.isImageBitmap())
- return value.getAsImageBitmap().get();
- ASSERT_NOT_REACHED();
- return nullptr;
-}
-
-void BaseRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSource, double x, double y, ExceptionState& exceptionState)
-{
- CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource);
- FloatSize sourceRectSize = imageSourceInternal->elementSize();
- FloatSize destRectSize = imageSourceInternal->defaultDestinationSize();
- drawImage(imageSourceInternal, 0, 0, sourceRectSize.width(), sourceRectSize.height(), x, y, destRectSize.width(), destRectSize.height(), exceptionState);
-}
-
-void BaseRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSource,
- double x, double y, double width, double height, ExceptionState& exceptionState)
-{
- CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource);
- FloatSize sourceRectSize = imageSourceInternal->elementSize();
- drawImage(imageSourceInternal, 0, 0, sourceRectSize.width(), sourceRectSize.height(), x, y, width, height, exceptionState);
-}
-
-void BaseRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSource,
- double sx, double sy, double sw, double sh,
- double dx, double dy, double dw, double dh, ExceptionState& exceptionState)
-{
- CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource);
- drawImage(imageSourceInternal, sx, sy, sw, sh, dx, dy, dw, dh, exceptionState);
-}
-
-bool BaseRenderingContext2D::shouldDrawImageAntialiased(const FloatRect& destRect) const
-{
- if (!state().shouldAntialias())
- return false;
- SkCanvas* c = drawingCanvas();
- ASSERT(c);
-
- const SkMatrix &ctm = c->getTotalMatrix();
- // Don't disable anti-aliasing if we're rotated or skewed.
- if (!ctm.rectStaysRect())
- return true;
- // Check if the dimensions of the destination are "small" (less than one
- // device pixel). To prevent sudden drop-outs. Since we know that
- // kRectStaysRect_Mask is set, the matrix either has scale and no skew or
- // vice versa. We can query the kAffine_Mask flag to determine which case
- // it is.
- // FIXME: This queries the CTM while drawing, which is generally
- // discouraged. Always drawing with AA can negatively impact performance
- // though - that's why it's not always on.
- SkScalar widthExpansion, heightExpansion;
- if (ctm.getType() & SkMatrix::kAffine_Mask)
- widthExpansion = ctm[SkMatrix::kMSkewY], heightExpansion = ctm[SkMatrix::kMSkewX];
- else
- widthExpansion = ctm[SkMatrix::kMScaleX], heightExpansion = ctm[SkMatrix::kMScaleY];
- return destRect.width() * fabs(widthExpansion) < 1 || destRect.height() * fabs(heightExpansion) < 1;
-}
-
-void BaseRenderingContext2D::drawImageInternal(SkCanvas* c, CanvasImageSource* imageSource, Image* image, const FloatRect& srcRect, const FloatRect& dstRect, const SkPaint* paint)
-{
- int initialSaveCount = c->getSaveCount();
- SkPaint imagePaint = *paint;
-
- if (paint->getImageFilter()) {
- SkMatrix invCtm;
- if (!c->getTotalMatrix().invert(&invCtm)) {
- // There is an earlier check for invertibility, but the arithmetic
- // in AffineTransform is not exactly identical, so it is possible
- // for SkMatrix to find the transform to be non-invertible at this stage.
- // crbug.com/504687
- return;
- }
- SkRect bounds = dstRect;
- SkPaint layerPaint;
- layerPaint.setXfermode(paint->getXfermode());
- SkAutoTUnref<SkImageFilter> localFilter(paint->getImageFilter()->newWithLocalMatrix(invCtm));
- layerPaint.setImageFilter(localFilter);
- c->saveLayer(&bounds, &layerPaint);
- imagePaint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
- imagePaint.setImageFilter(nullptr);
- }
-
- if (!imageSource->isVideoElement()) {
- imagePaint.setAntiAlias(shouldDrawImageAntialiased(dstRect));
- image->draw(c, imagePaint, dstRect, srcRect, DoNotRespectImageOrientation, Image::DoNotClampImageToSourceRect);
- } else {
- c->save();
- c->clipRect(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);
-}
-
-bool shouldDisableDeferral(CanvasImageSource* imageSource, DisableDeferralReason* reason)
-{
- ASSERT(reason);
- ASSERT(*reason == DisableDeferralReasonUnknown);
-
- if (imageSource->isVideoElement()) {
- *reason = DisableDeferralReasonDrawImageOfVideo;
- return true;
- }
- if (imageSource->isCanvasElement()) {
- HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(imageSource);
- if (canvas->isAnimated2D()) {
- *reason = DisableDeferralReasonDrawImageOfAnimated2dCanvas;
- return true;
- }
- }
- return false;
-}
-
-void BaseRenderingContext2D::drawImage(CanvasImageSource* imageSource,
- double sx, double sy, double sw, double sh,
- double dx, double dy, double dw, double dh, ExceptionState& exceptionState)
-{
- if (!drawingCanvas())
- return;
-
- RefPtr<Image> image;
- SourceImageStatus sourceImageStatus = InvalidSourceImageStatus;
- if (!imageSource->isVideoElement()) {
- AccelerationHint hint = imageBuffer()->isAccelerated() ? PreferAcceleration : PreferNoAcceleration;
- image = imageSource->getSourceImageForCanvas(&sourceImageStatus, hint, SnapshotReasonDrawImage);
- if (sourceImageStatus == UndecodableSourceImageStatus)
- exceptionState.throwDOMException(InvalidStateError, "The HTMLImageElement provided is in the 'broken' state.");
- if (!image || !image->width() || !image->height())
- return;
- } else {
- if (!static_cast<HTMLVideoElement*>(imageSource)->hasAvailableVideoFrame())
- return;
- }
-
- if (!std::isfinite(dx) || !std::isfinite(dy) || !std::isfinite(dw) || !std::isfinite(dh)
- || !std::isfinite(sx) || !std::isfinite(sy) || !std::isfinite(sw) || !std::isfinite(sh)
- || !dw || !dh || !sw || !sh)
- return;
-
- FloatRect srcRect = normalizeRect(FloatRect(sx, sy, sw, sh));
- FloatRect dstRect = normalizeRect(FloatRect(dx, dy, dw, dh));
-
- clipRectsToImageRect(FloatRect(FloatPoint(), imageSource->elementSize()), &srcRect, &dstRect);
-
- imageSource->adjustDrawRects(&srcRect, &dstRect);
-
- if (srcRect.isEmpty())
- return;
-
- DisableDeferralReason reason = DisableDeferralReasonUnknown;
- if (shouldDisableDeferral(imageSource, &reason) || image->isTextureBacked())
- disableDeferral(reason);
-
- validateStateStack();
-
- draw(
- [this, &imageSource, &image, &srcRect, dstRect](SkCanvas* c, const SkPaint* paint) // draw lambda
- {
- drawImageInternal(c, imageSource, image.get(), srcRect, dstRect, paint);
- },
- [this, &dstRect](const SkIRect& clipBounds) // overdraw test lambda
- {
- return rectContainsTransformedRect(dstRect, clipBounds);
- }, dstRect, CanvasRenderingContext2DState::ImagePaintType,
- imageSource->isOpaque() ? CanvasRenderingContext2DState::OpaqueImage : CanvasRenderingContext2DState::NonOpaqueImage);
-
- validateStateStack();
-
- bool isExpensive = false;
-
- if (ExpensiveCanvasHeuristicParameters::SVGImageSourcesAreExpensive && imageSource->isSVGSource())
- isExpensive = true;
-
- if (imageSource->elementSize().width() * imageSource->elementSize().height() > width() * height() * ExpensiveCanvasHeuristicParameters::ExpensiveImageSizeRatio)
- isExpensive = true;
-
- if (isExpensive) {
- ImageBuffer* buffer = imageBuffer();
- if (buffer)
- buffer->setHasExpensiveOp();
- }
-
- if (imageSource->isCanvasElement() && static_cast<HTMLCanvasElement*>(imageSource)->is3D()) {
- // WebGL to 2D canvas: must flush graphics context to prevent a race
- // FIXME: crbug.com/516331 Fix the underlying synchronization issue so this flush can be eliminated.
- imageBuffer()->flushGpu(FlushReasonDrawImageOfWebGL);
- }
-
- if (originClean() && wouldTaintOrigin(imageSource))
- setOriginTainted();
-}
-
-void BaseRenderingContext2D::clearCanvas()
-{
- FloatRect canvasRect(0, 0, width(), height());
- checkOverdraw(canvasRect, 0, CanvasRenderingContext2DState::NoImage, ClipFill);
- SkCanvas* c = drawingCanvas();
- if (c)
- c->clear(hasAlpha() ? SK_ColorTRANSPARENT : SK_ColorBLACK);
-}
-
-bool BaseRenderingContext2D::rectContainsTransformedRect(const FloatRect& rect, const SkIRect& transformedRect) const
-{
- FloatQuad quad(rect);
- FloatQuad transformedQuad(FloatRect(transformedRect.x(), transformedRect.y(), transformedRect.width(), transformedRect.height()));
- return state().transform().mapQuad(quad).containsQuad(transformedQuad);
-}
-
-CanvasGradient* BaseRenderingContext2D::createLinearGradient(double x0, double y0, double x1, double y1)
-{
- CanvasGradient* gradient = CanvasGradient::create(FloatPoint(x0, y0), FloatPoint(x1, y1));
- return gradient;
-}
-
-CanvasGradient* BaseRenderingContext2D::createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1, ExceptionState& exceptionState)
-{
- if (r0 < 0 || r1 < 0) {
- exceptionState.throwDOMException(IndexSizeError, String::format("The %s provided is less than 0.", r0 < 0 ? "r0" : "r1"));
- return nullptr;
- }
-
- CanvasGradient* gradient = CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1);
- return gradient;
-}
-
-CanvasPattern* BaseRenderingContext2D::createPattern(const CanvasImageSourceUnion& imageSource, const String& repetitionType, ExceptionState& exceptionState)
-{
- Pattern::RepeatMode repeatMode = CanvasPattern::parseRepetitionType(repetitionType, exceptionState);
- if (exceptionState.hadException())
- return nullptr;
-
- SourceImageStatus status;
- CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource);
- RefPtr<Image> imageForRendering = imageSourceInternal->getSourceImageForCanvas(&status, PreferNoAcceleration, SnapshotReasonCreatePattern);
-
- switch (status) {
- case NormalSourceImageStatus:
- break;
- case ZeroSizeCanvasSourceImageStatus:
- exceptionState.throwDOMException(InvalidStateError, String::format("The canvas %s is 0.", imageSourceInternal->elementSize().width() ? "height" : "width"));
- return nullptr;
- case UndecodableSourceImageStatus:
- exceptionState.throwDOMException(InvalidStateError, "Source image is in the 'broken' state.");
- return nullptr;
- case InvalidSourceImageStatus:
- imageForRendering = Image::nullImage();
- break;
- case IncompleteSourceImageStatus:
- return nullptr;
- default:
- ASSERT_NOT_REACHED();
- return nullptr;
- }
- ASSERT(imageForRendering);
-
- bool originClean = !wouldTaintOrigin(imageSourceInternal);
-
- return CanvasPattern::create(imageForRendering.release(), repeatMode, originClean);
-}
-
-bool BaseRenderingContext2D::computeDirtyRect(const FloatRect& localRect, SkIRect* dirtyRect)
-{
- SkIRect clipBounds;
- if (!drawingCanvas()->getClipDeviceBounds(&clipBounds))
- return false;
- return computeDirtyRect(localRect, clipBounds, dirtyRect);
-}
-
-bool BaseRenderingContext2D::computeDirtyRect(const FloatRect& localRect, const SkIRect& transformedClipBounds, SkIRect* dirtyRect)
-{
- FloatRect canvasRect = state().transform().mapRect(localRect);
-
- if (alphaChannel(state().shadowColor())) {
- FloatRect shadowRect(canvasRect);
- shadowRect.move(state().shadowOffset());
- shadowRect.inflate(state().shadowBlur());
- canvasRect.unite(shadowRect);
- }
-
- SkIRect canvasIRect;
- static_cast<SkRect>(canvasRect).roundOut(&canvasIRect);
- if (!canvasIRect.intersect(transformedClipBounds))
- return false;
-
- if (dirtyRect)
- *dirtyRect = canvasIRect;
-
- return true;
-}
-
-ImageData* BaseRenderingContext2D::createImageData(ImageData* imageData) const
-{
- return ImageData::create(imageData->size());
-}
-
-ImageData* BaseRenderingContext2D::createImageData(double sw, double sh, ExceptionState& exceptionState) const
-{
- if (!sw || !sh) {
- exceptionState.throwDOMException(IndexSizeError, String::format("The source %s is 0.", sw ? "height" : "width"));
- return nullptr;
- }
-
- FloatSize logicalSize(fabs(sw), fabs(sh));
- if (!logicalSize.isExpressibleAsIntSize())
- return nullptr;
-
- IntSize size = expandedIntSize(logicalSize);
- if (size.width() < 1)
- size.setWidth(1);
- if (size.height() < 1)
- size.setHeight(1);
-
- return ImageData::create(size);
-}
-
-ImageData* BaseRenderingContext2D::getImageData(double sx, double sy, double sw, double sh, ExceptionState& exceptionState) const
-{
- if (!originClean())
- exceptionState.throwSecurityError("The canvas has been tainted by cross-origin data.");
- else if (!sw || !sh)
- exceptionState.throwDOMException(IndexSizeError, String::format("The source %s is 0.", sw ? "height" : "width"));
-
- if (exceptionState.hadException())
- return nullptr;
-
- if (sw < 0) {
- sx += sw;
- sw = -sw;
- }
- if (sh < 0) {
- sy += sh;
- sh = -sh;
- }
-
- FloatRect logicalRect(sx, sy, sw, sh);
- if (logicalRect.width() < 1)
- logicalRect.setWidth(1);
- if (logicalRect.height() < 1)
- logicalRect.setHeight(1);
- if (!logicalRect.isExpressibleAsIntRect())
- return nullptr;
-
- IntRect imageDataRect = enclosingIntRect(logicalRect);
- ImageBuffer* buffer = imageBuffer();
- if (!buffer || isContextLost())
- return ImageData::create(imageDataRect.size());
-
- WTF::ArrayBufferContents contents;
- if (!buffer->getImageData(Unmultiplied, imageDataRect, contents))
- return nullptr;
-
- RefPtr<DOMArrayBuffer> arrayBuffer = DOMArrayBuffer::create(contents);
- return ImageData::create(
- imageDataRect.size(),
- DOMUint8ClampedArray::create(arrayBuffer, 0, arrayBuffer->byteLength()));
-}
-
-void BaseRenderingContext2D::putImageData(ImageData* data, double dx, double dy, ExceptionState& exceptionState)
-{
- putImageData(data, dx, dy, 0, 0, data->width(), data->height(), exceptionState);
-}
-
-void BaseRenderingContext2D::putImageData(ImageData* data, double dx, double dy, double dirtyX, double dirtyY, double dirtyWidth, double dirtyHeight, ExceptionState& exceptionState)
-{
- if (data->data()->bufferBase()->isNeutered()) {
- exceptionState.throwDOMException(InvalidStateError, "The source data has been neutered.");
- return;
- }
- ImageBuffer* buffer = imageBuffer();
- if (!buffer)
- return;
-
- if (dirtyWidth < 0) {
- dirtyX += dirtyWidth;
- dirtyWidth = -dirtyWidth;
- }
-
- if (dirtyHeight < 0) {
- dirtyY += dirtyHeight;
- dirtyHeight = -dirtyHeight;
- }
-
- FloatRect clipRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
- clipRect.intersect(IntRect(0, 0, data->width(), data->height()));
- IntSize destOffset(static_cast<int>(dx), static_cast<int>(dy));
- IntRect destRect = enclosingIntRect(clipRect);
- destRect.move(destOffset);
- destRect.intersect(IntRect(IntPoint(), buffer->size()));
- if (destRect.isEmpty())
- return;
- IntRect sourceRect(destRect);
- sourceRect.move(-destOffset);
-
- checkOverdraw(destRect, 0, CanvasRenderingContext2DState::NoImage, UntransformedUnclippedFill);
-
- buffer->putByteArray(Unmultiplied, data->data()->data(), IntSize(data->width(), data->height()), sourceRect, IntPoint(destOffset));
-
- didDraw(destRect);
-}
-
-void BaseRenderingContext2D::inflateStrokeRect(FloatRect& rect) const
-{
- // Fast approximation of the stroke's bounding rect.
- // This yields a slightly oversized rect but is very fast
- // compared to Path::strokeBoundingRect().
- static const double root2 = sqrtf(2);
- double delta = state().lineWidth() / 2;
- if (state().lineJoin() == MiterJoin)
- delta *= state().miterLimit();
- else if (state().lineCap() == SquareCap)
- delta *= root2;
-
- rect.inflate(delta);
-}
-
-bool BaseRenderingContext2D::imageSmoothingEnabled() const
-{
- return state().imageSmoothingEnabled();
-}
-
-void BaseRenderingContext2D::setImageSmoothingEnabled(bool enabled)
-{
- if (enabled == state().imageSmoothingEnabled())
- return;
-
- modifiableState().setImageSmoothingEnabled(enabled);
-}
-
-String BaseRenderingContext2D::imageSmoothingQuality() const
-{
- return state().imageSmoothingQuality();
-}
-
-void BaseRenderingContext2D::setImageSmoothingQuality(const String& quality)
-{
- if (quality == state().imageSmoothingQuality())
- return;
-
- modifiableState().setImageSmoothingQuality(quality);
-}
-
-void BaseRenderingContext2D::checkOverdraw(const SkRect& rect, const SkPaint* paint, CanvasRenderingContext2DState::ImageType imageType, DrawType drawType)
-{
- SkCanvas* c = drawingCanvas();
- if (!c || !imageBuffer()->isRecording())
- return;
-
- SkRect deviceRect;
- if (drawType == UntransformedUnclippedFill) {
- deviceRect = rect;
- } else {
- ASSERT(drawType == ClipFill);
- if (state().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 == CanvasRenderingContext2DState::NoImage) {
- SkShader* shader = paint->getShader();
- if (shader) {
- if (shader->isOpaque() && alpha == 0xFF)
- imageBuffer()->willOverwriteCanvas();
- return;
- }
- }
- }
-
- if (isSourceOver) {
- // With source over, we need to certify that alpha == 0xFF for all pixels
- if (imageType == CanvasRenderingContext2DState::NonOpaqueImage)
- return;
- if (alpha < 0xFF)
- return;
- }
-
- imageBuffer()->willOverwriteCanvas();
-}
-
-DEFINE_TRACE(BaseRenderingContext2D)
-{
- visitor->trace(m_stateStack);
-}
-
-} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698