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 "ImageUtils.h" 8 #include "ImageContainer.h" 9 #include "mozilla/AlreadyAddRefed.h" 10 #include "mozilla/dom/ImageBitmapBinding.h" 11 #include "mozilla/ErrorResult.h" 12 13 using namespace mozilla::layers; 14 using namespace mozilla::gfx; 15 16 namespace mozilla::dom { 17 GetImageBitmapFormatFromSurfaceFromat(SurfaceFormat aSurfaceFormat)18static ImageBitmapFormat GetImageBitmapFormatFromSurfaceFromat( 19 SurfaceFormat aSurfaceFormat) { 20 switch (aSurfaceFormat) { 21 case SurfaceFormat::B8G8R8A8: 22 case SurfaceFormat::B8G8R8X8: 23 return ImageBitmapFormat::BGRA32; 24 case SurfaceFormat::R8G8B8A8: 25 case SurfaceFormat::R8G8B8X8: 26 return ImageBitmapFormat::RGBA32; 27 case SurfaceFormat::R8G8B8: 28 return ImageBitmapFormat::RGB24; 29 case SurfaceFormat::B8G8R8: 30 return ImageBitmapFormat::BGR24; 31 case SurfaceFormat::HSV: 32 return ImageBitmapFormat::HSV; 33 case SurfaceFormat::Lab: 34 return ImageBitmapFormat::Lab; 35 case SurfaceFormat::Depth: 36 return ImageBitmapFormat::DEPTH; 37 case SurfaceFormat::A8: 38 return ImageBitmapFormat::GRAY8; 39 case SurfaceFormat::R5G6B5_UINT16: 40 case SurfaceFormat::YUV: 41 case SurfaceFormat::NV12: 42 case SurfaceFormat::P010: 43 case SurfaceFormat::P016: 44 case SurfaceFormat::UNKNOWN: 45 default: 46 return ImageBitmapFormat::EndGuard_; 47 } 48 } 49 GetImageBitmapFormatFromPlanarYCbCrData(layers::PlanarYCbCrData const * aData)50static ImageBitmapFormat GetImageBitmapFormatFromPlanarYCbCrData( 51 layers::PlanarYCbCrData const* aData) { 52 MOZ_ASSERT(aData); 53 54 if (aData->mYSkip == 0 && aData->mCbSkip == 0 && 55 aData->mCrSkip == 0) { // Possibly three planes. 56 if (aData->mCbChannel >= 57 aData->mYChannel + aData->mYSize.height * aData->mYStride && 58 aData->mCrChannel >= 59 aData->mCbChannel + aData->mCbCrSize.height * 60 aData->mCbCrStride) { // Three planes. 61 if (aData->mYSize.height == aData->mCbCrSize.height) { 62 if (aData->mYSize.width == aData->mCbCrSize.width) { 63 return ImageBitmapFormat::YUV444P; 64 } 65 if (((aData->mYSize.width + 1) / 2) == aData->mCbCrSize.width) { 66 return ImageBitmapFormat::YUV422P; 67 } 68 } else if (((aData->mYSize.height + 1) / 2) == aData->mCbCrSize.height) { 69 if (((aData->mYSize.width + 1) / 2) == aData->mCbCrSize.width) { 70 return ImageBitmapFormat::YUV420P; 71 } 72 } 73 } 74 } else if (aData->mYSkip == 0 && aData->mCbSkip == 1 && 75 aData->mCrSkip == 1) { // Possibly two planes. 76 if (aData->mCbChannel >= 77 aData->mYChannel + aData->mYSize.height * aData->mYStride && 78 aData->mCbChannel == aData->mCrChannel - 1) { // Two planes. 79 if (((aData->mYSize.height + 1) / 2) == aData->mCbCrSize.height && 80 ((aData->mYSize.width + 1) / 2) == aData->mCbCrSize.width) { 81 return ImageBitmapFormat::YUV420SP_NV12; // Y-Cb-Cr 82 } 83 } else if (aData->mCrChannel >= 84 aData->mYChannel + aData->mYSize.height * aData->mYStride && 85 aData->mCrChannel == aData->mCbChannel - 1) { // Two planes. 86 if (((aData->mYSize.height + 1) / 2) == aData->mCbCrSize.height && 87 ((aData->mYSize.width + 1) / 2) == aData->mCbCrSize.width) { 88 return ImageBitmapFormat::YUV420SP_NV21; // Y-Cr-Cb 89 } 90 } 91 } 92 93 return ImageBitmapFormat::EndGuard_; 94 } 95 96 // ImageUtils::Impl implements the _generic_ algorithm which always readback 97 // data in RGBA format into CPU memory. 98 // Since layers::CairoImage is just a warpper to a DataSourceSurface, the 99 // implementation of CairoSurfaceImpl is nothing different to the generic 100 // version. 101 class ImageUtils::Impl { 102 public: Impl(layers::Image * aImage)103 explicit Impl(layers::Image* aImage) : mImage(aImage), mSurface(nullptr) {} 104 105 virtual ~Impl() = default; 106 GetFormat() const107 virtual ImageBitmapFormat GetFormat() const { 108 return GetImageBitmapFormatFromSurfaceFromat(Surface()->GetFormat()); 109 } 110 GetBufferLength() const111 virtual uint32_t GetBufferLength() const { 112 DataSourceSurface::ScopedMap map(Surface(), DataSourceSurface::READ); 113 const uint32_t stride = map.GetStride(); 114 const IntSize size = Surface()->GetSize(); 115 return (uint32_t)(size.height * stride); 116 } 117 118 protected: 119 Impl() = default; 120 Surface() const121 DataSourceSurface* Surface() const { 122 if (!mSurface) { 123 RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface(); 124 MOZ_ASSERT(surface); 125 126 mSurface = surface->GetDataSurface(); 127 MOZ_ASSERT(mSurface); 128 } 129 130 return mSurface.get(); 131 } 132 133 RefPtr<layers::Image> mImage; 134 mutable RefPtr<DataSourceSurface> mSurface; 135 }; 136 137 // YUVImpl is optimized for the layers::PlanarYCbCrImage and layers::NVImage. 138 // This implementation does not readback data in RGBA format but keep it in YUV 139 // format family. 140 class YUVImpl final : public ImageUtils::Impl { 141 public: YUVImpl(layers::Image * aImage)142 explicit YUVImpl(layers::Image* aImage) : Impl(aImage) { 143 MOZ_ASSERT(aImage->GetFormat() == ImageFormat::PLANAR_YCBCR || 144 aImage->GetFormat() == ImageFormat::NV_IMAGE); 145 } 146 GetFormat() const147 ImageBitmapFormat GetFormat() const override { 148 return GetImageBitmapFormatFromPlanarYCbCrData(GetPlanarYCbCrData()); 149 } 150 GetBufferLength() const151 uint32_t GetBufferLength() const override { 152 if (mImage->GetFormat() == ImageFormat::PLANAR_YCBCR) { 153 return mImage->AsPlanarYCbCrImage()->GetDataSize(); 154 } 155 return mImage->AsNVImage()->GetBufferSize(); 156 } 157 158 private: GetPlanarYCbCrData() const159 const PlanarYCbCrData* GetPlanarYCbCrData() const { 160 if (mImage->GetFormat() == ImageFormat::PLANAR_YCBCR) { 161 return mImage->AsPlanarYCbCrImage()->GetData(); 162 } 163 return mImage->AsNVImage()->GetData(); 164 } 165 }; 166 167 // TODO: optimize for other platforms. 168 // For Windows: implement D3D9RGB32TextureImpl and D3D11ShareHandleTextureImpl. 169 // Others: SharedBGRImpl, MACIOSrufaceImpl, GLImageImpl, SurfaceTextureImpl 170 // EGLImageImpl and OverlayImegImpl. 171 ImageUtils(layers::Image * aImage)172ImageUtils::ImageUtils(layers::Image* aImage) : mImpl(nullptr) { 173 MOZ_ASSERT(aImage, "Create ImageUtils with nullptr."); 174 switch (aImage->GetFormat()) { 175 case mozilla::ImageFormat::PLANAR_YCBCR: 176 case mozilla::ImageFormat::NV_IMAGE: 177 mImpl = new YUVImpl(aImage); 178 break; 179 case mozilla::ImageFormat::CAIRO_SURFACE: 180 default: 181 mImpl = new Impl(aImage); 182 } 183 } 184 ~ImageUtils()185ImageUtils::~ImageUtils() { 186 if (mImpl) { 187 delete mImpl; 188 mImpl = nullptr; 189 } 190 } 191 GetFormat() const192ImageBitmapFormat ImageUtils::GetFormat() const { 193 MOZ_ASSERT(mImpl); 194 return mImpl->GetFormat(); 195 } 196 GetBufferLength() const197uint32_t ImageUtils::GetBufferLength() const { 198 MOZ_ASSERT(mImpl); 199 return mImpl->GetBufferLength(); 200 } 201 202 } // namespace mozilla::dom 203