blob: 602a906210eddcf20518201ec683b570ff4233bb [file] [log] [blame]
// 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 "platform/graphics/paint/DrawingDisplayItem.h"
#include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/paint/PaintCanvas.h"
#include "public/platform/WebDisplayItemList.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkData.h"
namespace blink {
void DrawingDisplayItem::Replay(GraphicsContext& context) const {
if (record_)
context.DrawRecord(record_);
}
void DrawingDisplayItem::AppendToWebDisplayItemList(
const IntRect& visual_rect,
WebDisplayItemList* list) const {
if (record_) {
list->AppendDrawingItem(visual_rect, record_,
EnclosingIntRect(record_bounds_));
}
}
bool DrawingDisplayItem::DrawsContent() const {
return record_.get();
}
int DrawingDisplayItem::NumberOfSlowPaths() const {
return record_ ? record_->numSlowPaths() : 0;
}
#ifndef NDEBUG
void DrawingDisplayItem::DumpPropertiesAsDebugString(
StringBuilder& string_builder) const {
DisplayItem::DumpPropertiesAsDebugString(string_builder);
if (record_) {
string_builder.Append(String::Format(
", rect: [%f,%f %fx%f]", record_bounds_.X(), record_bounds_.Y(),
record_bounds_.Width(), record_bounds_.Height()));
}
}
#endif
static bool RecordsEqual(sk_sp<const PaintRecord> record1,
sk_sp<const PaintRecord> record2,
const FloatRect& bounds) {
if (record1->size() != record2->size())
return false;
// TODO(enne): PaintRecord should have an operator==
sk_sp<SkData> data1 = ToSkPicture(record1, bounds)->serialize();
sk_sp<SkData> data2 = ToSkPicture(record2, bounds)->serialize();
return data1->equals(data2.get());
}
static SkBitmap RecordToBitmap(sk_sp<const PaintRecord> record,
const FloatRect& bounds) {
SkBitmap bitmap;
bitmap.allocPixels(
SkImageInfo::MakeN32Premul(bounds.Width(), bounds.Height()));
SkiaPaintCanvas canvas(bitmap);
canvas.clear(SK_ColorTRANSPARENT);
canvas.translate(-bounds.X(), -bounds.Y());
canvas.drawPicture(std::move(record));
return bitmap;
}
static bool BitmapsEqual(sk_sp<const PaintRecord> record1,
sk_sp<const PaintRecord> record2,
const FloatRect& bounds) {
SkBitmap bitmap1 = RecordToBitmap(record1, bounds);
SkBitmap bitmap2 = RecordToBitmap(record2, bounds);
int mismatch_count = 0;
const int kMaxMismatches = 10;
for (int y = 0; y < bounds.Height() && mismatch_count < kMaxMismatches; ++y) {
for (int x = 0; x < bounds.Width() && mismatch_count < kMaxMismatches;
++x) {
SkColor pixel1 = bitmap1.getColor(x, y);
SkColor pixel2 = bitmap2.getColor(x, y);
if (pixel1 != pixel2) {
LOG(ERROR) << "x=" << x << " y=" << y << " " << std::hex << pixel1
<< " vs " << std::hex << pixel2;
++mismatch_count;
}
}
}
return !mismatch_count;
}
bool DrawingDisplayItem::Equals(const DisplayItem& other) const {
if (!DisplayItem::Equals(other))
return false;
const sk_sp<const PaintRecord>& record = this->GetPaintRecord();
const FloatRect& bounds = this->GetPaintRecordBounds();
const sk_sp<const PaintRecord>& other_record =
static_cast<const DrawingDisplayItem&>(other).GetPaintRecord();
const FloatRect& other_bounds =
static_cast<const DrawingDisplayItem&>(other).GetPaintRecordBounds();
if (!record && !other_record)
return true;
if (!record || !other_record)
return false;
if (bounds != other_bounds)
return false;
if (RecordsEqual(record, other_record, bounds))
return true;
// Sometimes the client may produce different records for the same visual
// result, which should be treated as equal.
return BitmapsEqual(std::move(record), std::move(other_record), bounds);
}
} // namespace blink