Skip to content

Commit

Permalink
clone pixel_ref_utils into discardable_image_utils, since blink now c…
Browse files Browse the repository at this point in the history
…reates images instead of bitmaps. When this is in place, we can remove pixel_ref_utils.

BUG=

Review URL: https://codereview.chromium.org/1306293004

Cr-Commit-Position: refs/heads/master@{#346134}
  • Loading branch information
reed-at-google authored and Commit bot committed Aug 28, 2015
1 parent 25b4f71 commit 47c0625
Show file tree
Hide file tree
Showing 5 changed files with 354 additions and 0 deletions.
134 changes: 134 additions & 0 deletions skia/ext/discardable_image_utils.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Copyright 2015 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 "skia/ext/discardable_image_utils.h"

#include <algorithm>

#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/utils/SkNWayCanvas.h"

namespace skia {

namespace {

class DiscardableImageSet {
public:
DiscardableImageSet(std::vector<DiscardableImageUtils::PositionImage>* images)
: images_(images) {}

void Add(const SkImage* image,
const SkRect& rect,
const SkMatrix& matrix,
SkFilterQuality filter_quality) {
// We should only be saving discardable pixel refs.
SkASSERT(image->isLazyGenerated());

DiscardableImageUtils::PositionImage position_image;
position_image.image = image;
position_image.image_rect = rect;
position_image.matrix = matrix;
position_image.filter_quality = filter_quality;
images_->push_back(position_image);
}

private:
std::vector<DiscardableImageUtils::PositionImage>* images_;
};

SkRect MapRect(const SkMatrix& matrix, const SkRect& src) {
SkRect dst;
matrix.mapRect(&dst, src);
return dst;
}

class GatherDiscardableImageCanvas : public SkNWayCanvas {
public:
GatherDiscardableImageCanvas(int width,
int height,
DiscardableImageSet* image_set)
: SkNWayCanvas(width, height),
image_set_(image_set),
canvas_bounds_(SkRect::MakeIWH(width, height)) {}

protected:
// we need to "undo" the behavio of SkNWayCanvas, which will try to forward
// it.
void onDrawPicture(const SkPicture* picture,
const SkMatrix* matrix,
const SkPaint* paint) override {
SkCanvas::onDrawPicture(picture, matrix, paint);
}

void onDrawImage(const SkImage* image,
SkScalar x,
SkScalar y,
const SkPaint* paint) override {
const SkMatrix& ctm = this->getTotalMatrix();
AddImage(image, MapRect(ctm, SkRect::MakeXYWH(x, y, image->width(),
image->height())),
ctm, paint);
}

void onDrawImageRect(const SkImage* image,
const SkRect* src,
const SkRect& dst,
const SkPaint* paint,
SrcRectConstraint) override {
const SkMatrix& ctm = this->getTotalMatrix();
SkRect src_storage;
if (!src) {
src_storage = SkRect::MakeIWH(image->width(), image->height());
src = &src_storage;
}
SkMatrix matrix;
matrix.setRectToRect(*src, dst, SkMatrix::kFill_ScaleToFit);
matrix.postConcat(ctm);
AddImage(image, MapRect(ctm, dst), matrix, paint);
}

void onDrawImageNine(const SkImage* image,
const SkIRect& center,
const SkRect& dst,
const SkPaint* paint) override {
AddImage(image, dst, this->getTotalMatrix(), paint);
}

private:
DiscardableImageSet* image_set_;
const SkRect canvas_bounds_;

void AddImage(const SkImage* image,
const SkRect& rect,
const SkMatrix& matrix,
const SkPaint* paint) {
if (rect.intersects(canvas_bounds_) && image->isLazyGenerated()) {
SkFilterQuality filter_quality = kNone_SkFilterQuality;
if (paint) {
filter_quality = paint->getFilterQuality();
}
image_set_->Add(image, rect, matrix, filter_quality);
}
}
};

} // namespace

void DiscardableImageUtils::GatherDiscardableImages(
SkPicture* picture,
std::vector<PositionImage>* images) {
images->clear();
DiscardableImageSet image_set(images);

SkIRect picture_ibounds = picture->cullRect().roundOut();
// Use right/bottom as the size so that we don't need a translate and, as a
// result, the information is returned relative to the picture's origin.
GatherDiscardableImageCanvas canvas(picture_ibounds.right(),
picture_ibounds.bottom(), &image_set);

canvas.drawPicture(picture);
}

} // namespace skia
33 changes: 33 additions & 0 deletions skia/ext/discardable_image_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2015 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_PIXEL_REF_UTILS_H_
#define SKIA_EXT_PIXEL_REF_UTILS_H_

#include <vector>

#include "SkPicture.h"
#include "SkRect.h"

namespace skia {

class SK_API DiscardableImageUtils {
public:
struct PositionImage {
const SkImage* image;
SkRect image_rect;
SkMatrix matrix;
SkFilterQuality filter_quality;
};

static void GatherDiscardableImages(SkPicture* picture,
std::vector<PositionImage>* images);
};

using PositionImage = DiscardableImageUtils::PositionImage;
using DiscardableImageList = std::vector<PositionImage>;

} // namespace skia

#endif
185 changes: 185 additions & 0 deletions skia/ext/discardable_image_utils_unittest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
// 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.

#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "cc/test/geometry_test_utils.h"
#include "skia/ext/discardable_image_utils.h"
#include "skia/ext/refptr.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkImageGenerator.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/src/core/SkOrderedReadBuffer.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/skia_util.h"

namespace skia {

namespace {

class TestImageGenerator : public SkImageGenerator {
public:
TestImageGenerator(const SkImageInfo& info) : SkImageGenerator(info) {}
};

skia::RefPtr<SkImage> CreateDiscardableImage(const gfx::Size& size) {
const SkImageInfo info =
SkImageInfo::MakeN32Premul(size.width(), size.height());
return skia::AdoptRef(
SkImage::NewFromGenerator(new TestImageGenerator(info)));
}

SkCanvas* StartRecording(SkPictureRecorder* recorder, gfx::Rect layer_rect) {
SkCanvas* canvas =
recorder->beginRecording(layer_rect.width(), layer_rect.height());

canvas->save();
canvas->translate(-layer_rect.x(), -layer_rect.y());
canvas->clipRect(SkRect::MakeXYWH(layer_rect.x(), layer_rect.y(),
layer_rect.width(), layer_rect.height()));

return canvas;
}

SkPicture* StopRecording(SkPictureRecorder* recorder, SkCanvas* canvas) {
canvas->restore();
return recorder->endRecordingAsPicture();
}

void VerifyScales(SkScalar x_scale,
SkScalar y_scale,
const SkMatrix& matrix,
int source_line) {
SkSize scales;
bool success = matrix.decomposeScale(&scales);
EXPECT_TRUE(success) << "line: " << source_line;
EXPECT_FLOAT_EQ(x_scale, scales.width()) << "line: " << source_line;
EXPECT_FLOAT_EQ(y_scale, scales.height()) << "line: " << source_line;
}

} // namespace

TEST(DiscardableImageUtilsTest, DrawImage) {
gfx::Rect layer_rect(0, 0, 256, 256);

SkPictureRecorder recorder;
SkCanvas* canvas = StartRecording(&recorder, layer_rect);

skia::RefPtr<SkImage> first = CreateDiscardableImage(gfx::Size(50, 50));
skia::RefPtr<SkImage> second = CreateDiscardableImage(gfx::Size(50, 50));
skia::RefPtr<SkImage> third = CreateDiscardableImage(gfx::Size(50, 50));
skia::RefPtr<SkImage> fourth = CreateDiscardableImage(gfx::Size(50, 1));
skia::RefPtr<SkImage> fifth = CreateDiscardableImage(gfx::Size(10, 10));
skia::RefPtr<SkImage> sixth = CreateDiscardableImage(gfx::Size(10, 10));

canvas->save();

// At (0, 0).
canvas->drawImage(first.get(), 0, 0);
canvas->translate(25, 0);
// At (25, 0).
canvas->drawImage(second.get(), 0, 0);
canvas->translate(0, 50);
// At (50, 50).
canvas->drawImage(third.get(), 25, 0);

canvas->restore();
canvas->save();

canvas->translate(1, 0);
canvas->rotate(90);
// At (1, 0), rotated 90 degrees
canvas->drawImage(fourth.get(), 0, 0);

canvas->restore();
canvas->save();

canvas->scale(5.f, 6.f);
// At (0, 0), scaled by 5 and 6
canvas->drawImage(fifth.get(), 0, 0);

canvas->restore();

canvas->rotate(27);
canvas->scale(3.3f, 0.4f);

canvas->drawImage(sixth.get(), 0, 0);

canvas->restore();

skia::RefPtr<SkPicture> picture =
skia::AdoptRef(StopRecording(&recorder, canvas));

std::vector<skia::DiscardableImageUtils::PositionImage> images;
skia::DiscardableImageUtils::GatherDiscardableImages(picture.get(), &images);

EXPECT_EQ(6u, images.size());
EXPECT_FLOAT_RECT_EQ(SkRect::MakeXYWH(0, 0, 50, 50), images[0].image_rect);
VerifyScales(1.f, 1.f, images[0].matrix, __LINE__);
EXPECT_EQ(kNone_SkFilterQuality, images[0].filter_quality);
EXPECT_FLOAT_RECT_EQ(gfx::RectF(25, 0, 50, 50), images[1].image_rect);
VerifyScales(1.f, 1.f, images[1].matrix, __LINE__);
EXPECT_EQ(kNone_SkFilterQuality, images[1].filter_quality);
EXPECT_FLOAT_RECT_EQ(gfx::RectF(50, 50, 50, 50), images[2].image_rect);
VerifyScales(1.f, 1.f, images[2].matrix, __LINE__);
EXPECT_EQ(kNone_SkFilterQuality, images[2].filter_quality);
EXPECT_FLOAT_RECT_EQ(gfx::RectF(0, 0, 1, 50), images[3].image_rect);
VerifyScales(1.f, 1.f, images[3].matrix, __LINE__);
EXPECT_EQ(kNone_SkFilterQuality, images[3].filter_quality);
EXPECT_FLOAT_RECT_EQ(gfx::RectF(0, 0, 50, 60), images[4].image_rect);
VerifyScales(5.f, 6.f, images[4].matrix, __LINE__);
EXPECT_EQ(kNone_SkFilterQuality, images[4].filter_quality);
EXPECT_FLOAT_RECT_EQ(gfx::RectF(-1.8159621f, 0, 31.219175f, 18.545712f),
images[5].image_rect);
VerifyScales(3.3f, 0.4f, images[5].matrix, __LINE__);
EXPECT_EQ(kNone_SkFilterQuality, images[5].filter_quality);
}

TEST(DiscardableImageUtilsTest, DrawImageRect) {
gfx::Rect layer_rect(0, 0, 256, 256);

SkPictureRecorder recorder;
SkCanvas* canvas = StartRecording(&recorder, layer_rect);

skia::RefPtr<SkImage> first = CreateDiscardableImage(gfx::Size(50, 50));
skia::RefPtr<SkImage> second = CreateDiscardableImage(gfx::Size(50, 50));
skia::RefPtr<SkImage> third = CreateDiscardableImage(gfx::Size(50, 50));

canvas->save();

SkPaint paint;

// (0, 0, 100, 100).
canvas->drawImageRect(first.get(), SkRect::MakeWH(100, 100), &paint);
canvas->translate(25, 0);
// (75, 50, 10, 10).
canvas->drawImageRect(second.get(), SkRect::MakeXYWH(50, 50, 10, 10), &paint);
canvas->translate(5, 50);
// (0, 30, 100, 100).
canvas->drawImageRect(third.get(), SkRect::MakeXYWH(-30, -20, 100, 100),
&paint);

canvas->restore();

skia::RefPtr<SkPicture> picture =
skia::AdoptRef(StopRecording(&recorder, canvas));

std::vector<skia::DiscardableImageUtils::PositionImage> images;
skia::DiscardableImageUtils::GatherDiscardableImages(picture.get(), &images);

EXPECT_EQ(3u, images.size());
EXPECT_FLOAT_RECT_EQ(gfx::RectF(0, 0, 100, 100), images[0].image_rect);
VerifyScales(2.f, 2.f, images[0].matrix, __LINE__);
EXPECT_EQ(kNone_SkFilterQuality, images[0].filter_quality);
EXPECT_FLOAT_RECT_EQ(gfx::RectF(75, 50, 10, 10), images[1].image_rect);
VerifyScales(0.2f, 0.2f, images[1].matrix, __LINE__);
EXPECT_EQ(kNone_SkFilterQuality, images[1].filter_quality);
EXPECT_FLOAT_RECT_EQ(gfx::RectF(0, 30, 100, 100), images[2].image_rect);
VerifyScales(2.f, 2.f, images[2].matrix, __LINE__);
EXPECT_EQ(kNone_SkFilterQuality, images[2].filter_quality);
}

} // namespace skia
1 change: 1 addition & 0 deletions skia/skia_chrome.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
'ext/platform_device_linux.cc',
'ext/platform_device_mac.cc',
'ext/platform_device_win.cc',
'ext/discardable_image_utils.cc',
'ext/recursive_gaussian_convolution.cc',
'ext/SkDiscardableMemory_chrome.cc',
'ext/SkMemory_new_handler.cpp',
Expand Down
1 change: 1 addition & 0 deletions skia/skia_tests.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
'ext/analysis_canvas_unittest.cc',
'ext/bitmap_platform_device_mac_unittest.cc',
'ext/convolver_unittest.cc',
'ext/discardable_image_utils_unittest.cc',
'ext/image_operations_unittest.cc',
'ext/pixel_ref_utils_unittest.cc',
'ext/platform_canvas_unittest.cc',
Expand Down

0 comments on commit 47c0625

Please sign in to comment.