// Copyright (c) 2013 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 "ui/surface/transport_dib.h" #include #include #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/memory/shared_memory_mapping.h" #include "base/memory/unsafe_shared_memory_region.h" #include "base/numerics/checked_math.h" #include "build/build_config.h" #include "skia/ext/platform_canvas.h" TransportDIB::TransportDIB(base::UnsafeSharedMemoryRegion region) : shm_region_(std::move(region)) {} TransportDIB::~TransportDIB() = default; // static std::unique_ptr TransportDIB::Map( base::UnsafeSharedMemoryRegion region) { std::unique_ptr dib = CreateWithHandle(std::move(region)); if (!dib->Map()) return nullptr; return dib; } // static std::unique_ptr TransportDIB::CreateWithHandle( base::UnsafeSharedMemoryRegion region) { return base::WrapUnique(new TransportDIB(std::move(region))); } std::unique_ptr TransportDIB::GetPlatformCanvas(int w, int h, bool opaque) { if (!shm_region_.IsValid()) return nullptr; // Calculate the size for the memory region backing the canvas. If not valid // then fail gracefully. size_t canvas_size; // 32-bit RGB data. A size_t causes a type change from int when multiplying. const size_t bpp = 4; if (!base::CheckMul(h, base::CheckMul(w, bpp)).AssignIfValid(&canvas_size)) return nullptr; #if BUILDFLAG(IS_WIN) // This DIB already mapped the file into this process, but PlatformCanvas // will map it again. DCHECK(!memory()) << "Mapped file twice in the same process."; // We can't check the canvas size before mapping, but it's safe because // Windows will fail to map the section if the dimensions of the canvas // are too large. std::unique_ptr canvas = skia::CreatePlatformCanvasWithSharedSection( w, h, opaque, shm_region_.GetPlatformHandle(), skia::RETURN_NULL_ON_FAILURE); if (canvas) size_ = canvas_size; return canvas; #else if ((!memory() && !Map()) || !VerifyCanvasSize(w, h)) return nullptr; return skia::CreatePlatformCanvasWithPixels(w, h, opaque, static_cast(memory()), skia::RETURN_NULL_ON_FAILURE); #endif } bool TransportDIB::Map() { if (!shm_region_.IsValid()) return false; if (memory()) return true; shm_mapping_ = shm_region_.Map(); if (!shm_mapping_.IsValid()) { PLOG(ERROR) << "Failed to map transport DIB"; return false; } size_ = shm_mapping_.size(); return true; } void* TransportDIB::memory() const { return shm_mapping_.IsValid() ? shm_mapping_.memory() : nullptr; } base::UnsafeSharedMemoryRegion* TransportDIB::shared_memory_region() { return &shm_region_; } // static bool TransportDIB::VerifyCanvasSize(int w, int h) { if (w <= 0 || h <= 0) return false; size_t canvas_size; // 32-bit RGB data. A size_t causes a type change from int when multiplying. const size_t bpp = 4; if (!base::CheckMul(h, base::CheckMul(w, bpp)).AssignIfValid(&canvas_size)) return false; return canvas_size <= size_; }