blob: d3a49ed8be8dc11b86af67cdd600b05ddc0fc486 [file] [log] [blame]
// Copyright 2018 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/viz/host/layered_window_updater_impl.h"
#include "base/memory/shared_memory.h"
#include "components/viz/common/resources/resource_format.h"
#include "components/viz/common/resources/resource_sizes.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "skia/ext/platform_canvas.h"
#include "skia/ext/skia_utils_win.h"
#include "third_party/skia/include/core/SkCanvas.h"
namespace viz {
LayeredWindowUpdaterImpl::LayeredWindowUpdaterImpl(
HWND hwnd,
mojom::LayeredWindowUpdaterRequest request)
: hwnd_(hwnd), binding_(this, std::move(request)) {}
LayeredWindowUpdaterImpl::~LayeredWindowUpdaterImpl() = default;
void LayeredWindowUpdaterImpl::OnAllocatedSharedMemory(
const gfx::Size& pixel_size,
mojo::ScopedSharedBufferHandle scoped_buffer_handle) {
canvas_.reset();
// Make sure |pixel_size| is sane.
size_t expected_bytes;
bool size_result = ResourceSizes::MaybeSizeInBytes(
pixel_size, ResourceFormat::RGBA_8888, &expected_bytes);
if (!size_result)
return;
base::SharedMemoryHandle shm_handle;
MojoResult unwrap_result = mojo::UnwrapSharedMemoryHandle(
std::move(scoped_buffer_handle), &shm_handle, nullptr, nullptr);
if (unwrap_result != MOJO_RESULT_OK)
return;
// The SkCanvas maps shared memory on creation and unmaps on destruction.
canvas_ = skia::CreatePlatformCanvasWithSharedSection(
pixel_size.width(), pixel_size.height(), true, shm_handle.GetHandle(),
skia::RETURN_NULL_ON_FAILURE);
shm_handle.Close();
}
void LayeredWindowUpdaterImpl::Draw(DrawCallback draw_callback) {
TRACE_EVENT0("viz", "LayeredWindowUpdaterImpl::Draw");
if (!canvas_) {
std::move(draw_callback).Run();
return;
}
// Set WS_EX_LAYERED extended window style if not already set.
DWORD style = GetWindowLong(hwnd_, GWL_EXSTYLE);
DCHECK(!(style & WS_EX_COMPOSITED));
if (!(style & WS_EX_LAYERED))
SetWindowLong(hwnd_, GWL_EXSTYLE, style | WS_EX_LAYERED);
// Draw to the HWND. If |canvas_| size doesn't match HWND size then it will be
// clipped or guttered accordingly.
RECT wr;
GetWindowRect(hwnd_, &wr);
SIZE size = {wr.right - wr.left, wr.bottom - wr.top};
POINT position = {wr.left, wr.top};
POINT zero = {0, 0};
BLENDFUNCTION blend = {AC_SRC_OVER, 0x00, 0xFF, AC_SRC_ALPHA};
HDC dib_dc = skia::GetNativeDrawingContext(canvas_.get());
UpdateLayeredWindow(hwnd_, nullptr, &position, &size, dib_dc, &zero,
RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA);
std::move(draw_callback).Run();
}
} // namespace viz