tor-browser

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

ImageDataSerializer.cpp (12821B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      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 "ImageDataSerializer.h"
      8 
      9 #include "YCbCrUtils.h"           // for YCbCr conversions
     10 #include "gfx2DGlue.h"            // for SurfaceFormatToImageFormat
     11 #include "mozilla/Assertions.h"   // for MOZ_ASSERT, etc
     12 #include "mozilla/DebugOnly.h"    // for DebugOnly
     13 #include "mozilla/gfx/2D.h"       // for DataSourceSurface, Factory
     14 #include "mozilla/gfx/Logging.h"  // for gfxDebug
     15 #include "mozilla/gfx/Tools.h"    // for GetAlignedStride, etc
     16 #include "mozilla/gfx/Types.h"
     17 #include "mozilla/mozalloc.h"  // for operator delete, etc
     18 
     19 namespace mozilla {
     20 namespace layers {
     21 namespace ImageDataSerializer {
     22 
     23 using namespace gfx;
     24 
     25 int32_t ComputeRGBStride(SurfaceFormat aFormat, int32_t aWidth) {
     26 #ifdef XP_MACOSX
     27  // Some drivers require an alignment of 32 bytes for efficient texture upload.
     28  return GetAlignedStride<32>(aWidth, BytesPerPixel(aFormat));
     29 #else
     30  return GetAlignedStride<4>(aWidth, BytesPerPixel(aFormat));
     31 #endif
     32 }
     33 
     34 int32_t GetRGBStride(const RGBDescriptor& aDescriptor) {
     35  return ComputeRGBStride(aDescriptor.format(), aDescriptor.size().width);
     36 }
     37 
     38 uint32_t ComputeRGBBufferSize(IntSize aSize, SurfaceFormat aFormat) {
     39  MOZ_ASSERT(aSize.height >= 0 && aSize.width >= 0);
     40 
     41  // This takes care of checking whether there could be overflow
     42  // with enough margin for the metadata.
     43  if (!gfx::Factory::AllowedSurfaceSize(aSize)) {
     44    return 0;
     45  }
     46 
     47  // Note we're passing height instad of the bpp parameter, but the end
     48  // result is the same - and the bpp was already taken care of in the
     49  // ComputeRGBStride function.
     50  int32_t bufsize = GetAlignedStride<16>(ComputeRGBStride(aFormat, aSize.width),
     51                                         aSize.height);
     52 
     53  if (bufsize < 0) {
     54    // This should not be possible thanks to Factory::AllowedSurfaceSize
     55    return 0;
     56  }
     57 
     58  return bufsize;
     59 }
     60 
     61 // Minimum required shmem size in bytes
     62 uint32_t ComputeYCbCrBufferSize(const gfx::IntSize& aYSize, int32_t aYStride,
     63                                const gfx::IntSize& aCbCrSize,
     64                                int32_t aCbCrStride) {
     65  MOZ_ASSERT(aYSize.height >= 0 && aYSize.width >= 0);
     66 
     67  if (aYSize.height < 0 || aYSize.width < 0 || aCbCrSize.height < 0 ||
     68      aCbCrSize.width < 0 ||
     69      !gfx::Factory::AllowedSurfaceSize(IntSize(aYStride, aYSize.height)) ||
     70      !gfx::Factory::AllowedSurfaceSize(
     71          IntSize(aCbCrStride, aCbCrSize.height))) {
     72    return 0;
     73  }
     74 
     75  // Overflow checks are performed in AllowedSurfaceSize
     76  return GetAlignedStride<4>(aYSize.height, aYStride) +
     77         2 * GetAlignedStride<4>(aCbCrSize.height, aCbCrStride);
     78 }
     79 
     80 uint32_t ComputeYCbCrBufferSize(const gfx::IntSize& aYSize, int32_t aYStride,
     81                                const gfx::IntSize& aCbCrSize,
     82                                int32_t aCbCrStride, uint32_t aYOffset,
     83                                uint32_t aCbOffset, uint32_t aCrOffset) {
     84  MOZ_ASSERT(aYSize.height >= 0 && aYSize.width >= 0);
     85 
     86  if (aYSize.height < 0 || aYSize.width < 0 || aCbCrSize.height < 0 ||
     87      aCbCrSize.width < 0 ||
     88      !gfx::Factory::AllowedSurfaceSize(IntSize(aYStride, aYSize.height)) ||
     89      !gfx::Factory::AllowedSurfaceSize(
     90          IntSize(aCbCrStride, aCbCrSize.height))) {
     91    return 0;
     92  }
     93 
     94  uint32_t yLength = GetAlignedStride<4>(aYStride, aYSize.height);
     95  uint32_t cbCrLength = GetAlignedStride<4>(aCbCrStride, aCbCrSize.height);
     96  if (yLength == 0 || cbCrLength == 0) {
     97    return 0;
     98  }
     99 
    100  CheckedInt<uint32_t> yEnd = aYOffset;
    101  yEnd += yLength;
    102  CheckedInt<uint32_t> cbEnd = aCbOffset;
    103  cbEnd += cbCrLength;
    104  CheckedInt<uint32_t> crEnd = aCrOffset;
    105  crEnd += cbCrLength;
    106 
    107  if (!yEnd.isValid() || !cbEnd.isValid() || !crEnd.isValid() ||
    108      yEnd.value() > aCbOffset || cbEnd.value() > aCrOffset) {
    109    return 0;
    110  }
    111 
    112  return crEnd.value();
    113 }
    114 
    115 uint32_t ComputeYCbCrBufferSize(uint32_t aBufferSize) {
    116  return GetAlignedStride<4>(aBufferSize, 1);
    117 }
    118 
    119 void ComputeYCbCrOffsets(int32_t yStride, int32_t yHeight, int32_t cbCrStride,
    120                         int32_t cbCrHeight, uint32_t& outYOffset,
    121                         uint32_t& outCbOffset, uint32_t& outCrOffset) {
    122  outYOffset = 0;
    123  outCbOffset = outYOffset + GetAlignedStride<4>(yStride, yHeight);
    124  outCrOffset = outCbOffset + GetAlignedStride<4>(cbCrStride, cbCrHeight);
    125 }
    126 
    127 gfx::SurfaceFormat FormatFromBufferDescriptor(
    128    const BufferDescriptor& aDescriptor) {
    129  switch (aDescriptor.type()) {
    130    case BufferDescriptor::TRGBDescriptor:
    131      return aDescriptor.get_RGBDescriptor().format();
    132    case BufferDescriptor::TYCbCrDescriptor:
    133      return gfx::SurfaceFormat::YUV420;
    134    default:
    135      MOZ_CRASH("GFX: FormatFromBufferDescriptor");
    136  }
    137 }
    138 
    139 gfx::IntSize SizeFromBufferDescriptor(const BufferDescriptor& aDescriptor) {
    140  switch (aDescriptor.type()) {
    141    case BufferDescriptor::TRGBDescriptor:
    142      return aDescriptor.get_RGBDescriptor().size();
    143    case BufferDescriptor::TYCbCrDescriptor: {
    144      return aDescriptor.get_YCbCrDescriptor().display().Size();
    145    }
    146    default:
    147      MOZ_CRASH("GFX: SizeFromBufferDescriptor");
    148  }
    149 }
    150 
    151 gfx::IntRect RectFromBufferDescriptor(const BufferDescriptor& aDescriptor) {
    152  switch (aDescriptor.type()) {
    153    case BufferDescriptor::TRGBDescriptor: {
    154      auto size = aDescriptor.get_RGBDescriptor().size();
    155      return gfx::IntRect(0, 0, size.Width(), size.Height());
    156    }
    157    case BufferDescriptor::TYCbCrDescriptor:
    158      return aDescriptor.get_YCbCrDescriptor().display();
    159    default:
    160      MOZ_CRASH("GFX: RectFromBufferDescriptor");
    161  }
    162 }
    163 
    164 Maybe<gfx::IntSize> YSizeFromBufferDescriptor(
    165    const BufferDescriptor& aDescriptor) {
    166  switch (aDescriptor.type()) {
    167    case BufferDescriptor::TRGBDescriptor:
    168      return Nothing();
    169    case BufferDescriptor::TYCbCrDescriptor:
    170      return Some(aDescriptor.get_YCbCrDescriptor().ySize());
    171    default:
    172      MOZ_CRASH("GFX: YSizeFromBufferDescriptor");
    173  }
    174 }
    175 
    176 Maybe<gfx::IntSize> CbCrSizeFromBufferDescriptor(
    177    const BufferDescriptor& aDescriptor) {
    178  switch (aDescriptor.type()) {
    179    case BufferDescriptor::TRGBDescriptor:
    180      return Nothing();
    181    case BufferDescriptor::TYCbCrDescriptor:
    182      return Some(aDescriptor.get_YCbCrDescriptor().cbCrSize());
    183    default:
    184      MOZ_CRASH("GFX: CbCrSizeFromBufferDescriptor");
    185  }
    186 }
    187 
    188 Maybe<int32_t> YStrideFromBufferDescriptor(
    189    const BufferDescriptor& aDescriptor) {
    190  switch (aDescriptor.type()) {
    191    case BufferDescriptor::TRGBDescriptor:
    192      return Nothing();
    193    case BufferDescriptor::TYCbCrDescriptor:
    194      return Some(aDescriptor.get_YCbCrDescriptor().yStride());
    195    default:
    196      MOZ_CRASH("GFX: YStrideFromBufferDescriptor");
    197  }
    198 }
    199 
    200 Maybe<int32_t> CbCrStrideFromBufferDescriptor(
    201    const BufferDescriptor& aDescriptor) {
    202  switch (aDescriptor.type()) {
    203    case BufferDescriptor::TRGBDescriptor:
    204      return Nothing();
    205    case BufferDescriptor::TYCbCrDescriptor:
    206      return Some(aDescriptor.get_YCbCrDescriptor().cbCrStride());
    207    default:
    208      MOZ_CRASH("GFX: CbCrStrideFromBufferDescriptor");
    209  }
    210 }
    211 
    212 Maybe<gfx::YUVColorSpace> YUVColorSpaceFromBufferDescriptor(
    213    const BufferDescriptor& aDescriptor) {
    214  switch (aDescriptor.type()) {
    215    case BufferDescriptor::TRGBDescriptor:
    216      return Nothing();
    217    case BufferDescriptor::TYCbCrDescriptor:
    218      return Some(aDescriptor.get_YCbCrDescriptor().yUVColorSpace());
    219    default:
    220      MOZ_CRASH("GFX:  YUVColorSpaceFromBufferDescriptor");
    221  }
    222 }
    223 
    224 Maybe<gfx::ColorDepth> ColorDepthFromBufferDescriptor(
    225    const BufferDescriptor& aDescriptor) {
    226  switch (aDescriptor.type()) {
    227    case BufferDescriptor::TRGBDescriptor:
    228      return Nothing();
    229    case BufferDescriptor::TYCbCrDescriptor:
    230      return Some(aDescriptor.get_YCbCrDescriptor().colorDepth());
    231    default:
    232      MOZ_CRASH("GFX:  ColorDepthFromBufferDescriptor");
    233  }
    234 }
    235 
    236 Maybe<gfx::ColorRange> ColorRangeFromBufferDescriptor(
    237    const BufferDescriptor& aDescriptor) {
    238  switch (aDescriptor.type()) {
    239    case BufferDescriptor::TRGBDescriptor:
    240      return Nothing();
    241    case BufferDescriptor::TYCbCrDescriptor:
    242      return Some(aDescriptor.get_YCbCrDescriptor().colorRange());
    243    default:
    244      MOZ_CRASH("GFX: YUVFullRangeFromBufferDescriptor");
    245  }
    246 }
    247 
    248 Maybe<StereoMode> StereoModeFromBufferDescriptor(
    249    const BufferDescriptor& aDescriptor) {
    250  switch (aDescriptor.type()) {
    251    case BufferDescriptor::TRGBDescriptor:
    252      return Nothing();
    253    case BufferDescriptor::TYCbCrDescriptor:
    254      return Some(aDescriptor.get_YCbCrDescriptor().stereoMode());
    255    default:
    256      MOZ_CRASH("GFX:  StereoModeFromBufferDescriptor");
    257  }
    258 }
    259 
    260 Maybe<gfx::ChromaSubsampling> ChromaSubsamplingFromBufferDescriptor(
    261    const BufferDescriptor& aDescriptor) {
    262  switch (aDescriptor.type()) {
    263    case BufferDescriptor::TRGBDescriptor:
    264      return Nothing();
    265    case BufferDescriptor::TYCbCrDescriptor:
    266      return Some(aDescriptor.get_YCbCrDescriptor().chromaSubsampling());
    267    default:
    268      MOZ_CRASH("GFX: ChromaSubsamplingFromBufferDescriptor");
    269  }
    270 }
    271 
    272 uint8_t* GetYChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor) {
    273  return aBuffer + aDescriptor.yOffset();
    274 }
    275 
    276 uint8_t* GetCbChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor) {
    277  return aBuffer + aDescriptor.cbOffset();
    278 }
    279 
    280 uint8_t* GetCrChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor) {
    281  return aBuffer + aDescriptor.crOffset();
    282 }
    283 
    284 already_AddRefed<DataSourceSurface> DataSourceSurfaceFromYCbCrDescriptor(
    285    uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor,
    286    gfx::DataSourceSurface* aSurface) {
    287  const gfx::IntRect display = aDescriptor.display();
    288  const gfx::IntSize size = display.Size();
    289  RefPtr<DataSourceSurface> result;
    290  if (aSurface) {
    291    MOZ_ASSERT(aSurface->GetSize() == size);
    292    MOZ_ASSERT(aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8);
    293    if (aSurface->GetSize() == size &&
    294        aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8) {
    295      result = aSurface;
    296    }
    297  }
    298 
    299  if (!result) {
    300    result =
    301        Factory::CreateDataSourceSurface(size, gfx::SurfaceFormat::B8G8R8X8);
    302  }
    303  if (NS_WARN_IF(!result)) {
    304    return nullptr;
    305  }
    306 
    307  DataSourceSurface::MappedSurface map;
    308  if (NS_WARN_IF(!result->Map(DataSourceSurface::MapType::WRITE, &map))) {
    309    return nullptr;
    310  }
    311 
    312  layers::PlanarYCbCrData ycbcrData;
    313  ycbcrData.mYChannel = GetYChannel(aBuffer, aDescriptor);
    314  ycbcrData.mYStride = aDescriptor.yStride();
    315  ycbcrData.mCbChannel = GetCbChannel(aBuffer, aDescriptor);
    316  ycbcrData.mCrChannel = GetCrChannel(aBuffer, aDescriptor);
    317  ycbcrData.mCbCrStride = aDescriptor.cbCrStride();
    318  ycbcrData.mPictureRect = aDescriptor.display();
    319  ycbcrData.mYUVColorSpace = aDescriptor.yUVColorSpace();
    320  ycbcrData.mColorDepth = aDescriptor.colorDepth();
    321  ycbcrData.mChromaSubsampling = aDescriptor.chromaSubsampling();
    322 
    323  if (NS_WARN_IF(NS_FAILED(
    324          gfx::ConvertYCbCrToRGB(ycbcrData, gfx::SurfaceFormat::B8G8R8X8, size,
    325                                 map.mData, map.mStride)))) {
    326    MOZ_ASSERT_UNREACHABLE("Failed to convert YUV into RGB data");
    327    return nullptr;
    328  }
    329 
    330  result->Unmap();
    331  return result.forget();
    332 }
    333 
    334 void ConvertAndScaleFromYCbCrDescriptor(uint8_t* aBuffer,
    335                                        const YCbCrDescriptor& aDescriptor,
    336                                        const gfx::SurfaceFormat& aDestFormat,
    337                                        const gfx::IntSize& aDestSize,
    338                                        unsigned char* aDestBuffer,
    339                                        int32_t aStride) {
    340  MOZ_ASSERT(aBuffer);
    341 
    342  layers::PlanarYCbCrData ycbcrData;
    343  ycbcrData.mYChannel = GetYChannel(aBuffer, aDescriptor);
    344  ycbcrData.mYStride = aDescriptor.yStride();
    345  ycbcrData.mCbChannel = GetCbChannel(aBuffer, aDescriptor);
    346  ycbcrData.mCrChannel = GetCrChannel(aBuffer, aDescriptor);
    347  ycbcrData.mCbCrStride = aDescriptor.cbCrStride();
    348  ycbcrData.mPictureRect = aDescriptor.display();
    349  ycbcrData.mYUVColorSpace = aDescriptor.yUVColorSpace();
    350  ycbcrData.mColorDepth = aDescriptor.colorDepth();
    351  ycbcrData.mChromaSubsampling = aDescriptor.chromaSubsampling();
    352 
    353  DebugOnly<nsresult> result = gfx::ConvertYCbCrToRGB(
    354      ycbcrData, aDestFormat, aDestSize, aDestBuffer, aStride);
    355  MOZ_ASSERT(NS_SUCCEEDED(result), "Failed to convert YUV into RGB data");
    356 }
    357 
    358 gfx::IntSize GetCroppedCbCrSize(const YCbCrDescriptor& aDescriptor) {
    359  return ChromaSize(aDescriptor.display().Size(),
    360                    aDescriptor.chromaSubsampling());
    361 }
    362 
    363 }  // namespace ImageDataSerializer
    364 }  // namespace layers
    365 }  // namespace mozilla