blob: 05f254c6f2397c7cd71053b4a4fc33aec3eb0757 [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 "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"
#include "third_party/skia/include/core/SkPictureAnalyzer.h"
namespace blink {
void DrawingDisplayItem::replay(GraphicsContext& context) const {
if (m_picture)
context.drawPicture(m_picture.get());
}
void DrawingDisplayItem::appendToWebDisplayItemList(
const IntRect& visualRect,
WebDisplayItemList* list) const {
if (m_picture)
list->appendDrawingItem(visualRect, m_picture);
}
bool DrawingDisplayItem::drawsContent() const {
return m_picture.get();
}
void DrawingDisplayItem::analyzeForGpuRasterization(
SkPictureGpuAnalyzer& analyzer) const {
analyzer.analyzePicture(m_picture.get());
}
#ifndef NDEBUG
void DrawingDisplayItem::dumpPropertiesAsDebugString(
StringBuilder& stringBuilder) const {
DisplayItem::dumpPropertiesAsDebugString(stringBuilder);
if (m_picture) {
stringBuilder.append(
String::format(", rect: [%f,%f %fx%f]", m_picture->cullRect().x(),
m_picture->cullRect().y(), m_picture->cullRect().width(),
m_picture->cullRect().height()));
}
}
#endif
static bool picturesEqual(const SkPicture* picture1,
const SkPicture* picture2) {
if (picture1->approximateOpCount() != picture2->approximateOpCount())
return false;
sk_sp<SkData> data1 = picture1->serialize();
sk_sp<SkData> data2 = picture2->serialize();
return data1->equals(data2.get());
}
static SkBitmap pictureToBitmap(const SkPicture* picture) {
SkBitmap bitmap;
SkRect rect = picture->cullRect();
bitmap.allocPixels(SkImageInfo::MakeN32Premul(rect.width(), rect.height()));
SkCanvas canvas(bitmap);
canvas.clear(SK_ColorTRANSPARENT);
canvas.translate(-rect.x(), -rect.y());
canvas.drawPicture(picture);
return bitmap;
}
static bool bitmapsEqual(const SkPicture* picture1, const SkPicture* picture2) {
SkRect rect = picture1->cullRect();
if (rect != picture2->cullRect())
return false;
SkBitmap bitmap1 = pictureToBitmap(picture1);
SkBitmap bitmap2 = pictureToBitmap(picture2);
bitmap1.lockPixels();
bitmap2.lockPixels();
int mismatchCount = 0;
const int maxMismatches = 10;
for (int y = 0; y < rect.height() && mismatchCount < maxMismatches; ++y) {
for (int x = 0; x < rect.width() && mismatchCount < maxMismatches; ++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;
++mismatchCount;
}
}
}
bitmap1.unlockPixels();
bitmap2.unlockPixels();
return !mismatchCount;
}
bool DrawingDisplayItem::equals(const DisplayItem& other) const {
if (!DisplayItem::equals(other))
return false;
const SkPicture* picture = this->picture();
const SkPicture* otherPicture =
static_cast<const DrawingDisplayItem&>(other).picture();
if (!picture && !otherPicture)
return true;
if (!picture || !otherPicture)
return false;
if (picturesEqual(picture, otherPicture))
return true;
// Sometimes the client may produce different pictures for the same visual
// result, which should be treated as equal.
return bitmapsEqual(picture, otherPicture);
}
} // namespace blink