提交 106b47b7 编写于 作者: A Adam Barth

Merge pull request #2305 from abarth/roll_skia

Update Skia version
......@@ -21,7 +21,7 @@ vars = {
'chromium_git': 'https://chromium.googlesource.com',
'mojo_sdk_revision': '6759b40b6f2f97b939280692070d457dfc5221b0',
'mojo_devtools_revision': '49879d78ce4486e10c2214a101d9b2e82794b2f4',
'skia_revision': '52e2581700b719aad317605160a2cef45d3db68b',
'skia_revision': '609d97918788c077514f190b0f1087ccbd420f5d',
# Note: When updating the Dart revision, ensure that all entries that are
# dependencies of dart are also updated
......
......@@ -260,8 +260,6 @@ component("skia") {
"ext/SkDiscardableMemory_chrome.cc",
"ext/SkDiscardableMemory_chrome.h",
"ext/SkMemory_new_handler.cpp",
"ext/analysis_canvas.cc",
"ext/analysis_canvas.h",
"ext/bitmap_platform_device.h",
"ext/convolver.cc",
"ext/convolver.h",
......@@ -319,29 +317,11 @@ component("skia") {
# Remove unused util files include in utils.gypi
sources -= [
"//third_party/skia/include/utils/SkBoundaryPatch.h",
"//third_party/skia/include/utils/SkCamera.h",
"//third_party/skia/include/utils/SkCanvasStateUtils.h",
"//third_party/skia/include/utils/SkCubicInterval.h",
"//third_party/skia/include/utils/SkCullPoints.h",
"//third_party/skia/include/utils/SkDebugUtils.h",
"//third_party/skia/include/utils/SkDumpCanvas.h",
"//third_party/skia/include/utils/SkEventTracer.h",
"//third_party/skia/include/utils/SkFrontBufferedStream.h",
"//third_party/skia/include/utils/SkInterpolator.h",
"//third_party/skia/include/utils/SkLayer.h",
"//third_party/skia/include/utils/SkMeshUtils.h",
"//third_party/skia/include/utils/SkNinePatch.h",
"//third_party/skia/include/utils/SkParsePaint.h",
"//third_party/skia/include/utils/SkParsePath.h",
"//third_party/skia/include/utils/SkRandom.h",
"//third_party/skia/src/utils/SkBitmapHasher.cpp",
"//third_party/skia/src/utils/SkBitmapHasher.h",
"//third_party/skia/src/utils/SkBoundaryPatch.cpp",
"//third_party/skia/src/utils/SkCamera.cpp",
"//third_party/skia/src/utils/SkCanvasStack.h",
"//third_party/skia/src/utils/SkCubicInterval.cpp",
"//third_party/skia/src/utils/SkCullPoints.cpp",
"//third_party/skia/src/utils/SkDumpCanvas.cpp",
"//third_party/skia/src/utils/SkFloatUtils.h",
"//third_party/skia/src/utils/SkFrontBufferedStream.cpp",
......@@ -627,7 +607,6 @@ source_set("skia_opts") {
test("skia_unittests") {
sources = [
"ext/analysis_canvas_unittest.cc",
"ext/bitmap_platform_device_mac_unittest.cc",
"ext/convolver_unittest.cc",
"ext/image_operations_unittest.cc",
......
// Copyright (c) 2013 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 "base/logging.h"
#include "base/trace_event/trace_event.h"
#include "skia/ext/analysis_canvas.h"
#include "third_party/skia/include/core/SkDraw.h"
#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkRRect.h"
#include "third_party/skia/include/core/SkShader.h"
#include "third_party/skia/src/core/SkRasterClip.h"
namespace {
const int kNoLayer = -1;
bool ActsLikeClear(SkXfermode::Mode mode, unsigned src_alpha) {
switch (mode) {
case SkXfermode::kClear_Mode:
return true;
case SkXfermode::kSrc_Mode:
case SkXfermode::kSrcIn_Mode:
case SkXfermode::kDstIn_Mode:
case SkXfermode::kSrcOut_Mode:
case SkXfermode::kDstATop_Mode:
return src_alpha == 0;
case SkXfermode::kDstOut_Mode:
return src_alpha == 0xFF;
default:
return false;
}
}
bool IsSolidColorPaint(const SkPaint& paint) {
SkXfermode::Mode xfermode;
// getXfermode can return a NULL, but that is handled
// gracefully by AsMode (NULL turns into kSrcOver mode).
SkXfermode::AsMode(paint.getXfermode(), &xfermode);
// Paint is solid color if the following holds:
// - Alpha is 1.0, style is fill, and there are no special effects
// - Xfer mode is either kSrc or kSrcOver (kSrcOver is equivalent
// to kSrc if source alpha is 1.0, which is already checked).
return (paint.getAlpha() == 255 &&
!paint.getShader() &&
!paint.getLooper() &&
!paint.getMaskFilter() &&
!paint.getColorFilter() &&
!paint.getImageFilter() &&
paint.getStyle() == SkPaint::kFill_Style &&
(xfermode == SkXfermode::kSrc_Mode ||
xfermode == SkXfermode::kSrcOver_Mode));
}
// Returns true if the specified drawn_rect will cover the entire canvas, and
// that the canvas is not clipped (i.e. it covers ALL of the canvas).
bool IsFullQuad(SkCanvas* canvas, const SkRect& drawn_rect) {
if (!canvas->isClipRect())
return false;
SkIRect clip_irect;
canvas->getClipDeviceBounds(&clip_irect);
// if the clip is smaller than the canvas, we're partly clipped, so abort.
if (!clip_irect.contains(SkIRect::MakeSize(canvas->getDeviceSize())))
return false;
const SkMatrix& matrix = canvas->getTotalMatrix();
// If the transform results in a non-axis aligned
// rect, then be conservative and return false.
if (!matrix.rectStaysRect())
return false;
SkRect device_rect;
matrix.mapRect(&device_rect, drawn_rect);
SkRect clip_rect;
clip_rect.set(clip_irect);
return device_rect.contains(clip_rect);
}
} // namespace
namespace skia {
void AnalysisCanvas::SetForceNotSolid(bool flag) {
is_forced_not_solid_ = flag;
if (is_forced_not_solid_)
is_solid_color_ = false;
}
void AnalysisCanvas::SetForceNotTransparent(bool flag) {
is_forced_not_transparent_ = flag;
if (is_forced_not_transparent_)
is_transparent_ = false;
}
void AnalysisCanvas::onDrawPaint(const SkPaint& paint) {
SkRect rect;
getClipBounds(&rect);
drawRect(rect, paint);
}
void AnalysisCanvas::onDrawPoints(SkCanvas::PointMode mode,
size_t count,
const SkPoint points[],
const SkPaint& paint) {
is_solid_color_ = false;
is_transparent_ = false;
++draw_op_count_;
}
void AnalysisCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
// This recreates the early-exit logic in SkCanvas.cpp.
SkRect scratch;
if (paint.canComputeFastBounds() &&
quickReject(paint.computeFastBounds(rect, &scratch))) {
return;
}
// An extra no-op check SkCanvas.cpp doesn't do.
if (paint.nothingToDraw())
return;
bool does_cover_canvas = IsFullQuad(this, rect);
SkXfermode::Mode xfermode;
SkXfermode::AsMode(paint.getXfermode(), &xfermode);
// This canvas will become transparent if the following holds:
// - The quad is a full tile quad
// - We're not in "forced not transparent" mode
// - Transfer mode is clear (0 color, 0 alpha)
//
// If the paint alpha is not 0, or if the transfrer mode is
// not src, then this canvas will not be transparent.
//
// In all other cases, we keep the current transparent value
if (does_cover_canvas &&
!is_forced_not_transparent_ &&
ActsLikeClear(xfermode, paint.getAlpha())) {
is_transparent_ = true;
} else if (paint.getAlpha() != 0 || xfermode != SkXfermode::kSrc_Mode) {
is_transparent_ = false;
}
// This bitmap is solid if and only if the following holds.
// Note that this might be overly conservative:
// - We're not in "forced not solid" mode
// - Paint is solid color
// - The quad is a full tile quad
if (!is_forced_not_solid_ && IsSolidColorPaint(paint) && does_cover_canvas) {
is_solid_color_ = true;
color_ = paint.getColor();
} else {
is_solid_color_ = false;
}
++draw_op_count_;
}
void AnalysisCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
is_solid_color_ = false;
is_transparent_ = false;
++draw_op_count_;
}
void AnalysisCanvas::onDrawRRect(const SkRRect& rr, const SkPaint& paint) {
// This should add the SkRRect to an SkPath, and call
// drawPath, but since drawPath ignores the SkPath, just
// do the same work here.
is_solid_color_ = false;
is_transparent_ = false;
++draw_op_count_;
}
void AnalysisCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
is_solid_color_ = false;
is_transparent_ = false;
++draw_op_count_;
}
void AnalysisCanvas::onDrawBitmap(const SkBitmap& bitmap,
SkScalar left,
SkScalar top,
const SkPaint*) {
is_solid_color_ = false;
is_transparent_ = false;
++draw_op_count_;
}
void AnalysisCanvas::onDrawBitmapRect(const SkBitmap&,
const SkRect* src,
const SkRect& dst,
const SkPaint* paint,
SrcRectConstraint flags) {
// Call drawRect to determine transparency,
// but reset solid color to false.
SkPaint tmpPaint;
if (!paint)
paint = &tmpPaint;
drawRect(dst, *paint);
is_solid_color_ = false;
++draw_op_count_;
}
void AnalysisCanvas::onDrawBitmapNine(const SkBitmap& bitmap,
const SkIRect& center,
const SkRect& dst,
const SkPaint* paint) {
is_solid_color_ = false;
is_transparent_ = false;
++draw_op_count_;
}
void AnalysisCanvas::onDrawSprite(const SkBitmap& bitmap,
int left,
int top,
const SkPaint* paint) {
is_solid_color_ = false;
is_transparent_ = false;
++draw_op_count_;
}
void AnalysisCanvas::onDrawText(const void* text,
size_t len,
SkScalar x,
SkScalar y,
const SkPaint& paint) {
is_solid_color_ = false;
is_transparent_ = false;
++draw_op_count_;
}
void AnalysisCanvas::onDrawPosText(const void* text,
size_t byteLength,
const SkPoint pos[],
const SkPaint& paint) {
is_solid_color_ = false;
is_transparent_ = false;
++draw_op_count_;
}
void AnalysisCanvas::onDrawPosTextH(const void* text,
size_t byteLength,
const SkScalar xpos[],
SkScalar constY,
const SkPaint& paint) {
is_solid_color_ = false;
is_transparent_ = false;
++draw_op_count_;
}
void AnalysisCanvas::onDrawTextOnPath(const void* text,
size_t len,
const SkPath& path,
const SkMatrix* matrix,
const SkPaint& paint) {
is_solid_color_ = false;
is_transparent_ = false;
++draw_op_count_;
}
void AnalysisCanvas::onDrawTextBlob(const SkTextBlob* blob,
SkScalar x,
SkScalar y,
const SkPaint &paint) {
is_solid_color_ = false;
is_transparent_ = false;
++draw_op_count_;
}
void AnalysisCanvas::onDrawDRRect(const SkRRect& outer,
const SkRRect& inner,
const SkPaint& paint) {
is_solid_color_ = false;
is_transparent_ = false;
++draw_op_count_;
}
void AnalysisCanvas::onDrawVertices(SkCanvas::VertexMode,
int vertex_count,
const SkPoint verts[],
const SkPoint texs[],
const SkColor colors[],
SkXfermode* xmode,
const uint16_t indices[],
int index_count,
const SkPaint& paint) {
is_solid_color_ = false;
is_transparent_ = false;
++draw_op_count_;
}
// Needed for now, since SkCanvas requires a bitmap, even if it is not backed
// by any pixels
static SkBitmap MakeEmptyBitmap(int width, int height) {
SkBitmap bitmap;
bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
return bitmap;
}
AnalysisCanvas::AnalysisCanvas(int width, int height)
: INHERITED(MakeEmptyBitmap(width, height)),
saved_stack_size_(0),
force_not_solid_stack_level_(kNoLayer),
force_not_transparent_stack_level_(kNoLayer),
is_forced_not_solid_(false),
is_forced_not_transparent_(false),
is_solid_color_(true),
color_(SK_ColorTRANSPARENT),
is_transparent_(true),
draw_op_count_(0) {
}
AnalysisCanvas::~AnalysisCanvas() {}
bool AnalysisCanvas::GetColorIfSolid(SkColor* color) const {
if (is_transparent_) {
*color = SK_ColorTRANSPARENT;
return true;
}
if (is_solid_color_) {
*color = color_;
return true;
}
return false;
}
bool AnalysisCanvas::abort() {
// Early out as soon as we have more than one draw op.
// TODO(vmpstr): Investigate if 1 is the correct metric here. We need to
// balance the amount of time we spend analyzing vs how many tiles would be
// solid if the number was higher.
if (draw_op_count_ > 1) {
// We have to reset solid/transparent state to false since we don't
// know whether consequent operations will make this false.
is_solid_color_ = false;
is_transparent_ = false;
return true;
}
return false;
}
void AnalysisCanvas::OnComplexClip() {
// complex clips can make our calls to IsFullQuad invalid (ie have false
// positives). As a precaution, force the setting to be non-solid
// and non-transparent until we pop this
if (force_not_solid_stack_level_ == kNoLayer) {
force_not_solid_stack_level_ = saved_stack_size_;
SetForceNotSolid(true);
}
if (force_not_transparent_stack_level_ == kNoLayer) {
force_not_transparent_stack_level_ = saved_stack_size_;
SetForceNotTransparent(true);
}
}
void AnalysisCanvas::onClipRect(const SkRect& rect,
SkRegion::Op op,
ClipEdgeStyle edge_style) {
INHERITED::onClipRect(rect, op, edge_style);
}
void AnalysisCanvas::onClipPath(const SkPath& path,
SkRegion::Op op,
ClipEdgeStyle edge_style) {
OnComplexClip();
INHERITED::onClipRect(path.getBounds(), op, edge_style);
}
void AnalysisCanvas::onClipRRect(const SkRRect& rrect,
SkRegion::Op op,
ClipEdgeStyle edge_style) {
OnComplexClip();
INHERITED::onClipRect(rrect.getBounds(), op, edge_style);
}
void AnalysisCanvas::onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) {
const ClipEdgeStyle edge_style = kHard_ClipEdgeStyle;
if (deviceRgn.isRect()) {
onClipRect(SkRect::MakeFromIRect(deviceRgn.getBounds()), op, edge_style);
return;
}
OnComplexClip();
INHERITED::onClipRect(
SkRect::MakeFromIRect(deviceRgn.getBounds()), op, edge_style);
}
void AnalysisCanvas::willSave() {
++saved_stack_size_;
INHERITED::willSave();
}
SkCanvas::SaveLayerStrategy AnalysisCanvas::willSaveLayer(
const SkRect* bounds,
const SkPaint* paint,
SkCanvas::SaveFlags flags) {
++saved_stack_size_;
SkIRect canvas_ibounds = SkIRect::MakeSize(this->getDeviceSize());
SkRect canvas_bounds;
canvas_bounds.set(canvas_ibounds);
// If after we draw to the saved layer, we have to blend with the current
// layer, then we can conservatively say that the canvas will not be of
// solid color.
if ((paint && !IsSolidColorPaint(*paint)) ||
(bounds && !bounds->contains(canvas_bounds))) {
if (force_not_solid_stack_level_ == kNoLayer) {
force_not_solid_stack_level_ = saved_stack_size_;
SetForceNotSolid(true);
}
}
// If after we draw to the save layer, we have to blend with the current
// layer using any part of the current layer's alpha, then we can
// conservatively say that the canvas will not be transparent.
SkXfermode::Mode xfermode = SkXfermode::kSrc_Mode;
if (paint)
SkXfermode::AsMode(paint->getXfermode(), &xfermode);
if (xfermode != SkXfermode::kDst_Mode) {
if (force_not_transparent_stack_level_ == kNoLayer) {
force_not_transparent_stack_level_ = saved_stack_size_;
SetForceNotTransparent(true);
}
}
INHERITED::willSaveLayer(bounds, paint, flags);
// Actually saving a layer here could cause a new bitmap to be created
// and real rendering to occur.
return kNoLayer_SaveLayerStrategy;
}
void AnalysisCanvas::willRestore() {
DCHECK(saved_stack_size_);
if (saved_stack_size_) {
--saved_stack_size_;
if (saved_stack_size_ < force_not_solid_stack_level_) {
SetForceNotSolid(false);
force_not_solid_stack_level_ = kNoLayer;
}
if (saved_stack_size_ < force_not_transparent_stack_level_) {
SetForceNotTransparent(false);
force_not_transparent_stack_level_ = kNoLayer;
}
}
INHERITED::willRestore();
}
} // namespace skia
// Copyright (c) 2013 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.
#ifndef SKIA_EXT_ANALYSIS_CANVAS_H_
#define SKIA_EXT_ANALYSIS_CANVAS_H_
#include "base/compiler_specific.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPicture.h"
namespace skia {
// Does not render anything, but gathers statistics about a region
// (specified as a clip rectangle) of an SkPicture as the picture is
// played back through it.
// To use: play a picture into the canvas, and then check result.
class SK_API AnalysisCanvas : public SkCanvas,
public SkPicture::AbortCallback {
public:
AnalysisCanvas(int width, int height);
~AnalysisCanvas() override;
// Returns true when a SkColor can be used to represent result.
bool GetColorIfSolid(SkColor* color) const;
void SetForceNotSolid(bool flag);
void SetForceNotTransparent(bool flag);
// SkPicture::AbortCallback override.
bool abort() override;
// SkCanvas overrides.
void onDrawPaint(const SkPaint& paint) override;
void onDrawPoints(PointMode,
size_t count,
const SkPoint pts[],
const SkPaint&) override;
void onDrawOval(const SkRect&, const SkPaint&) override;
void onDrawRect(const SkRect&, const SkPaint&) override;
void onDrawRRect(const SkRRect&, const SkPaint&) override;
void onDrawPath(const SkPath& path, const SkPaint&) override;
void onDrawBitmap(const SkBitmap&,
SkScalar left,
SkScalar top,
const SkPaint* paint = NULL) override;
void onDrawBitmapRect(const SkBitmap&,
const SkRect* src,
const SkRect& dst,
const SkPaint* paint,
SrcRectConstraint flags) override;
void onDrawBitmapNine(const SkBitmap& bitmap,
const SkIRect& center,
const SkRect& dst,
const SkPaint* paint = NULL) override;
void onDrawSprite(const SkBitmap&,
int left,
int top,
const SkPaint* paint = NULL) override;
void onDrawVertices(VertexMode,
int vertexCount,
const SkPoint vertices[],
const SkPoint texs[],
const SkColor colors[],
SkXfermode*,
const uint16_t indices[],
int indexCount,
const SkPaint&) override;
protected:
void willSave() override;
SaveLayerStrategy willSaveLayer(const SkRect*,
const SkPaint*,
SaveFlags) override;
void willRestore() override;
void onClipRect(const SkRect& rect,
SkRegion::Op op,
ClipEdgeStyle edge_style) override;
void onClipRRect(const SkRRect& rrect,
SkRegion::Op op,
ClipEdgeStyle edge_style) override;
void onClipPath(const SkPath& path,
SkRegion::Op op,
ClipEdgeStyle edge_style) override;
void onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) override;
void onDrawText(const void* text,
size_t byteLength,
SkScalar x,
SkScalar y,
const SkPaint&) override;
void onDrawPosText(const void* text,
size_t byteLength,
const SkPoint pos[],
const SkPaint&) override;
void onDrawPosTextH(const void* text,
size_t byteLength,
const SkScalar xpos[],
SkScalar constY,
const SkPaint&) override;
void onDrawTextOnPath(const void* text,
size_t byteLength,
const SkPath& path,
const SkMatrix* matrix,
const SkPaint&) override;
void onDrawTextBlob(const SkTextBlob* blob,
SkScalar x,
SkScalar y,
const SkPaint& paint) override;
void onDrawDRRect(const SkRRect& outer,
const SkRRect& inner,
const SkPaint&) override;
void OnComplexClip();
private:
typedef SkCanvas INHERITED;
int saved_stack_size_;
int force_not_solid_stack_level_;
int force_not_transparent_stack_level_;
bool is_forced_not_solid_;
bool is_forced_not_transparent_;
bool is_solid_color_;
SkColor color_;
bool is_transparent_;
int draw_op_count_;
};
} // namespace skia
#endif // SKIA_EXT_ANALYSIS_CANVAS_H_
// Copyright 2013 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 "base/compiler_specific.h"
#include "skia/ext/analysis_canvas.h"
#include "skia/ext/refptr.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkShader.h"
#include "third_party/skia/include/effects/SkOffsetImageFilter.h"
namespace {
void SolidColorFill(skia::AnalysisCanvas& canvas) {
canvas.clear(SkColorSetARGB(255, 255, 255, 255));
}
void TransparentFill(skia::AnalysisCanvas& canvas) {
canvas.clear(SkColorSetARGB(0, 0, 0, 0));
}
} // namespace
namespace skia {
TEST(AnalysisCanvasTest, EmptyCanvas) {
skia::AnalysisCanvas canvas(255, 255);
SkColor color;
EXPECT_TRUE(canvas.GetColorIfSolid(&color));
EXPECT_EQ(color, SkColorSetARGB(0, 0, 0, 0));
}
TEST(AnalysisCanvasTest, ClearCanvas) {
skia::AnalysisCanvas canvas(255, 255);
// Transparent color
SkColor color = SkColorSetARGB(0, 12, 34, 56);
canvas.clear(color);
SkColor outputColor;
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
// Solid color
color = SkColorSetARGB(255, 65, 43, 21);
canvas.clear(color);
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
EXPECT_EQ(outputColor, color);
// Translucent color
color = SkColorSetARGB(128, 11, 22, 33);
canvas.clear(color);
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
// Test helper methods
SolidColorFill(canvas);
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
TransparentFill(canvas);
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
}
TEST(AnalysisCanvasTest, ComplexActions) {
skia::AnalysisCanvas canvas(255, 255);
// Draw paint test.
SkColor color = SkColorSetARGB(255, 11, 22, 33);
SkPaint paint;
paint.setColor(color);
canvas.drawPaint(paint);
SkColor outputColor;
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
// Draw points test.
SkPoint points[4] = {
SkPoint::Make(0, 0),
SkPoint::Make(255, 0),
SkPoint::Make(255, 255),
SkPoint::Make(0, 255)
};
SolidColorFill(canvas);
canvas.drawPoints(SkCanvas::kLines_PointMode, 4, points, paint);
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
// Draw oval test.
SolidColorFill(canvas);
canvas.drawOval(SkRect::MakeWH(255, 255), paint);
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
// Draw bitmap test.
SolidColorFill(canvas);
SkBitmap secondBitmap;
secondBitmap.allocN32Pixels(255, 255);
canvas.drawBitmap(secondBitmap, 0, 0);
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
}
TEST(AnalysisCanvasTest, SimpleDrawRect) {
skia::AnalysisCanvas canvas(255, 255);
SkColor color = SkColorSetARGB(255, 11, 22, 33);
SkPaint paint;
paint.setColor(color);
canvas.clipRect(SkRect::MakeWH(255, 255));
canvas.drawRect(SkRect::MakeWH(255, 255), paint);
SkColor outputColor;
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
EXPECT_EQ(color, outputColor);
color = SkColorSetARGB(255, 22, 33, 44);
paint.setColor(color);
canvas.translate(-128, -128);
canvas.drawRect(SkRect::MakeWH(382, 382), paint);
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
color = SkColorSetARGB(255, 33, 44, 55);
paint.setColor(color);
canvas.drawRect(SkRect::MakeWH(383, 383), paint);
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
EXPECT_EQ(color, outputColor);
color = SkColorSetARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRect(SkRect::MakeWH(383, 383), paint);
// This test relies on canvas treating a paint with 0-color as a no-op
// thus not changing its "is_solid" status.
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
EXPECT_EQ(outputColor, SkColorSetARGB(255, 33, 44, 55));
color = SkColorSetARGB(128, 128, 128, 128);
paint.setColor(color);
canvas.drawRect(SkRect::MakeWH(383, 383), paint);
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
paint.setXfermodeMode(SkXfermode::kClear_Mode);
canvas.drawRect(SkRect::MakeWH(382, 382), paint);
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
canvas.drawRect(SkRect::MakeWH(383, 383), paint);
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
canvas.translate(128, 128);
color = SkColorSetARGB(255, 11, 22, 33);
paint.setColor(color);
paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
canvas.drawRect(SkRect::MakeWH(255, 255), paint);
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
EXPECT_EQ(color, outputColor);
canvas.rotate(50);
canvas.drawRect(SkRect::MakeWH(255, 255), paint);
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
}
TEST(AnalysisCanvasTest, FilterPaint) {
skia::AnalysisCanvas canvas(255, 255);
SkPaint paint;
skia::RefPtr<SkImageFilter> filter = skia::AdoptRef(SkOffsetImageFilter::Create(10, 10));
paint.setImageFilter(filter.get());
canvas.drawRect(SkRect::MakeWH(255, 255), paint);
SkColor outputColor;
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
}
TEST(AnalysisCanvasTest, ClipPath) {
skia::AnalysisCanvas canvas(255, 255);
// Skia will look for paths that are actually rects and treat
// them as such. We add a divot to the following path to prevent
// this optimization and truly test clipPath's behavior.
SkPath path;
path.moveTo(0, 0);
path.lineTo(128, 50);
path.lineTo(255, 0);
path.lineTo(255, 255);
path.lineTo(0, 255);
SkColor outputColor;
SolidColorFill(canvas);
canvas.clipPath(path);
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
canvas.save();
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
canvas.clipPath(path);
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
canvas.restore();
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
SolidColorFill(canvas);
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
}
TEST(AnalysisCanvasTest, SaveLayerWithXfermode) {
skia::AnalysisCanvas canvas(255, 255);
SkRect bounds = SkRect::MakeWH(255, 255);
SkColor outputColor;
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
SkPaint paint;
// Note: nothing is draw to the the save layer, but solid color
// and transparency are handled conservatively in case the layer's
// SkPaint draws something. For example, there could be an
// SkPictureImageFilter. If someday analysis_canvas starts doing
// a deeper analysis of the SkPaint, this test may need to be
// redesigned.
TransparentFill(canvas);
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
canvas.saveLayer(&bounds, &paint);
canvas.restore();
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
TransparentFill(canvas);
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
canvas.saveLayer(&bounds, &paint);
canvas.restore();
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
// Layer with dst xfermode is a no-op, so this is the only case
// where solid color is unaffected by the layer.
TransparentFill(canvas);
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
paint.setXfermodeMode(SkXfermode::kDst_Mode);
canvas.saveLayer(&bounds, &paint);
canvas.restore();
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
}
TEST(AnalysisCanvasTest, SaveLayerRestore) {
skia::AnalysisCanvas canvas(255, 255);
SkColor outputColor;
SolidColorFill(canvas);
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
SkRect bounds = SkRect::MakeWH(255, 255);
SkPaint paint;
paint.setColor(SkColorSetARGB(255, 255, 255, 255));
paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
// This should force non-transparency
canvas.saveLayer(&bounds, &paint);
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
TransparentFill(canvas);
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
SolidColorFill(canvas);
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
paint.setXfermodeMode(SkXfermode::kDst_Mode);
// This should force non-solid color
canvas.saveLayer(&bounds, &paint);
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
TransparentFill(canvas);
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
SolidColorFill(canvas);
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
canvas.restore();
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
TransparentFill(canvas);
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
SolidColorFill(canvas);
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
canvas.restore();
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
TransparentFill(canvas);
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
SolidColorFill(canvas);
EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
}
TEST(AnalysisCanvasTest, EarlyOutNotSolid) {
SkRTreeFactory factory;
SkPictureRecorder recorder;
// Create a picture with 3 commands, last of which is non-solid.
skia::RefPtr<SkCanvas> record_canvas =
skia::SharePtr(recorder.beginRecording(256, 256, &factory));
std::string text = "text";
SkPoint point = SkPoint::Make(SkIntToScalar(25), SkIntToScalar(25));
SkPaint paint;
paint.setColor(SkColorSetARGB(255, 255, 255, 255));
paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
record_canvas->drawRect(SkRect::MakeWH(256, 256), paint);
record_canvas->drawRect(SkRect::MakeWH(256, 256), paint);
record_canvas->drawText(
text.c_str(), text.length(), point.fX, point.fY, paint);
skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording());
// Draw the picture into the analysis canvas, using the canvas as a callback
// as well.
skia::AnalysisCanvas canvas(256, 256);
picture->playback(&canvas, &canvas);
// Ensure that canvas is not solid.
SkColor output_color;
EXPECT_FALSE(canvas.GetColorIfSolid(&output_color));
// Verify that we aborted drawing.
EXPECT_TRUE(canvas.abortDrawing());
}
TEST(AnalysisCanvasTest, ClipComplexRegion) {
skia::AnalysisCanvas canvas(255, 255);
SkPath path;
path.moveTo(0, 0);
path.lineTo(128, 50);
path.lineTo(255, 0);
path.lineTo(255, 255);
path.lineTo(0, 255);
SkIRect pathBounds = path.getBounds().round();
SkRegion region;
region.setPath(path, SkRegion(pathBounds));
SkColor outputColor;
SolidColorFill(canvas);
canvas.clipRegion(region);
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
canvas.save();
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
canvas.clipRegion(region);
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
canvas.restore();
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
SolidColorFill(canvas);
EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
}
} // namespace skia
# Copyright (c) 2012 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.
{
'conditions': [
# In component mode (shared_lib), we build all of skia as a single DLL.
# However, in the static mode, we need to build skia as multiple targets
# in order to support the use case where a platform (e.g. Android) may
# already have a copy of skia as a system library.
['component=="static_library"', {
'targets': [
{
'target_name': 'skia_library',
'type': 'static_library',
'includes': [
'skia_library.gypi',
'skia_common.gypi',
'../build/android/increase_size_for_speed.gypi',
# Disable LTO due to compiler error
# in mems_in_disjoint_alias_sets_p, at alias.c:393
# crbug.com/422255
'../build/android/disable_lto.gypi',
],
},
],
}],
['component=="static_library"', {
'targets': [
{
'target_name': 'skia',
'type': 'none',
'dependencies': [
'skia_library',
'skia_chrome',
],
'export_dependent_settings': [
'skia_library',
'skia_chrome',
],
},
{
'target_name': 'skia_chrome',
'type': 'static_library',
'includes': [
'skia_chrome.gypi',
'skia_common.gypi',
'../build/android/increase_size_for_speed.gypi',
],
},
],
},
{ # component != static_library
'targets': [
{
'target_name': 'skia',
'type': 'shared_library',
'includes': [
'skia_library.gypi',
'skia_chrome.gypi',
'skia_common.gypi',
'../build/android/increase_size_for_speed.gypi',
],
'defines': [
'SKIA_DLL',
'SKIA_IMPLEMENTATION=1',
'GR_GL_IGNORE_ES3_MSAA=0',
],
'direct_dependent_settings': {
'defines': [
'SKIA_DLL',
'GR_GL_IGNORE_ES3_MSAA=0',
],
},
},
{
'target_name': 'skia_library',
'type': 'none',
},
{
'target_name': 'skia_chrome',
'type': 'none',
},
],
}],
],
# targets that are not dependent upon the component type
'targets': [
{
'target_name': 'skia_chrome_opts',
'type': 'static_library',
'include_dirs': [
'..',
'config',
'../third_party/skia/include/core',
],
'conditions': [
[ 'os_posix == 1 and OS != "mac" and OS != "android" and \
target_arch != "arm" and target_arch != "mipsel" and \
target_arch != "arm64" and target_arch != "mips64el"', {
'cflags': [
'-msse2',
],
}],
[ 'target_arch != "arm" and target_arch != "mipsel" and \
target_arch != "arm64" and target_arch != "mips64el"', {
'sources': [
'ext/convolver_SSE2.cc',
'ext/convolver_SSE2.h',
],
}],
[ 'target_arch == "mipsel" and mips_dsp_rev >= 2',{
'sources': [
'ext/convolver_mips_dspr2.cc',
'ext/convolver_mips_dspr2.h',
],
}],
],
},
{
'target_name': 'image_operations_bench',
'type': 'executable',
'dependencies': [
'../base/base.gyp:base',
'skia',
],
'include_dirs': [
'..',
],
'sources': [
'ext/image_operations_bench.cc',
],
},
{
'target_name': 'filter_fuzz_stub',
'type': 'executable',
'dependencies': [
'../base/base.gyp:base',
'skia.gyp:skia',
],
'sources': [
'tools/filter_fuzz_stub/filter_fuzz_stub.cc',
],
'includes': [
'../build/android/increase_size_for_speed.gypi',
],
},
],
}
# Copyright 2013 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.
# This gypi file contains all the Chrome-specific enhancements to Skia.
# In component mode (shared_lib) it is folded into a single shared library with
# the Skia files but in all other cases it is a separate library.
{
'dependencies': [
'skia_library',
'skia_chrome_opts',
'../base/base.gyp:base',
'../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
],
'direct_dependent_settings': {
'include_dirs': [
'ext',
],
},
'variables': {
# TODO(scottmg): http://crbug.com/177306
'clang_warning_flags_unset': [
# Don't warn about string->bool used in asserts.
'-Wstring-conversion',
],
},
'sources': [
'config/SkUserConfig.h',
# Note: file list duplicated in GN build.
'ext/analysis_canvas.cc',
'ext/analysis_canvas.h',
'ext/benchmarking_canvas.cc',
'ext/benchmarking_canvas.h',
'ext/bitmap_platform_device.h',
'ext/bitmap_platform_device_cairo.cc',
'ext/bitmap_platform_device_cairo.h',
'ext/bitmap_platform_device_mac.cc',
'ext/bitmap_platform_device_mac.h',
'ext/bitmap_platform_device_skia.cc',
'ext/bitmap_platform_device_skia.h',
'ext/bitmap_platform_device_win.cc',
'ext/bitmap_platform_device_win.h',
'ext/convolver.cc',
'ext/convolver.h',
'ext/event_tracer_impl.cc',
'ext/event_tracer_impl.h',
'ext/fontmgr_default_win.cc',
'ext/fontmgr_default_win.h',
'ext/google_logging.cc',
'ext/image_operations.cc',
'ext/image_operations.h',
'ext/opacity_draw_filter.cc',
'ext/opacity_draw_filter.h',
'ext/pixel_ref_utils.cc',
'ext/pixel_ref_utils.h',
'ext/platform_canvas.cc',
'ext/platform_canvas.h',
'ext/platform_device.cc',
'ext/platform_device.h',
'ext/platform_device_linux.cc',
'ext/platform_device_mac.cc',
'ext/platform_device_win.cc',
'ext/recursive_gaussian_convolution.cc',
'ext/recursive_gaussian_convolution.h',
'ext/refptr.h',
'ext/SkDiscardableMemory_chrome.h',
'ext/SkDiscardableMemory_chrome.cc',
'ext/SkMemory_new_handler.cpp',
'ext/skia_utils_base.cc',
'ext/skia_utils_base.h',
'ext/skia_utils_ios.mm',
'ext/skia_utils_ios.h',
'ext/skia_utils_mac.mm',
'ext/skia_utils_mac.h',
'ext/skia_utils_win.cc',
'ext/skia_utils_win.h',
],
'conditions': [
[ 'OS == "android" and '
'enable_basic_printing==0 and enable_print_preview==0', {
'sources!': [
'ext/skia_utils_base.cc',
],
}],
['OS == "ios"', {
'dependencies!': [
'skia_chrome_opts',
],
}],
[ 'OS != "android" and (OS != "linux" or use_cairo==1)', {
'sources!': [
'ext/bitmap_platform_device_skia.cc',
],
}],
],
'target_conditions': [
# Pull in specific linux files for android (which have been filtered out
# by file name rules).
[ 'OS == "android"', {
'sources/': [
['include', 'ext/platform_device_linux\\.cc$'],
],
}],
],
}
......@@ -25,7 +25,7 @@
'<(skia_src_path)/ports/SkFontMgr_android_factory.cpp',
'<(skia_src_path)/ports/SkFontMgr_android_parser.cpp',
'<(skia_src_path)/ports/SkFontMgr_win_dw.cpp',
'<(skia_src_path)/ports/SkGlobalInitialization_chromium.cpp',
'<(skia_src_path)/ports/SkGlobalInitialization_default.cpp',
'<(skia_src_path)/ports/SkImageDecoder_empty.cpp',
'<(skia_src_path)/ports/SkOSFile_posix.cpp',
'<(skia_src_path)/ports/SkRemotableFontMgr_win_dw.cpp',
......
......@@ -50,7 +50,7 @@
'../third_party/skia/src/ports/SkFontMgr_android_factory.cpp',
'../third_party/skia/src/ports/SkFontMgr_android_parser.cpp',
'../third_party/skia/src/ports/SkFontMgr_win_dw.cpp',
'../third_party/skia/src/ports/SkGlobalInitialization_chromium.cpp',
'../third_party/skia/src/ports/SkGlobalInitialization_default.cpp',
'../third_party/skia/src/ports/SkOSFile_posix.cpp',
'../third_party/skia/src/ports/SkOSFile_stdio.cpp',
'../third_party/skia/src/ports/SkOSFile_win.cpp',
......
# Copyright 2013 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.
# This gyp file contains the platform-specific optimizations for Skia
{
'variables': {
'skia_src_path': '../third_party/skia/src',
'includes': [ '../third_party/skia/gyp/opts.gypi' ],
'include_dirs': [
'../third_party/skia/include/core',
'../third_party/skia/include/effects',
'../third_party/skia/include/utils',
'../third_party/skia/src/core',
'../third_party/skia/src/opts',
'../third_party/skia/src/utils',
],
},
'targets': [
# Due to an unfortunate intersection of lameness between gcc and gyp,
# we have to build the *_SSE2.cpp files in a separate target. The
# gcc lameness is that, in order to compile SSE2 intrinsics code, it
# must be passed the -msse2 flag. However, with this flag, it may
# emit SSE2 instructions even for scalar code, such as the CPUID
# test used to test for the presence of SSE2. So that, and all other
# code must be compiled *without* -msse2. The gyp lameness is that it
# does not allow file-specific CFLAGS, so we must create this extra
# target for those files to be compiled with -msse2.
#
# This is actually only a problem on 32-bit Linux (all Intel Macs have
# SSE2, Linux x86_64 has SSE2 by definition, and MSC will happily emit
# SSE2 from instrinsics, which generating plain ol' 386 for everything
# else). However, to keep the .gyp file simple and avoid platform-specific
# build breakage, we do this on all platforms.
# For about the same reason, we need to compile the ARM opts files
# separately as well.
{
'target_name': 'skia_opts',
'type': 'static_library',
'includes': [
'skia_common.gypi',
'../build/android/increase_size_for_speed.gypi',
# Disable LTO due to compiler error
# in mems_in_disjoint_alias_sets_p, at alias.c:393
# crbug.com/422255
'../build/android/disable_lto.gypi',
],
'include_dirs': [ '<@(include_dirs)' ],
'conditions': [
[ 'os_posix == 1 and OS != "mac" and OS != "android" and \
target_arch != "arm" and target_arch != "arm64" and \
target_arch != "mipsel" and target_arch != "mips64el"', {
'cflags': [ '-msse2' ],
}],
[ 'target_arch != "arm" and target_arch != "mipsel" and \
target_arch != "arm64" and target_arch != "mips64el"', {
'sources': [ '<@(sse2_sources)' ],
'dependencies': [
'skia_opts_ssse3',
'skia_opts_sse41',
],
}],
[ 'target_arch == "arm"', {
'conditions': [
[ 'arm_version >= 7', {
'sources': [ '<@(armv7_sources)' ],
}, { # arm_version < 7
'sources': [ '<@(none_sources)' ],
}],
[ 'arm_version >= 7 and (arm_neon == 1 or arm_neon_optional == 1)', {
'dependencies': [
'skia_opts_neon',
]
}],
],
# The assembly uses the frame pointer register (r7 in Thumb/r11 in
# ARM), the compiler doesn't like that. Explicitly remove the
# -fno-omit-frame-pointer flag for Android, as that gets added to all
# targets via common.gypi.
'cflags!': [
'-fno-omit-frame-pointer',
'-marm',
'-mapcs-frame',
],
'cflags': [
'-fomit-frame-pointer',
],
}],
[ 'target_arch == "mipsel"',{
'cflags': [ '-fomit-frame-pointer' ],
'conditions': [
[ 'mips_dsp_rev >= 1', {
'sources': [ '<@(mips_dsp_sources)' ],
}, { # mips_dsp_rev == 0
'sources': [ '<@(none_sources)' ],
}],
],
}],
[ 'target_arch == "mips64el"',{
'cflags': [ '-fomit-frame-pointer' ],
'sources': [ '<@(none_sources)' ],
}],
[ 'target_arch == "arm64"', {
'sources': [ '<@(arm64_sources)' ],
}],
],
},
# For the same lame reasons as what is done for skia_opts, we have to
# create another target specifically for SSSE3 code as we would not want
# to compile the SSE2 code with -mssse3 which would potentially allow
# gcc to generate SSSE3 code.
{
'target_name': 'skia_opts_ssse3',
'type': 'static_library',
'includes': [
'skia_common.gypi',
'../build/android/increase_size_for_speed.gypi',
],
'include_dirs': [ '<@(include_dirs)' ],
'conditions': [
[ 'OS in ["linux", "freebsd", "openbsd", "solaris", "android"]', {
'cflags': [ '-mssse3' ],
}],
[ 'OS == "mac"', {
'xcode_settings': {
'GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS': 'YES',
},
}],
[ 'OS == "win" and clang == 1', {
# cl.exe's /arch flag doesn't have a setting for SSSE3, and cl.exe
# doesn't need it for intrinsics. clang-cl does need it, though.
'msvs_settings': {
'VCCLCompilerTool': { 'AdditionalOptions': [ '-mssse3' ] },
},
}],
[ 'OS == "win"', {
'defines' : [ 'SK_CPU_SSE_LEVEL=31' ],
}],
[ 'target_arch != "arm" and target_arch != "arm64" and \
target_arch != "mipsel" and target_arch != "mips64el"', {
'sources': [ '<@(ssse3_sources)' ],
}],
],
},
# For the same lame reasons as what is done for skia_opts, we also have to
# create another target specifically for SSE4.1 code as we would not want
# to compile the SSE2 code with -msse4.1 which would potentially allow
# gcc to generate SSE4.1 code.
{
'target_name': 'skia_opts_sse41',
'type': 'static_library',
'includes': [
'skia_common.gypi',
'../build/android/increase_size_for_speed.gypi',
],
'include_dirs': [ '<@(include_dirs)' ],
'sources': [ '<@(sse41_sources)' ],
'conditions': [
[ 'OS in ["linux", "freebsd", "openbsd", "solaris", "android"]', {
'cflags': [ '-msse4.1' ],
}],
[ 'OS == "mac"', {
'xcode_settings': {
'GCC_ENABLE_SSE41_EXTENSIONS': 'YES',
},
}],
[ 'OS == "win" and clang == 1', {
# cl.exe's /arch flag doesn't have a setting for SSE4.1, and cl.exe
# doesn't need it for intrinsics. clang-cl does need it, though.
'msvs_settings': {
'VCCLCompilerTool': { 'AdditionalOptions': [ '-msse4.1' ] },
},
}],
[ 'OS == "win"', {
'defines' : [ 'SK_CPU_SSE_LEVEL=41' ],
}],
],
},
{
'target_name': 'skia_opts_none',
'type': 'static_library',
'includes': [
'skia_common.gypi',
'../build/android/increase_size_for_speed.gypi',
],
'include_dirs': [ '<@(include_dirs)' ],
'sources': [ '<@(none_sources)' ],
},
],
'conditions': [
# NEON code must be compiled with -mfpu=neon which also affects scalar
# code. To support dynamic NEON code paths, we need to build all
# NEON-specific sources in a separate static library. The situation
# is very similar to the SSSE3 one.
['target_arch == "arm" and (arm_neon == 1 or arm_neon_optional == 1)', {
'targets': [
{
'target_name': 'skia_opts_neon',
'type': 'static_library',
'includes': [
'skia_common.gypi',
'../build/android/increase_size_for_speed.gypi',
# Disable LTO due to Neon issues
# crbug.com/408997
'../build/android/disable_lto.gypi',
],
'include_dirs': [ '<@(include_dirs)' ],
'cflags!': [
'-fno-omit-frame-pointer',
'-mfpu=vfp', # remove them all, just in case.
'-mfpu=vfpv3',
'-mfpu=vfpv3-d16',
],
'cflags': [
'-mfpu=neon',
'-fomit-frame-pointer',
],
'ldflags': [
'-march=armv7-a',
'-Wl,--fix-cortex-a8',
],
'sources': [ '<@(neon_sources)' ],
},
],
}],
],
}
# TEMPORARY overrides of
# src/third_party/WebKit/LayoutTests/platform/chromium/test_expectations.txt
# that are associated with changes to the Skia code.
#
# GUIDELINES:
# - This file should be empty most of the time.
# - Expectations should only be added TEMPORARILY, as a step towards
# rebaselining layout test results. If any one expectation remains in here
# for more than a week or two, then we are probably doing something wrong.
# - Expectations from this file should NOT be rolled into any other
# test_expectations file. If there is a test that we expect to fail
# indefinitely, then we should add that test to the roach motel that is
# src/third_party/WebKit/LayoutTests/platform/chromium/test_expectations.txt
# - Tests listed in this file should NOT be rebaselined by WebKit Gardeners,
# unless they have made arrangements with Skia developers.
#
# For more information, see https://bugs.webkit.org/show_bug.cgi?id=86749
# or email skia-dev@google.com .
#
# INSTRUCTIONS:
# If you are rolling Skia's DEPS within Chrome, and trybot results indicate
# that the DEPS roll would break some webkit layout_tests, please follow
# these steps:
#
# 1. Confirm that those layout_test failures are "reasonable"-- Are they
# actually improvements, not regressions? Or maybe they are very minor
# differences that go along with a performance improvement?
# If not, please fix Skia rather than rolling in the version that will
# regress the webkit layout_tests.
#
# 2. File a bug to yourself to track the rebaselining of results caused by
# your Skia DEPS roll.
#
# 3. Add one or more lines to this file, in the same syntax used in the main
# test_expectations file, to mark those tests as expected-to-fail.
# Add this file to your DEPS roll CL.
#
# 4. Run your DEPS roll CL through the trybots again, and confirm your CL does
# not cause any layout tests to fail. (If there are still failures as a
# result of your CL, you probably didn't add the test expectations correctly.)
#
# 5. Commit your DEPS roll CL, and keep an eye on the waterfall bots to make
# sure nothing goes red.
#
# 6. Make sure to rebaseline the layout tests as soon as possible! The longer
# we leave overrides in this file, the harder it will be to rebaseline those
# tests (because other rendering changes might creep in).
#
# START OVERRIDES HERE
# END OVERRIDES HERE (this line ensures that the file is newline-terminated)
# Copyright 2014 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.
{
'variables': {
'chromium_code': 1,
},
'targets': [
{
'target_name': 'skia_unittests',
'type': '<(gtest_target_type)',
'dependencies': [
'../base/base.gyp:base',
'../base/base.gyp:run_all_unittests',
'../testing/gtest.gyp:gtest',
'../skia/skia.gyp:skia',
'../ui/gfx/gfx.gyp:gfx',
'../ui/gfx/gfx.gyp:gfx_geometry',
],
'sources': [
'ext/analysis_canvas_unittest.cc',
'ext/bitmap_platform_device_mac_unittest.cc',
'ext/convolver_unittest.cc',
'ext/image_operations_unittest.cc',
'ext/pixel_ref_utils_unittest.cc',
'ext/platform_canvas_unittest.cc',
'ext/recursive_gaussian_convolution_unittest.cc',
'ext/refptr_unittest.cc',
'ext/skia_utils_ios_unittest.mm',
'ext/skia_utils_mac_unittest.mm',
],
'conditions': [
['OS != "win" and OS != "mac"', {
'sources!': [
'ext/platform_canvas_unittest.cc',
],
}],
['OS == "android"', {
'dependencies': [
'../testing/android/native_test.gyp:native_test_native_code',
],
}],
],
},
],
'conditions': [
['OS == "android"', {
'targets': [
{
'target_name': 'skia_unittests_apk',
'type': 'none',
'dependencies': [
'skia_unittests',
],
'variables': {
'test_suite_name': 'skia_unittests',
},
'includes': [ '../build/apk_test.gypi' ],
},
],
}],
],
}
......@@ -264,8 +264,6 @@ source_set("platform") {
"graphics/filters/FESpecularLighting.h",
"graphics/filters/FETile.cpp",
"graphics/filters/FETile.h",
"graphics/filters/FETurbulence.cpp",
"graphics/filters/FETurbulence.h",
"graphics/filters/Filter.h",
"graphics/filters/FilterEffect.cpp",
"graphics/filters/FilterEffect.h",
......
......@@ -45,7 +45,7 @@ DecodingImageGenerator::~DecodingImageGenerator()
{
}
SkData* DecodingImageGenerator::onRefEncodedData()
SkData* DecodingImageGenerator::onRefEncodedData(GrContext* ctx)
{
// FIXME: If the image has been clipped or scaled, do not return the original
// encoded data, since on playback it will not be known how the clipping/scaling
......
......@@ -49,7 +49,7 @@ public:
void setGenerationId(size_t id) { m_generationId = id; }
protected:
virtual SkData* onRefEncodedData() override;
virtual SkData* onRefEncodedData(GrContext* ctx = nullptr) override;
virtual bool onGetPixels(const SkImageInfo&, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount) override;
virtual bool onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3]) override;
......
......@@ -104,7 +104,7 @@ void StrokeData::setupPaintDashPathEffect(SkPaint* paint, int length) const
}
SkScalar dashLengthSk = SkIntToScalar(dashLength);
SkScalar intervals[2] = { dashLengthSk, dashLengthSk };
RefPtr<SkDashPathEffect> pathEffect = adoptRef(SkDashPathEffect::Create(intervals, 2, SkIntToScalar(phase)));
RefPtr<SkPathEffect> pathEffect = adoptRef(SkDashPathEffect::Create(intervals, 2, SkIntToScalar(phase)));
paint->setPathEffect(pathEffect.get());
}
}
......
......@@ -103,7 +103,7 @@ private:
SkPaint::Cap m_lineCap;
SkPaint::Join m_lineJoin;
float m_miterLimit;
RefPtr<SkDashPathEffect> m_dash;
RefPtr<SkPathEffect> m_dash;
};
} // namespace blink
......
/*
* Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
* Copyright (C) 2005 Eric Seidel <eric@webkit.org>
* Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
* Copyright (C) 2010 Renata Hodovan <reni@inf.u-szeged.hu>
* Copyright (C) 2011 Gabor Loki <loki@webkit.org>
* Copyright (C) 2013 Google Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "sky/engine/platform/graphics/filters/FETurbulence.h"
#include "sky/engine/platform/graphics/filters/ParallelJobs.h"
#include "sky/engine/platform/graphics/filters/SkiaImageFilterBuilder.h"
#include "sky/engine/platform/text/TextStream.h"
#include "sky/engine/wtf/MathExtras.h"
#include "sky/engine/wtf/Uint8ClampedArray.h"
#include "third_party/skia/include/effects/SkPerlinNoiseShader.h"
#include "third_party/skia/include/effects/SkRectShaderImageFilter.h"
namespace blink {
/*
Produces results in the range [1, 2**31 - 2]. Algorithm is:
r = (a * r) mod m where a = randAmplitude = 16807 and
m = randMaximum = 2**31 - 1 = 2147483647, r = seed.
See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988
To test: the algorithm should produce the result 1043618065
as the 10,000th generated number if the original seed is 1.
*/
static const int s_perlinNoise = 4096;
static const long s_randMaximum = 2147483647; // 2**31 - 1
static const int s_randAmplitude = 16807; // 7**5; primitive root of m
static const int s_randQ = 127773; // m / a
static const int s_randR = 2836; // m % a
FETurbulence::FETurbulence(Filter* filter, TurbulenceType type, float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed, bool stitchTiles)
: FilterEffect(filter)
, m_type(type)
, m_baseFrequencyX(baseFrequencyX)
, m_baseFrequencyY(baseFrequencyY)
, m_numOctaves(numOctaves)
, m_seed(seed)
, m_stitchTiles(stitchTiles)
{
}
PassRefPtr<FETurbulence> FETurbulence::create(Filter* filter, TurbulenceType type, float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed, bool stitchTiles)
{
return adoptRef(new FETurbulence(filter, type, baseFrequencyX, baseFrequencyY, numOctaves, seed, stitchTiles));
}
TurbulenceType FETurbulence::type() const
{
return m_type;
}
bool FETurbulence::setType(TurbulenceType type)
{
if (m_type == type)
return false;
m_type = type;
return true;
}
float FETurbulence::baseFrequencyY() const
{
return m_baseFrequencyY;
}
bool FETurbulence::setBaseFrequencyY(float baseFrequencyY)
{
if (m_baseFrequencyY == baseFrequencyY)
return false;
m_baseFrequencyY = baseFrequencyY;
return true;
}
float FETurbulence::baseFrequencyX() const
{
return m_baseFrequencyX;
}
bool FETurbulence::setBaseFrequencyX(float baseFrequencyX)
{
if (m_baseFrequencyX == baseFrequencyX)
return false;
m_baseFrequencyX = baseFrequencyX;
return true;
}
float FETurbulence::seed() const
{
return m_seed;
}
bool FETurbulence::setSeed(float seed)
{
if (m_seed == seed)
return false;
m_seed = seed;
return true;
}
int FETurbulence::numOctaves() const
{
return m_numOctaves;
}
bool FETurbulence::setNumOctaves(int numOctaves)
{
if (m_numOctaves == numOctaves)
return false;
m_numOctaves = numOctaves;
return true;
}
bool FETurbulence::stitchTiles() const
{
return m_stitchTiles;
}
bool FETurbulence::setStitchTiles(bool stitch)
{
if (m_stitchTiles == stitch)
return false;
m_stitchTiles = stitch;
return true;
}
// The turbulence calculation code is an adapted version of what appears in the SVG 1.1 specification:
// http://www.w3.org/TR/SVG11/filters.html#feTurbulence
// Compute pseudo random number.
inline long FETurbulence::PaintingData::random()
{
long result = s_randAmplitude * (seed % s_randQ) - s_randR * (seed / s_randQ);
if (result <= 0)
result += s_randMaximum;
seed = result;
return result;
}
inline float smoothCurve(float t)
{
return t * t * (3 - 2 * t);
}
inline float linearInterpolation(float t, float a, float b)
{
return a + t * (b - a);
}
inline void FETurbulence::initPaint(PaintingData& paintingData)
{
float normalizationFactor;
// The seed value clamp to the range [1, s_randMaximum - 1].
if (paintingData.seed <= 0)
paintingData.seed = -(paintingData.seed % (s_randMaximum - 1)) + 1;
if (paintingData.seed > s_randMaximum - 1)
paintingData.seed = s_randMaximum - 1;
float* gradient;
for (int channel = 0; channel < 4; ++channel) {
for (int i = 0; i < s_blockSize; ++i) {
paintingData.latticeSelector[i] = i;
gradient = paintingData.gradient[channel][i];
gradient[0] = static_cast<float>((paintingData.random() % (2 * s_blockSize)) - s_blockSize) / s_blockSize;
gradient[1] = static_cast<float>((paintingData.random() % (2 * s_blockSize)) - s_blockSize) / s_blockSize;
normalizationFactor = sqrtf(gradient[0] * gradient[0] + gradient[1] * gradient[1]);
gradient[0] /= normalizationFactor;
gradient[1] /= normalizationFactor;
}
}
for (int i = s_blockSize - 1; i > 0; --i) {
int k = paintingData.latticeSelector[i];
int j = paintingData.random() % s_blockSize;
ASSERT(j >= 0);
ASSERT(j < 2 * s_blockSize + 2);
paintingData.latticeSelector[i] = paintingData.latticeSelector[j];
paintingData.latticeSelector[j] = k;
}
for (int i = 0; i < s_blockSize + 2; ++i) {
paintingData.latticeSelector[s_blockSize + i] = paintingData.latticeSelector[i];
for (int channel = 0; channel < 4; ++channel) {
paintingData.gradient[channel][s_blockSize + i][0] = paintingData.gradient[channel][i][0];
paintingData.gradient[channel][s_blockSize + i][1] = paintingData.gradient[channel][i][1];
}
}
}
inline void checkNoise(int& noiseValue, int limitValue, int newValue)
{
if (noiseValue >= limitValue)
noiseValue -= newValue;
if (noiseValue >= limitValue - 1)
noiseValue -= newValue - 1;
}
float FETurbulence::noise2D(int channel, PaintingData& paintingData, StitchData& stitchData, const FloatPoint& noiseVector)
{
struct Noise {
int noisePositionIntegerValue;
float noisePositionFractionValue;
Noise(float component)
{
float position = component + s_perlinNoise;
noisePositionIntegerValue = static_cast<int>(position);
noisePositionFractionValue = position - noisePositionIntegerValue;
}
};
Noise noiseX(noiseVector.x());
Noise noiseY(noiseVector.y());
float* q;
float sx, sy, a, b, u, v;
// If stitching, adjust lattice points accordingly.
if (m_stitchTiles) {
checkNoise(noiseX.noisePositionIntegerValue, stitchData.wrapX, stitchData.width);
checkNoise(noiseY.noisePositionIntegerValue, stitchData.wrapY, stitchData.height);
}
noiseX.noisePositionIntegerValue &= s_blockMask;
noiseY.noisePositionIntegerValue &= s_blockMask;
int latticeIndex = paintingData.latticeSelector[noiseX.noisePositionIntegerValue];
int nextLatticeIndex = paintingData.latticeSelector[(noiseX.noisePositionIntegerValue + 1) & s_blockMask];
sx = smoothCurve(noiseX.noisePositionFractionValue);
sy = smoothCurve(noiseY.noisePositionFractionValue);
// This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement.
int temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue];
q = paintingData.gradient[channel][temp];
u = noiseX.noisePositionFractionValue * q[0] + noiseY.noisePositionFractionValue * q[1];
temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue];
q = paintingData.gradient[channel][temp];
v = (noiseX.noisePositionFractionValue - 1) * q[0] + noiseY.noisePositionFractionValue * q[1];
a = linearInterpolation(sx, u, v);
temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue + 1];
q = paintingData.gradient[channel][temp];
u = noiseX.noisePositionFractionValue * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1];
temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue + 1];
q = paintingData.gradient[channel][temp];
v = (noiseX.noisePositionFractionValue - 1) * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1];
b = linearInterpolation(sx, u, v);
return linearInterpolation(sy, a, b);
}
unsigned char FETurbulence::calculateTurbulenceValueForPoint(int channel, PaintingData& paintingData, StitchData& stitchData, const FloatPoint& point, float baseFrequencyX, float baseFrequencyY)
{
float tileWidth = paintingData.filterSize.width();
float tileHeight = paintingData.filterSize.height();
ASSERT(tileWidth > 0 && tileHeight > 0);
// Adjust the base frequencies if necessary for stitching.
if (m_stitchTiles) {
// When stitching tiled turbulence, the frequencies must be adjusted
// so that the tile borders will be continuous.
if (baseFrequencyX) {
float lowFrequency = floorf(tileWidth * baseFrequencyX) / tileWidth;
float highFrequency = ceilf(tileWidth * baseFrequencyX) / tileWidth;
// BaseFrequency should be non-negative according to the standard.
if (baseFrequencyX / lowFrequency < highFrequency / baseFrequencyX)
baseFrequencyX = lowFrequency;
else
baseFrequencyX = highFrequency;
}
if (baseFrequencyY) {
float lowFrequency = floorf(tileHeight * baseFrequencyY) / tileHeight;
float highFrequency = ceilf(tileHeight * baseFrequencyY) / tileHeight;
if (baseFrequencyY / lowFrequency < highFrequency / baseFrequencyY)
baseFrequencyY = lowFrequency;
else
baseFrequencyY = highFrequency;
}
// Set up TurbulenceInitial stitch values.
stitchData.width = roundf(tileWidth * baseFrequencyX);
stitchData.wrapX = s_perlinNoise + stitchData.width;
stitchData.height = roundf(tileHeight * baseFrequencyY);
stitchData.wrapY = s_perlinNoise + stitchData.height;
}
float turbulenceFunctionResult = 0;
FloatPoint noiseVector(point.x() * baseFrequencyX, point.y() * baseFrequencyY);
float ratio = 1;
for (int octave = 0; octave < m_numOctaves; ++octave) {
if (m_type == FETURBULENCE_TYPE_FRACTALNOISE)
turbulenceFunctionResult += noise2D(channel, paintingData, stitchData, noiseVector) / ratio;
else
turbulenceFunctionResult += fabsf(noise2D(channel, paintingData, stitchData, noiseVector)) / ratio;
noiseVector.setX(noiseVector.x() * 2);
noiseVector.setY(noiseVector.y() * 2);
ratio *= 2;
if (m_stitchTiles) {
// Update stitch values. Subtracting s_perlinNoiseoise before the multiplication and
// adding it afterward simplifies to subtracting it once.
stitchData.width *= 2;
stitchData.wrapX = 2 * stitchData.wrapX - s_perlinNoise;
stitchData.height *= 2;
stitchData.wrapY = 2 * stitchData.wrapY - s_perlinNoise;
}
}
// The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult * 255) + 255) / 2 by fractalNoise
// and (turbulenceFunctionResult * 255) by turbulence.
if (m_type == FETURBULENCE_TYPE_FRACTALNOISE)
turbulenceFunctionResult = turbulenceFunctionResult * 0.5f + 0.5f;
// Clamp result
turbulenceFunctionResult = std::max(std::min(turbulenceFunctionResult, 1.f), 0.f);
return static_cast<unsigned char>(turbulenceFunctionResult * 255);
}
inline void FETurbulence::fillRegion(Uint8ClampedArray* pixelArray, PaintingData& paintingData, int startY, int endY, float baseFrequencyX, float baseFrequencyY)
{
IntRect filterRegion = absolutePaintRect();
IntPoint point(0, filterRegion.y() + startY);
int indexOfPixelChannel = startY * (filterRegion.width() << 2);
int channel;
StitchData stitchData;
for (int y = startY; y < endY; ++y) {
point.setY(point.y() + 1);
point.setX(filterRegion.x());
for (int x = 0; x < filterRegion.width(); ++x) {
point.setX(point.x() + 1);
for (channel = 0; channel < 4; ++channel, ++indexOfPixelChannel)
pixelArray->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(channel, paintingData, stitchData, filter()->mapAbsolutePointToLocalPoint(point), baseFrequencyX, baseFrequencyY));
}
}
}
void FETurbulence::fillRegionWorker(FillRegionParameters* parameters)
{
parameters->filter->fillRegion(parameters->pixelArray, *parameters->paintingData, parameters->startY, parameters->endY, parameters->baseFrequencyX, parameters->baseFrequencyY);
}
void FETurbulence::applySoftware()
{
Uint8ClampedArray* pixelArray = createUnmultipliedImageResult();
if (!pixelArray)
return;
if (absolutePaintRect().isEmpty()) {
pixelArray->zeroFill();
return;
}
PaintingData paintingData(m_seed, roundedIntSize(filterPrimitiveSubregion().size()));
initPaint(paintingData);
int optimalThreadNumber = (absolutePaintRect().width() * absolutePaintRect().height()) / s_minimalRectDimension;
if (optimalThreadNumber > 1) {
// Initialize parallel jobs
ParallelJobs<FillRegionParameters> parallelJobs(&FETurbulence::fillRegionWorker, optimalThreadNumber);
// Fill the parameter array
int i = parallelJobs.numberOfJobs();
if (i > 1) {
// Split the job into "stepY"-sized jobs but there a few jobs that need to be slightly larger since
// stepY * jobs < total size. These extras are handled by the remainder "jobsWithExtra".
const int stepY = absolutePaintRect().height() / i;
const int jobsWithExtra = absolutePaintRect().height() % i;
int startY = 0;
for (; i > 0; --i) {
FillRegionParameters& params = parallelJobs.parameter(i-1);
params.filter = this;
params.pixelArray = pixelArray;
params.paintingData = &paintingData;
params.startY = startY;
startY += i < jobsWithExtra ? stepY + 1 : stepY;
params.endY = startY;
params.baseFrequencyX = m_baseFrequencyX;
params.baseFrequencyY = m_baseFrequencyY;
}
// Execute parallel jobs
parallelJobs.execute();
return;
}
}
// Fallback to single threaded mode if there is no room for a new thread or the paint area is too small.
fillRegion(pixelArray, paintingData, 0, absolutePaintRect().height(), m_baseFrequencyX, m_baseFrequencyY);
}
SkShader* FETurbulence::createShader()
{
const SkISize size = SkISize::Make(effectBoundaries().width(), effectBoundaries().height());
// Frequency should be scaled by page zoom, but not by primitiveUnits.
// So we apply only the transform scale (as Filter::apply*Scale() do)
// and not the target bounding box scale (as SVGFilter::apply*Scale()
// would do). Note also that we divide by the scale since this is
// a frequency, not a period.
const AffineTransform& absoluteTransform = filter()->absoluteTransform();
float baseFrequencyX = m_baseFrequencyX / absoluteTransform.a();
float baseFrequencyY = m_baseFrequencyY / absoluteTransform.d();
return (type() == FETURBULENCE_TYPE_FRACTALNOISE) ?
SkPerlinNoiseShader::CreateFractalNoise(SkFloatToScalar(baseFrequencyX),
SkFloatToScalar(baseFrequencyY), numOctaves(), SkFloatToScalar(seed()),
stitchTiles() ? &size : 0) :
SkPerlinNoiseShader::CreateTurbulence(SkFloatToScalar(baseFrequencyX),
SkFloatToScalar(baseFrequencyY), numOctaves(), SkFloatToScalar(seed()),
stitchTiles() ? &size : 0);
}
PassRefPtr<SkImageFilter> FETurbulence::createImageFilter(SkiaImageFilterBuilder* builder)
{
SkAutoTUnref<SkShader> shader(createShader());
SkImageFilter::CropRect rect = getCropRect(builder->cropOffset());
return adoptRef(SkRectShaderImageFilter::Create(shader, &rect));
}
static TextStream& operator<<(TextStream& ts, const TurbulenceType& type)
{
switch (type) {
case FETURBULENCE_TYPE_UNKNOWN:
ts << "UNKNOWN";
break;
case FETURBULENCE_TYPE_TURBULENCE:
ts << "TURBULENCE";
break;
case FETURBULENCE_TYPE_FRACTALNOISE:
ts << "NOISE";
break;
}
return ts;
}
TextStream& FETurbulence::externalRepresentation(TextStream& ts, int indent) const
{
writeIndent(ts, indent);
ts << "[feTurbulence";
FilterEffect::externalRepresentation(ts);
ts << " type=\"" << type() << "\" "
<< "baseFrequency=\"" << baseFrequencyX() << ", " << baseFrequencyY() << "\" "
<< "seed=\"" << seed() << "\" "
<< "numOctaves=\"" << numOctaves() << "\" "
<< "stitchTiles=\"" << stitchTiles() << "\"]\n";
return ts;
}
} // namespace blink
/*
* Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
* Copyright (C) 2005 Eric Seidel <eric@webkit.org>
* Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
* Copyright (C) 2010 Renata Hodovan <reni@inf.u-szeged.hu>
* Copyright (C) 2013 Google Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef SKY_ENGINE_PLATFORM_GRAPHICS_FILTERS_FETURBULENCE_H_
#define SKY_ENGINE_PLATFORM_GRAPHICS_FILTERS_FETURBULENCE_H_
#include "sky/engine/platform/graphics/filters/Filter.h"
#include "sky/engine/platform/graphics/filters/FilterEffect.h"
namespace blink {
enum TurbulenceType {
FETURBULENCE_TYPE_UNKNOWN = 0,
FETURBULENCE_TYPE_FRACTALNOISE = 1,
FETURBULENCE_TYPE_TURBULENCE = 2
};
class PLATFORM_EXPORT FETurbulence : public FilterEffect {
public:
static PassRefPtr<FETurbulence> create(Filter*, TurbulenceType, float, float, int, float, bool);
TurbulenceType type() const;
bool setType(TurbulenceType);
float baseFrequencyY() const;
bool setBaseFrequencyY(float);
float baseFrequencyX() const;
bool setBaseFrequencyX(float);
float seed() const;
bool setSeed(float);
int numOctaves() const;
bool setNumOctaves(int);
bool stitchTiles() const;
bool setStitchTiles(bool);
static void fillRegionWorker(void*);
virtual TextStream& externalRepresentation(TextStream&, int indention) const override;
private:
static const int s_blockSize = 256;
static const int s_blockMask = s_blockSize - 1;
static const int s_minimalRectDimension = (100 * 100); // Empirical data limit for parallel jobs.
struct PaintingData {
PaintingData(long paintingSeed, const IntSize& paintingSize)
: seed(paintingSeed)
, filterSize(paintingSize)
{
}
long seed;
int latticeSelector[2 * s_blockSize + 2];
float gradient[4][2 * s_blockSize + 2][2];
IntSize filterSize;
inline long random();
};
struct StitchData {
StitchData()
: width(0)
, wrapX(0)
, height(0)
, wrapY(0)
{
}
int width; // How much to subtract to wrap for stitching.
int wrapX; // Minimum value to wrap.
int height;
int wrapY;
};
template<typename Type>
friend class ParallelJobs;
struct FillRegionParameters {
FETurbulence* filter;
Uint8ClampedArray* pixelArray;
PaintingData* paintingData;
int startY;
int endY;
float baseFrequencyX;
float baseFrequencyY;
};
static void fillRegionWorker(FillRegionParameters*);
FETurbulence(Filter*, TurbulenceType, float, float, int, float, bool);
virtual void applySoftware() override;
virtual PassRefPtr<SkImageFilter> createImageFilter(SkiaImageFilterBuilder*) override;
SkShader* createShader();
inline void initPaint(PaintingData&);
float noise2D(int channel, PaintingData&, StitchData&, const FloatPoint&);
unsigned char calculateTurbulenceValueForPoint(int channel, PaintingData&, StitchData&, const FloatPoint&, float, float);
inline void fillRegion(Uint8ClampedArray*, PaintingData&, int, int, float, float);
TurbulenceType m_type;
float m_baseFrequencyX;
float m_baseFrequencyY;
int m_numOctaves;
float m_seed;
bool m_stitchTiles;
};
} // namespace blink
#endif // SKY_ENGINE_PLATFORM_GRAPHICS_FILTERS_FETURBULENCE_H_
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册