blob: f39a0bf581f26e3f2cbeb93877536fafc5fde1c3 [file] [log] [blame]
// 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 "platform/testing/PictureMatchers.h"
#include <utility>
#include "platform/geometry/FloatQuad.h"
#include "platform/geometry/FloatRect.h"
#include "platform/wtf/Vector.h"
#include "platform/wtf/text/WTFString.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPicture.h"
namespace blink {
namespace {
struct QuadWithColor {
FloatQuad quad;
Color color;
};
class DrawsRectangleCanvas : public SkCanvas {
public:
DrawsRectangleCanvas()
: SkCanvas(800, 600),
save_count_(0),
alpha_(255),
alpha_save_layer_count_(-1) {}
const Vector<QuadWithColor>& QuadsWithColor() const { return quads_; }
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
SkRect clipped_rect(rect);
for (Vector<ClipAndIndex>::const_reverse_iterator clip = clips_.rbegin();
clip != clips_.rend(); clip++) {
if (SkRect::Intersects(rect, clip->rect))
CHECK(clipped_rect.intersect(clip->rect));
}
SkPoint quad[4];
getTotalMatrix().mapRectToQuad(quad, clipped_rect);
QuadWithColor quad_with_color;
quad_with_color.quad = FloatQuad(quad);
unsigned paint_alpha = static_cast<unsigned>(paint.getAlpha());
SkPaint paint_with_alpha(paint);
paint_with_alpha.setAlpha(static_cast<U8CPU>(alpha_ * paint_alpha / 255));
quad_with_color.color = Color(paint_with_alpha.getColor());
quads_.push_back(quad_with_color);
SkCanvas::onDrawRect(clipped_rect, paint);
}
SkCanvas::SaveLayerStrategy getSaveLayerStrategy(
const SaveLayerRec& rec) override {
save_count_++;
unsigned layer_alpha = static_cast<unsigned>(rec.fPaint->getAlpha());
if (layer_alpha < 255) {
DCHECK_EQ(alpha_save_layer_count_, -1);
alpha_save_layer_count_ = save_count_;
alpha_ = layer_alpha;
}
return SkCanvas::getSaveLayerStrategy(rec);
}
void willSave() override {
save_count_++;
SkCanvas::willSave();
}
void willRestore() override {
DCHECK_GT(save_count_, 0);
if (clips_.size() && save_count_ == clips_.back().save_count)
clips_.pop_back();
if (alpha_save_layer_count_ == save_count_) {
alpha_ = 255;
alpha_save_layer_count_ = -1;
}
save_count_--;
SkCanvas::willRestore();
}
void onClipRect(const SkRect& rect,
SkClipOp op,
ClipEdgeStyle style) override {
ClipAndIndex clip_struct;
clip_struct.rect = rect;
clip_struct.save_count = save_count_;
clips_.push_back(clip_struct);
SkCanvas::onClipRect(rect, op, style);
}
struct ClipAndIndex {
SkRect rect;
int save_count;
};
private:
Vector<QuadWithColor> quads_;
Vector<ClipAndIndex> clips_;
int save_count_;
unsigned alpha_;
int alpha_save_layer_count_;
};
class DrawsRectanglesMatcher
: public ::testing::MatcherInterface<const SkPicture&> {
public:
DrawsRectanglesMatcher(const Vector<RectWithColor>& rects_with_color)
: rects_with_color_(rects_with_color) {}
bool MatchAndExplain(
const SkPicture& picture,
::testing::MatchResultListener* listener) const override {
DrawsRectangleCanvas canvas;
picture.playback(&canvas);
const auto& quads = canvas.QuadsWithColor();
if (quads.size() != rects_with_color_.size()) {
*listener << "which draws " << quads.size() << " quads";
return false;
}
for (unsigned index = 0; index < quads.size(); index++) {
const auto& quad_with_color = quads[index];
const auto& rect_with_color = rects_with_color_[index];
const FloatRect& rect = quad_with_color.quad.BoundingBox();
if (EnclosingIntRect(rect) != EnclosingIntRect(rect_with_color.rect) ||
quad_with_color.color != rect_with_color.color) {
if (listener->IsInterested()) {
*listener << "at index " << index << " which draws ";
PrintTo(rect, listener->stream());
*listener << " with color "
<< quad_with_color.color.Serialized().Ascii().data()
<< "\n";
}
return false;
}
}
return true;
}
void DescribeTo(::std::ostream* os) const override {
*os << "\n";
for (unsigned index = 0; index < rects_with_color_.size(); index++) {
const auto& rect_with_color = rects_with_color_[index];
*os << "at index " << index << " rect draws ";
PrintTo(rect_with_color.rect, os);
*os << " with color " << rect_with_color.color.Serialized().Ascii().data()
<< "\n";
}
}
private:
const Vector<RectWithColor> rects_with_color_;
};
} // namespace
::testing::Matcher<const SkPicture&> DrawsRectangle(const FloatRect& rect,
Color color) {
Vector<RectWithColor> rects_with_color;
rects_with_color.push_back(RectWithColor(rect, color));
return ::testing::MakeMatcher(new DrawsRectanglesMatcher(rects_with_color));
}
::testing::Matcher<const SkPicture&> DrawsRectangles(
const Vector<RectWithColor>& rects_with_color) {
return ::testing::MakeMatcher(new DrawsRectanglesMatcher(rects_with_color));
}
} // namespace blink