tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ImageUtils.cpp (7037B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/dom/ImageUtils.h"
      8 
      9 #include "ImageContainer.h"
     10 #include "Intervals.h"
     11 #include "mozilla/dom/ImageBitmapBinding.h"
     12 
     13 using namespace mozilla::layers;
     14 using namespace mozilla::gfx;
     15 
     16 namespace mozilla::dom {
     17 
     18 static Maybe<ImageBitmapFormat> GetImageBitmapFormatFromSurfaceFromat(
     19    SurfaceFormat aSurfaceFormat) {
     20  switch (aSurfaceFormat) {
     21    case SurfaceFormat::B8G8R8A8:
     22    case SurfaceFormat::B8G8R8X8:
     23      return Some(ImageBitmapFormat::BGRA32);
     24    case SurfaceFormat::R8G8B8A8:
     25    case SurfaceFormat::R8G8B8X8:
     26      return Some(ImageBitmapFormat::RGBA32);
     27    case SurfaceFormat::R8G8B8:
     28      return Some(ImageBitmapFormat::RGB24);
     29    case SurfaceFormat::B8G8R8:
     30      return Some(ImageBitmapFormat::BGR24);
     31    case SurfaceFormat::HSV:
     32      return Some(ImageBitmapFormat::HSV);
     33    case SurfaceFormat::Lab:
     34      return Some(ImageBitmapFormat::Lab);
     35    case SurfaceFormat::Depth:
     36      return Some(ImageBitmapFormat::DEPTH);
     37    case SurfaceFormat::A8:
     38      return Some(ImageBitmapFormat::GRAY8);
     39    case SurfaceFormat::R5G6B5_UINT16:
     40    case SurfaceFormat::R10G10B10A2_UINT32:
     41    case SurfaceFormat::R10G10B10X2_UINT32:
     42    case SurfaceFormat::R16G16B16A16F:
     43    case SurfaceFormat::YUV420:
     44    case SurfaceFormat::NV12:
     45    case SurfaceFormat::P010:
     46    case SurfaceFormat::P016:
     47    case SurfaceFormat::UNKNOWN:
     48    default:
     49      return Nothing();
     50  }
     51 }
     52 
     53 static Maybe<ImageBitmapFormat> GetImageBitmapFormatFromPlanarYCbCrData(
     54    layers::PlanarYCbCrData const* aData) {
     55  MOZ_ASSERT(aData);
     56 
     57  auto ySize = aData->YDataSize();
     58  auto cbcrSize = aData->CbCrDataSize();
     59  media::Interval<uintptr_t> YInterval(
     60      uintptr_t(aData->mYChannel),
     61      uintptr_t(aData->mYChannel) + ySize.height * aData->mYStride),
     62      CbInterval(
     63          uintptr_t(aData -> mCbChannel),
     64          uintptr_t(aData->mCbChannel) + cbcrSize.height * aData->mCbCrStride),
     65      CrInterval(
     66          uintptr_t(aData->mCrChannel),
     67          uintptr_t(aData->mCrChannel) + cbcrSize.height * aData->mCbCrStride);
     68  if (aData->mYSkip == 0 && aData->mCbSkip == 0 &&
     69      aData->mCrSkip == 0) {  // Possibly three planes.
     70    if (!YInterval.Intersects(CbInterval) &&
     71        !CbInterval.Intersects(CrInterval)) {  // Three planes.
     72      switch (aData->mChromaSubsampling) {
     73        case ChromaSubsampling::FULL:
     74          return Some(ImageBitmapFormat::YUV444P);
     75        case ChromaSubsampling::HALF_WIDTH:
     76          return Some(ImageBitmapFormat::YUV422P);
     77        case ChromaSubsampling::HALF_WIDTH_AND_HEIGHT:
     78          return Some(ImageBitmapFormat::YUV420P);
     79        default:
     80          break;
     81      }
     82    }
     83  } else if (aData->mYSkip == 0 && aData->mCbSkip == 1 && aData->mCrSkip == 1 &&
     84             aData->mChromaSubsampling ==
     85                 ChromaSubsampling::HALF_WIDTH_AND_HEIGHT) {  // Possibly two
     86                                                              // planes.
     87    if (!YInterval.Intersects(CbInterval) &&
     88        aData->mCbChannel == aData->mCrChannel - 1) {  // Two planes.
     89      return Some(ImageBitmapFormat::YUV420SP_NV12);   // Y-Cb-Cr
     90    } else if (!YInterval.Intersects(CrInterval) &&
     91               aData->mCrChannel == aData->mCbChannel - 1) {  // Two planes.
     92      return Some(ImageBitmapFormat::YUV420SP_NV21);          // Y-Cr-Cb
     93    }
     94  }
     95 
     96  return Nothing();
     97 }
     98 
     99 // ImageUtils::Impl implements the _generic_ algorithm which always readback
    100 // data in RGBA format into CPU memory.
    101 // Since layers::CairoImage is just a warpper to a DataSourceSurface, the
    102 // implementation of CairoSurfaceImpl is nothing different to the generic
    103 // version.
    104 class ImageUtils::Impl {
    105 public:
    106  explicit Impl(layers::Image* aImage) : mImage(aImage), mSurface(nullptr) {}
    107 
    108  virtual ~Impl() = default;
    109 
    110  virtual Maybe<ImageBitmapFormat> GetFormat() const {
    111    if (DataSourceSurface* surface = Surface()) {
    112      return GetImageBitmapFormatFromSurfaceFromat(surface->GetFormat());
    113    }
    114    return Nothing();
    115  }
    116 
    117  virtual uint32_t GetBufferLength() const {
    118    if (DataSourceSurface* surface = Surface()) {
    119      DataSourceSurface::ScopedMap map(surface, DataSourceSurface::READ);
    120      const uint32_t stride = map.GetStride();
    121      const IntSize size = surface->GetSize();
    122      return (uint32_t)(size.height * stride);
    123    }
    124    return 0;
    125  }
    126 
    127 protected:
    128  Impl() = default;
    129 
    130  DataSourceSurface* Surface() const {
    131    if (mSurface) {
    132      return mSurface.get();
    133    }
    134 
    135    RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface();
    136    if (NS_WARN_IF(!surface)) {
    137      return nullptr;
    138    }
    139 
    140    mSurface = surface->GetDataSurface();
    141    MOZ_ASSERT(mSurface);
    142    return mSurface.get();
    143  }
    144 
    145  RefPtr<layers::Image> mImage;
    146  mutable RefPtr<DataSourceSurface> mSurface;
    147 };
    148 
    149 // YUVImpl is optimized for the layers::PlanarYCbCrImage and layers::NVImage.
    150 // This implementation does not readback data in RGBA format but keep it in YUV
    151 // format family.
    152 class YUVImpl final : public ImageUtils::Impl {
    153 public:
    154  explicit YUVImpl(layers::Image* aImage) : Impl(aImage) {
    155    MOZ_ASSERT(aImage->GetFormat() == ImageFormat::PLANAR_YCBCR ||
    156               aImage->GetFormat() == ImageFormat::NV_IMAGE);
    157  }
    158 
    159  Maybe<ImageBitmapFormat> GetFormat() const override {
    160    return GetImageBitmapFormatFromPlanarYCbCrData(GetPlanarYCbCrData());
    161  }
    162 
    163  uint32_t GetBufferLength() const override {
    164    if (mImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
    165      return mImage->AsPlanarYCbCrImage()->GetDataSize();
    166    }
    167    return mImage->AsNVImage()->GetBufferSize();
    168  }
    169 
    170 private:
    171  const PlanarYCbCrData* GetPlanarYCbCrData() const {
    172    if (mImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
    173      return mImage->AsPlanarYCbCrImage()->GetData();
    174    }
    175    return mImage->AsNVImage()->GetData();
    176  }
    177 };
    178 
    179 // TODO: optimize for other platforms.
    180 // For Windows: implement D3D9RGB32TextureImpl and D3D11ShareHandleTextureImpl.
    181 // Others: SharedBGRImpl, MACIOSrufaceImpl, GLImageImpl, SurfaceTextureImpl
    182 //         EGLImageImpl and OverlayImegImpl.
    183 
    184 ImageUtils::ImageUtils(layers::Image* aImage) : mImpl(nullptr) {
    185  MOZ_ASSERT(aImage, "Create ImageUtils with nullptr.");
    186  switch (aImage->GetFormat()) {
    187    case mozilla::ImageFormat::PLANAR_YCBCR:
    188    case mozilla::ImageFormat::NV_IMAGE:
    189      mImpl = new YUVImpl(aImage);
    190      break;
    191    case mozilla::ImageFormat::MOZ2D_SURFACE:
    192    default:
    193      mImpl = new Impl(aImage);
    194  }
    195 }
    196 
    197 ImageUtils::~ImageUtils() {
    198  if (mImpl) {
    199    delete mImpl;
    200    mImpl = nullptr;
    201  }
    202 }
    203 
    204 Maybe<ImageBitmapFormat> ImageUtils::GetFormat() const {
    205  MOZ_ASSERT(mImpl);
    206  return mImpl->GetFormat();
    207 }
    208 
    209 uint32_t ImageUtils::GetBufferLength() const {
    210  MOZ_ASSERT(mImpl);
    211  return mImpl->GetBufferLength();
    212 }
    213 
    214 }  // namespace mozilla::dom