| // 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 |