| Index: components/test_runner/pixel_dump.cc
|
| diff --git a/components/test_runner/pixel_dump.cc b/components/test_runner/pixel_dump.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1b49c178325bd0a49a39c2af9f1cd63807e11009
|
| --- /dev/null
|
| +++ b/components/test_runner/pixel_dump.cc
|
| @@ -0,0 +1,203 @@
|
| +// 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 "components/test_runner/pixel_dump.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/bind_helpers.h"
|
| +#include "base/callback.h"
|
| +#include "base/logging.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/thread_task_runner_handle.h"
|
| +#include "base/trace_event/trace_event.h"
|
| +#include "components/test_runner/layout_test_runtime_flags.h"
|
| +// FIXME: Including platform_canvas.h here is a layering violation.
|
| +#include "skia/ext/platform_canvas.h"
|
| +#include "third_party/WebKit/public/platform/Platform.h"
|
| +#include "third_party/WebKit/public/platform/WebClipboard.h"
|
| +#include "third_party/WebKit/public/platform/WebCompositeAndReadbackAsyncCallback.h"
|
| +#include "third_party/WebKit/public/platform/WebData.h"
|
| +#include "third_party/WebKit/public/platform/WebImage.h"
|
| +#include "third_party/WebKit/public/platform/WebPoint.h"
|
| +#include "third_party/WebKit/public/web/WebFrame.h"
|
| +#include "third_party/WebKit/public/web/WebPagePopup.h"
|
| +#include "third_party/WebKit/public/web/WebPrintParams.h"
|
| +#include "third_party/WebKit/public/web/WebView.h"
|
| +#include "ui/gfx/geometry/point.h"
|
| +
|
| +namespace test_runner {
|
| +
|
| +namespace {
|
| +
|
| +struct PixelsDumpRequest {
|
| + PixelsDumpRequest(blink::WebView* web_view,
|
| + const LayoutTestRuntimeFlags& layout_test_runtime_flags,
|
| + const base::Callback<void(const SkBitmap&)>& callback)
|
| + : web_view(web_view),
|
| + layout_test_runtime_flags(layout_test_runtime_flags),
|
| + callback(callback) {}
|
| +
|
| + blink::WebView* web_view;
|
| + const LayoutTestRuntimeFlags& layout_test_runtime_flags;
|
| + base::Callback<void(const SkBitmap&)> callback;
|
| +};
|
| +
|
| +class CaptureCallback : public blink::WebCompositeAndReadbackAsyncCallback {
|
| + public:
|
| + CaptureCallback(const base::Callback<void(const SkBitmap&)>& callback);
|
| + virtual ~CaptureCallback();
|
| +
|
| + void set_wait_for_popup(bool wait) { wait_for_popup_ = wait; }
|
| + void set_popup_position(const gfx::Point& position) {
|
| + popup_position_ = position;
|
| + }
|
| +
|
| + // WebCompositeAndReadbackAsyncCallback implementation.
|
| + void didCompositeAndReadback(const SkBitmap& bitmap) override;
|
| +
|
| + private:
|
| + base::Callback<void(const SkBitmap&)> callback_;
|
| + SkBitmap main_bitmap_;
|
| + bool wait_for_popup_;
|
| + gfx::Point popup_position_;
|
| +};
|
| +
|
| +void DrawSelectionRect(const PixelsDumpRequest& dump_request,
|
| + SkCanvas* canvas) {
|
| + // See if we need to draw the selection bounds rect. Selection bounds
|
| + // rect is the rect enclosing the (possibly transformed) selection.
|
| + // The rect should be drawn after everything is laid out and painted.
|
| + if (!dump_request.layout_test_runtime_flags.dump_selection_rect())
|
| + return;
|
| + // If there is a selection rect - draw a red 1px border enclosing rect
|
| + blink::WebRect wr = dump_request.web_view->mainFrame()->selectionBoundsRect();
|
| + if (wr.isEmpty())
|
| + return;
|
| + // Render a red rectangle bounding selection rect
|
| + SkPaint paint;
|
| + paint.setColor(0xFFFF0000); // Fully opaque red
|
| + paint.setStyle(SkPaint::kStroke_Style);
|
| + paint.setFlags(SkPaint::kAntiAlias_Flag);
|
| + paint.setStrokeWidth(1.0f);
|
| + SkIRect rect; // Bounding rect
|
| + rect.set(wr.x, wr.y, wr.x + wr.width, wr.y + wr.height);
|
| + canvas->drawIRect(rect, paint);
|
| +}
|
| +
|
| +void CapturePixelsForPrinting(scoped_ptr<PixelsDumpRequest> dump_request) {
|
| + dump_request->web_view->updateAllLifecyclePhases();
|
| +
|
| + blink::WebSize page_size_in_pixels = dump_request->web_view->size();
|
| + blink::WebFrame* web_frame = dump_request->web_view->mainFrame();
|
| +
|
| + int page_count = web_frame->printBegin(page_size_in_pixels);
|
| + int totalHeight = page_count * (page_size_in_pixels.height + 1) - 1;
|
| +
|
| + bool is_opaque = false;
|
| + skia::RefPtr<SkCanvas> canvas(skia::AdoptRef(skia::TryCreateBitmapCanvas(
|
| + page_size_in_pixels.width, totalHeight, is_opaque)));
|
| + if (!canvas) {
|
| + dump_request->callback.Run(SkBitmap());
|
| + return;
|
| + }
|
| + web_frame->printPagesWithBoundaries(canvas.get(), page_size_in_pixels);
|
| + web_frame->printEnd();
|
| +
|
| + DrawSelectionRect(*dump_request, canvas.get());
|
| + const SkBitmap bitmap = skia::ReadPixels(canvas.get());
|
| + dump_request->callback.Run(bitmap);
|
| +}
|
| +
|
| +CaptureCallback::CaptureCallback(
|
| + const base::Callback<void(const SkBitmap&)>& callback)
|
| + : callback_(callback), wait_for_popup_(false) {}
|
| +
|
| +CaptureCallback::~CaptureCallback() {}
|
| +
|
| +void CaptureCallback::didCompositeAndReadback(const SkBitmap& bitmap) {
|
| + TRACE_EVENT2("shell", "CaptureCallback::didCompositeAndReadback", "x",
|
| + bitmap.info().width(), "y", bitmap.info().height());
|
| + if (!wait_for_popup_) {
|
| + callback_.Run(bitmap);
|
| + delete this;
|
| + return;
|
| + }
|
| + if (main_bitmap_.isNull()) {
|
| + bitmap.deepCopyTo(&main_bitmap_);
|
| + return;
|
| + }
|
| + SkCanvas canvas(main_bitmap_);
|
| + canvas.drawBitmap(bitmap, popup_position_.x(), popup_position_.y());
|
| + callback_.Run(main_bitmap_);
|
| + delete this;
|
| +}
|
| +
|
| +void DidCapturePixelsAsync(scoped_ptr<PixelsDumpRequest> dump_request,
|
| + const SkBitmap& bitmap) {
|
| + SkCanvas canvas(bitmap);
|
| + DrawSelectionRect(*dump_request, &canvas);
|
| + if (!dump_request->callback.is_null())
|
| + dump_request->callback.Run(bitmap);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +void DumpPixelsAsync(blink::WebView* web_view,
|
| + const LayoutTestRuntimeFlags& layout_test_runtime_flags,
|
| + float device_scale_factor_for_test,
|
| + const base::Callback<void(const SkBitmap&)>& callback) {
|
| + TRACE_EVENT0("shell", "WebTestProxyBase::CapturePixelsAsync");
|
| + DCHECK(!callback.is_null());
|
| + DCHECK(!layout_test_runtime_flags.dump_drag_image());
|
| +
|
| + scoped_ptr<PixelsDumpRequest> pixels_request(
|
| + new PixelsDumpRequest(web_view, layout_test_runtime_flags, callback));
|
| +
|
| + if (layout_test_runtime_flags.is_printing()) {
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| + FROM_HERE, base::Bind(&CapturePixelsForPrinting,
|
| + base::Passed(std::move(pixels_request))));
|
| + return;
|
| + }
|
| +
|
| + CaptureCallback* capture_callback = new CaptureCallback(base::Bind(
|
| + &DidCapturePixelsAsync, base::Passed(std::move(pixels_request))));
|
| + web_view->compositeAndReadbackAsync(capture_callback);
|
| + if (blink::WebPagePopup* popup = web_view->pagePopup()) {
|
| + capture_callback->set_wait_for_popup(true);
|
| + blink::WebPoint position = popup->positionRelativeToOwner();
|
| + position.x *= device_scale_factor_for_test;
|
| + position.y *= device_scale_factor_for_test;
|
| + capture_callback->set_popup_position(position);
|
| + popup->compositeAndReadbackAsync(capture_callback);
|
| + }
|
| +}
|
| +
|
| +void CopyImageAtAndCapturePixels(
|
| + blink::WebView* web_view,
|
| + int x,
|
| + int y,
|
| + const base::Callback<void(const SkBitmap&)>& callback) {
|
| + DCHECK(!callback.is_null());
|
| + uint64_t sequence_number =
|
| + blink::Platform::current()->clipboard()->sequenceNumber(
|
| + blink::WebClipboard::Buffer());
|
| + web_view->copyImageAt(blink::WebPoint(x, y));
|
| + if (sequence_number ==
|
| + blink::Platform::current()->clipboard()->sequenceNumber(
|
| + blink::WebClipboard::Buffer())) {
|
| + SkBitmap emptyBitmap;
|
| + callback.Run(emptyBitmap);
|
| + return;
|
| + }
|
| +
|
| + blink::WebData data = blink::Platform::current()->clipboard()->readImage(
|
| + blink::WebClipboard::Buffer());
|
| + blink::WebImage image = blink::WebImage::fromData(data, blink::WebSize());
|
| + const SkBitmap& bitmap = image.getSkBitmap();
|
| + SkAutoLockPixels autoLock(bitmap);
|
| + callback.Run(bitmap);
|
| +}
|
| +
|
| +} // namespace test_runner
|
|
|