transport_dib.cc 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // Copyright (c) 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/surface/transport_dib.h"
  5. #include <stddef.h>
  6. #include <memory>
  7. #include "base/logging.h"
  8. #include "base/memory/ptr_util.h"
  9. #include "base/memory/shared_memory_mapping.h"
  10. #include "base/memory/unsafe_shared_memory_region.h"
  11. #include "base/numerics/checked_math.h"
  12. #include "build/build_config.h"
  13. #include "skia/ext/platform_canvas.h"
  14. TransportDIB::TransportDIB(base::UnsafeSharedMemoryRegion region)
  15. : shm_region_(std::move(region)) {}
  16. TransportDIB::~TransportDIB() = default;
  17. // static
  18. std::unique_ptr<TransportDIB> TransportDIB::Map(
  19. base::UnsafeSharedMemoryRegion region) {
  20. std::unique_ptr<TransportDIB> dib = CreateWithHandle(std::move(region));
  21. if (!dib->Map())
  22. return nullptr;
  23. return dib;
  24. }
  25. // static
  26. std::unique_ptr<TransportDIB> TransportDIB::CreateWithHandle(
  27. base::UnsafeSharedMemoryRegion region) {
  28. return base::WrapUnique(new TransportDIB(std::move(region)));
  29. }
  30. std::unique_ptr<SkCanvas> TransportDIB::GetPlatformCanvas(int w,
  31. int h,
  32. bool opaque) {
  33. if (!shm_region_.IsValid())
  34. return nullptr;
  35. // Calculate the size for the memory region backing the canvas. If not valid
  36. // then fail gracefully.
  37. size_t canvas_size;
  38. // 32-bit RGB data. A size_t causes a type change from int when multiplying.
  39. const size_t bpp = 4;
  40. if (!base::CheckMul(h, base::CheckMul(w, bpp)).AssignIfValid(&canvas_size))
  41. return nullptr;
  42. #if BUILDFLAG(IS_WIN)
  43. // This DIB already mapped the file into this process, but PlatformCanvas
  44. // will map it again.
  45. DCHECK(!memory()) << "Mapped file twice in the same process.";
  46. // We can't check the canvas size before mapping, but it's safe because
  47. // Windows will fail to map the section if the dimensions of the canvas
  48. // are too large.
  49. std::unique_ptr<SkCanvas> canvas =
  50. skia::CreatePlatformCanvasWithSharedSection(
  51. w, h, opaque, shm_region_.GetPlatformHandle(),
  52. skia::RETURN_NULL_ON_FAILURE);
  53. if (canvas)
  54. size_ = canvas_size;
  55. return canvas;
  56. #else
  57. if ((!memory() && !Map()) || !VerifyCanvasSize(w, h))
  58. return nullptr;
  59. return skia::CreatePlatformCanvasWithPixels(w, h, opaque,
  60. static_cast<uint8_t*>(memory()),
  61. skia::RETURN_NULL_ON_FAILURE);
  62. #endif
  63. }
  64. bool TransportDIB::Map() {
  65. if (!shm_region_.IsValid())
  66. return false;
  67. if (memory())
  68. return true;
  69. shm_mapping_ = shm_region_.Map();
  70. if (!shm_mapping_.IsValid()) {
  71. PLOG(ERROR) << "Failed to map transport DIB";
  72. return false;
  73. }
  74. size_ = shm_mapping_.size();
  75. return true;
  76. }
  77. void* TransportDIB::memory() const {
  78. return shm_mapping_.IsValid() ? shm_mapping_.memory() : nullptr;
  79. }
  80. base::UnsafeSharedMemoryRegion* TransportDIB::shared_memory_region() {
  81. return &shm_region_;
  82. }
  83. // static
  84. bool TransportDIB::VerifyCanvasSize(int w, int h) {
  85. if (w <= 0 || h <= 0)
  86. return false;
  87. size_t canvas_size;
  88. // 32-bit RGB data. A size_t causes a type change from int when multiplying.
  89. const size_t bpp = 4;
  90. if (!base::CheckMul(h, base::CheckMul(w, bpp)).AssignIfValid(&canvas_size))
  91. return false;
  92. return canvas_size <= size_;
  93. }