[go: nahoru, domu]

ImageHijackCanvas should skip non-lazy images from SkImageShader

ImageHijack canvas can currently hit a DCHECK when we try to process
images from SkImageShaders, as it handles them even if they are
non-lazy. Non-lazy images should be skipped.

BUG=673981
CQ_INCLUDE_TRYBOTS=master.tryserver.blink:linux_trusty_blink_rel

Review-Url: https://codereview.chromium.org/2572783005
Cr-Commit-Position: refs/heads/master@{#438650}
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 8e6b7e5..d9c52a2d 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -852,6 +852,7 @@
     "output/texture_mailbox_deleter_unittest.cc",
     "playback/discardable_image_map_unittest.cc",
     "playback/display_item_list_unittest.cc",
+    "playback/image_hijack_canvas_unittest.cc",
     "playback/raster_source_unittest.cc",
     "playback/recording_source_unittest.cc",
     "proto/base_conversions_unittest.cc",
diff --git a/cc/playback/image_hijack_canvas.cc b/cc/playback/image_hijack_canvas.cc
index 98fd4717..a5d596d7 100644
--- a/cc/playback/image_hijack_canvas.cc
+++ b/cc/playback/image_hijack_canvas.cc
@@ -83,7 +83,7 @@
     SkMatrix matrix;
     SkShader::TileMode xy[2];
     SkImage* image = shader->isAImage(&matrix, xy);
-    if (!image)
+    if (!image || !image->isLazyGenerated())
       return base::Optional<ScopedImagePaint>();
 
     SkMatrix total_image_matrix = matrix;
diff --git a/cc/playback/image_hijack_canvas.h b/cc/playback/image_hijack_canvas.h
index 46495da..be9a6ba 100644
--- a/cc/playback/image_hijack_canvas.h
+++ b/cc/playback/image_hijack_canvas.h
@@ -6,13 +6,14 @@
 #define CC_PLAYBACK_IMAGE_HIJACK_CANVAS_H_
 
 #include "base/macros.h"
+#include "cc/base/cc_export.h"
 #include "third_party/skia/include/utils/SkNWayCanvas.h"
 
 namespace cc {
 
 class ImageDecodeCache;
 
-class ImageHijackCanvas : public SkNWayCanvas {
+class CC_EXPORT ImageHijackCanvas : public SkNWayCanvas {
  public:
   ImageHijackCanvas(int width,
                     int height,
diff --git a/cc/playback/image_hijack_canvas_unittest.cc b/cc/playback/image_hijack_canvas_unittest.cc
new file mode 100644
index 0000000..214de87
--- /dev/null
+++ b/cc/playback/image_hijack_canvas_unittest.cc
@@ -0,0 +1,65 @@
+// 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 "cc/playback/image_hijack_canvas.h"
+
+#include "cc/tiles/image_decode_cache.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkImage.h"
+#include "third_party/skia/include/core/SkPath.h"
+
+namespace cc {
+namespace {
+
+class MockImageDecodeCache : public ImageDecodeCache {
+ public:
+  MOCK_METHOD3(GetTaskForImageAndRef,
+               bool(const DrawImage& image,
+                    const TracingInfo& tracing_info,
+                    scoped_refptr<TileTask>* task));
+  MOCK_METHOD1(UnrefImage, void(const DrawImage& image));
+  MOCK_METHOD1(GetDecodedImageForDraw,
+               DecodedDrawImage(const DrawImage& image));
+  MOCK_METHOD2(DrawWithImageFinished,
+               void(const DrawImage& image,
+                    const DecodedDrawImage& decoded_image));
+  MOCK_METHOD0(ReduceCacheUsage, void());
+  MOCK_METHOD1(SetShouldAggressivelyFreeResources,
+               void(bool aggressively_free_resources));
+};
+
+TEST(ImageHijackCanvasTest, NonLazyImagesSkipped) {
+  // Use a strict mock so that if *any* ImageDecodeCache methods are called, we
+  // will hit an error.
+  testing::StrictMock<MockImageDecodeCache> image_decode_cache;
+  ImageHijackCanvas canvas(100, 100, &image_decode_cache);
+
+  // Use an SkBitmap backed image to ensure that the image is not
+  // lazy-generated.
+  SkBitmap bitmap;
+  bitmap.allocN32Pixels(10, 10, true);
+  sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
+
+  SkPaint paint;
+  canvas.drawImage(image, 0, 0, &paint);
+  canvas.drawImageRect(image, SkRect::MakeXYWH(0, 0, 10, 10),
+                       SkRect::MakeXYWH(10, 10, 10, 10), &paint);
+
+  SkPaint image_paint;
+  image_paint.setShader(
+      image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode));
+  SkRect paint_rect = SkRect::MakeXYWH(0, 0, 100, 100);
+  canvas.drawRect(paint_rect, image_paint);
+  SkPath path;
+  path.addRect(paint_rect, SkPath::kCW_Direction);
+  canvas.drawPath(path, image_paint);
+  canvas.drawOval(paint_rect, image_paint);
+  canvas.drawArc(paint_rect, 0, 40, true, image_paint);
+  canvas.drawRRect(SkRRect::MakeRect(paint_rect), image_paint);
+}
+
+}  // namespace
+
+}  // namespace cc