LCOV - code coverage report
Current view: top level - gfx/2d - DataSurfaceHelpers.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 5 142 3.5 %
Date: 2017-07-14 16:53:18 Functions: 1 13 7.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include <cstring>
       7             : 
       8             : #include "2D.h"
       9             : #include "DataSurfaceHelpers.h"
      10             : #include "Logging.h"
      11             : #include "mozilla/MathAlgorithms.h"
      12             : #include "mozilla/PodOperations.h"
      13             : #include "Swizzle.h"
      14             : #include "Tools.h"
      15             : 
      16             : namespace mozilla {
      17             : namespace gfx {
      18             : 
      19             : int32_t
      20           0 : StrideForFormatAndWidth(SurfaceFormat aFormat, int32_t aWidth)
      21             : {
      22           0 :   MOZ_ASSERT(aFormat <= SurfaceFormat::UNKNOWN);
      23           0 :   MOZ_ASSERT(aWidth > 0);
      24             : 
      25             :   // There's nothing special about this alignment, other than that it's what
      26             :   // cairo_format_stride_for_width uses.
      27             :   static const int32_t alignment = sizeof(int32_t);
      28             : 
      29           0 :   const int32_t bpp = BytesPerPixel(aFormat);
      30             : 
      31           0 :   if (aWidth >= (INT32_MAX - alignment) / bpp) {
      32           0 :     return -1; // too big
      33             :   }
      34             : 
      35           0 :   return (bpp * aWidth + alignment-1) & ~(alignment-1);
      36             : }
      37             : 
      38             : already_AddRefed<DataSourceSurface>
      39           0 : CreateDataSourceSurfaceFromData(const IntSize& aSize,
      40             :                                 SurfaceFormat aFormat,
      41             :                                 const uint8_t* aData,
      42             :                                 int32_t aDataStride)
      43             : {
      44             :   RefPtr<DataSourceSurface> srcSurface =
      45           0 :       Factory::CreateWrappingDataSourceSurface(const_cast<uint8_t*>(aData),
      46             :                                                aDataStride,
      47             :                                                aSize,
      48           0 :                                                aFormat);
      49             :   RefPtr<DataSourceSurface> destSurface =
      50           0 :       Factory::CreateDataSourceSurface(aSize, aFormat, false);
      51             : 
      52           0 :   if (!srcSurface || !destSurface) {
      53           0 :     return nullptr;
      54             :   }
      55             : 
      56           0 :   if (CopyRect(srcSurface,
      57             :                destSurface,
      58           0 :                IntRect(IntPoint(), srcSurface->GetSize()),
      59           0 :                IntPoint())) {
      60           0 :     return destSurface.forget();
      61             :   }
      62             : 
      63           0 :   return nullptr;
      64             : }
      65             : 
      66             : already_AddRefed<DataSourceSurface>
      67           0 : CreateDataSourceSurfaceWithStrideFromData(const IntSize &aSize,
      68             :                                           SurfaceFormat aFormat,
      69             :                                           int32_t aStride,
      70             :                                           const uint8_t* aData,
      71             :                                           int32_t aDataStride)
      72             : {
      73             :   RefPtr<DataSourceSurface> srcSurface =
      74           0 :       Factory::CreateWrappingDataSourceSurface(const_cast<uint8_t*>(aData),
      75             :                                                aDataStride,
      76             :                                                aSize,
      77           0 :                                                aFormat);
      78             :   RefPtr<DataSourceSurface> destSurface =
      79           0 :       Factory::CreateDataSourceSurfaceWithStride(aSize, aFormat, aStride, false);
      80             : 
      81           0 :   if (!srcSurface || !destSurface) {
      82           0 :     return nullptr;
      83             :   }
      84             : 
      85           0 :   if (CopyRect(srcSurface,
      86             :                destSurface,
      87           0 :                IntRect(IntPoint(), srcSurface->GetSize()),
      88           0 :                IntPoint())) {
      89           0 :     return destSurface.forget();
      90             :   }
      91             : 
      92           0 :   return nullptr;
      93             : }
      94             : 
      95             : uint8_t*
      96           0 : DataAtOffset(DataSourceSurface* aSurface,
      97             :              const DataSourceSurface::MappedSurface* aMap,
      98             :              IntPoint aPoint)
      99             : {
     100           0 :   if (!SurfaceContainsPoint(aSurface, aPoint)) {
     101           0 :     MOZ_CRASH("GFX: sample position needs to be inside surface!");
     102             :   }
     103             : 
     104           0 :   MOZ_ASSERT(Factory::CheckSurfaceSize(aSurface->GetSize()),
     105             :              "surface size overflows - this should have been prevented when the surface was created");
     106             : 
     107           0 :   uint8_t* data = aMap->mData + aPoint.y * aMap->mStride +
     108           0 :     aPoint.x * BytesPerPixel(aSurface->GetFormat());
     109             : 
     110           0 :   if (data < aMap->mData) {
     111           0 :     MOZ_CRASH("GFX: out-of-range data access");
     112             :   }
     113             : 
     114           0 :   return data;
     115             : }
     116             : 
     117             : // This check is safe against integer overflow.
     118             : bool
     119           0 : SurfaceContainsPoint(SourceSurface* aSurface, const IntPoint& aPoint)
     120             : {
     121           0 :   IntSize size = aSurface->GetSize();
     122           0 :   return aPoint.x >= 0 && aPoint.x < size.width &&
     123           0 :          aPoint.y >= 0 && aPoint.y < size.height;
     124             : }
     125             : 
     126             : void
     127           0 : CopySurfaceDataToPackedArray(uint8_t* aSrc, uint8_t* aDst, IntSize aSrcSize,
     128             :                              int32_t aSrcStride, int32_t aBytesPerPixel)
     129             : {
     130           0 :   MOZ_ASSERT(aBytesPerPixel > 0,
     131             :              "Negative stride for aDst not currently supported");
     132           0 :   MOZ_ASSERT(BufferSizeFromStrideAndHeight(aSrcStride, aSrcSize.height) > 0,
     133             :              "How did we end up with a surface with such a big buffer?");
     134             : 
     135           0 :   int packedStride = aSrcSize.width * aBytesPerPixel;
     136             : 
     137           0 :   if (aSrcStride == packedStride) {
     138             :     // aSrc is already packed, so we can copy with a single memcpy.
     139           0 :     memcpy(aDst, aSrc, packedStride * aSrcSize.height);
     140             :   } else {
     141             :     // memcpy one row at a time.
     142           0 :     for (int row = 0; row < aSrcSize.height; ++row) {
     143           0 :       memcpy(aDst, aSrc, packedStride);
     144           0 :       aSrc += aSrcStride;
     145           0 :       aDst += packedStride;
     146             :     }
     147             :   }
     148           0 : }
     149             : 
     150             : UniquePtr<uint8_t[]>
     151           0 : SurfaceToPackedBGRA(DataSourceSurface *aSurface)
     152             : {
     153           0 :   SurfaceFormat format = aSurface->GetFormat();
     154           0 :   if (format != SurfaceFormat::B8G8R8A8 && format != SurfaceFormat::B8G8R8X8) {
     155           0 :     return nullptr;
     156             :   }
     157             : 
     158           0 :   IntSize size = aSurface->GetSize();
     159             : 
     160             :   UniquePtr<uint8_t[]> imageBuffer(
     161           0 :     new (std::nothrow) uint8_t[size.width * size.height * sizeof(uint32_t)]);
     162           0 :   if (!imageBuffer) {
     163           0 :     return nullptr;
     164             :   }
     165             : 
     166             :   DataSourceSurface::MappedSurface map;
     167           0 :   if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) {
     168           0 :     return nullptr;
     169             :   }
     170             : 
     171           0 :   CopySurfaceDataToPackedArray(map.mData, imageBuffer.get(), size,
     172           0 :                                map.mStride, 4 * sizeof(uint8_t));
     173             : 
     174           0 :   aSurface->Unmap();
     175             : 
     176           0 :   if (format == SurfaceFormat::B8G8R8X8) {
     177             :     // Convert BGRX to BGRA by setting a to 255.
     178           0 :     SwizzleData(imageBuffer.get(), size.width * sizeof(uint32_t), SurfaceFormat::X8R8G8B8_UINT32,
     179           0 :                 imageBuffer.get(), size.width * sizeof(uint32_t), SurfaceFormat::A8R8G8B8_UINT32,
     180           0 :                 size);
     181             :   }
     182             : 
     183           0 :   return imageBuffer;
     184             : }
     185             : 
     186             : uint8_t*
     187           0 : SurfaceToPackedBGR(DataSourceSurface *aSurface)
     188             : {
     189           0 :   SurfaceFormat format = aSurface->GetFormat();
     190           0 :   MOZ_ASSERT(format == SurfaceFormat::B8G8R8X8, "Format not supported");
     191             : 
     192           0 :   if (format != SurfaceFormat::B8G8R8X8) {
     193             :     // To support B8G8R8A8 we'd need to un-pre-multiply alpha
     194           0 :     return nullptr;
     195             :   }
     196             : 
     197           0 :   IntSize size = aSurface->GetSize();
     198             : 
     199           0 :   uint8_t* imageBuffer = new (std::nothrow) uint8_t[size.width * size.height * 3 * sizeof(uint8_t)];
     200           0 :   if (!imageBuffer) {
     201           0 :     return nullptr;
     202             :   }
     203             : 
     204             :   DataSourceSurface::MappedSurface map;
     205           0 :   if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) {
     206           0 :     delete [] imageBuffer;
     207           0 :     return nullptr;
     208             :   }
     209             : 
     210           0 :   SwizzleData(map.mData, map.mStride, SurfaceFormat::B8G8R8X8,
     211           0 :               imageBuffer, size.width * 3, SurfaceFormat::B8G8R8,
     212           0 :               size);
     213             : 
     214           0 :   aSurface->Unmap();
     215             : 
     216           0 :   return imageBuffer;
     217             : }
     218             : 
     219             : void
     220           0 : ClearDataSourceSurface(DataSourceSurface *aSurface)
     221             : {
     222             :   DataSourceSurface::MappedSurface map;
     223           0 :   if (!aSurface->Map(DataSourceSurface::MapType::WRITE, &map)) {
     224           0 :     MOZ_ASSERT(false, "Failed to map DataSourceSurface");
     225             :     return;
     226             :   }
     227             : 
     228             :   // We avoid writing into the gaps between the rows here since we can't be
     229             :   // sure that some drivers don't use those bytes.
     230             : 
     231           0 :   uint32_t width = aSurface->GetSize().width;
     232           0 :   uint32_t bytesPerRow = width * BytesPerPixel(aSurface->GetFormat());
     233           0 :   uint8_t* row = map.mData;
     234             :   // converting to size_t here because otherwise the temporaries can overflow
     235             :   // and we can end up with |end| being a bad address!
     236           0 :   uint8_t* end = row + size_t(map.mStride) * size_t(aSurface->GetSize().height);
     237             : 
     238           0 :   while (row != end) {
     239           0 :     memset(row, 0, bytesPerRow);
     240           0 :     row += map.mStride;
     241             :   }
     242             : 
     243           0 :   aSurface->Unmap();
     244           0 : }
     245             : 
     246             : size_t
     247           2 : BufferSizeFromStrideAndHeight(int32_t aStride,
     248             :                               int32_t aHeight,
     249             :                               int32_t aExtraBytes)
     250             : {
     251           2 :   if (MOZ_UNLIKELY(aHeight <= 0) || MOZ_UNLIKELY(aStride <= 0)) {
     252           0 :     return 0;
     253             :   }
     254             : 
     255             :   // We limit the length returned to values that can be represented by int32_t
     256             :   // because we don't want to allocate buffers any bigger than that. This
     257             :   // allows for a buffer size of over 2 GiB which is already rediculously
     258             :   // large and will make the process janky. (Note the choice of the signed type
     259             :   // is deliberate because we specifically don't want the returned value to
     260             :   // overflow if someone stores the buffer length in an int32_t variable.)
     261             : 
     262             :   CheckedInt32 requiredBytes =
     263           2 :     CheckedInt32(aStride) * CheckedInt32(aHeight) + CheckedInt32(aExtraBytes);
     264           2 :   if (MOZ_UNLIKELY(!requiredBytes.isValid())) {
     265           0 :     gfxWarning() << "Buffer size too big; returning zero " << aStride << ", " << aHeight << ", " << aExtraBytes;
     266           0 :     return 0;
     267             :   }
     268           2 :   return requiredBytes.value();
     269             : }
     270             : 
     271             : size_t
     272           0 : BufferSizeFromDimensions(int32_t aWidth,
     273             :                          int32_t aHeight,
     274             :                          int32_t aDepth,
     275             :                          int32_t aExtraBytes)
     276             : {
     277           0 :   if (MOZ_UNLIKELY(aHeight <= 0) ||
     278           0 :       MOZ_UNLIKELY(aWidth <= 0) ||
     279           0 :       MOZ_UNLIKELY(aDepth <= 0)) {
     280           0 :     return 0;
     281             :   }
     282             : 
     283             :   // Similar to BufferSizeFromStrideAndHeight, but with an extra parameter.
     284             : 
     285           0 :   CheckedInt32 requiredBytes = CheckedInt32(aWidth) * CheckedInt32(aHeight) * CheckedInt32(aDepth) + CheckedInt32(aExtraBytes);
     286           0 :   if (MOZ_UNLIKELY(!requiredBytes.isValid())) {
     287           0 :     gfxWarning() << "Buffer size too big; returning zero " << aWidth << ", " << aHeight << ", " << aDepth << ", " << aExtraBytes;
     288           0 :     return 0;
     289             :   }
     290           0 :   return requiredBytes.value();
     291             : }
     292             : 
     293             : /**
     294             :  * aSrcRect: Rect relative to the aSrc surface
     295             :  * aDestPoint: Point inside aDest surface
     296             :  */
     297             : bool
     298           0 : CopyRect(DataSourceSurface* aSrc, DataSourceSurface* aDest,
     299             :          IntRect aSrcRect, IntPoint aDestPoint)
     300             : {
     301           0 :   if (aSrcRect.Overflows() ||
     302           0 :       IntRect(aDestPoint, aSrcRect.Size()).Overflows()) {
     303           0 :     MOZ_CRASH("GFX: we should never be getting invalid rects at this point");
     304             :   }
     305             : 
     306           0 :   MOZ_RELEASE_ASSERT(aSrc->GetFormat() == aDest->GetFormat(),
     307             :                      "GFX: different surface formats");
     308           0 :   MOZ_RELEASE_ASSERT(IntRect(IntPoint(), aSrc->GetSize()).Contains(aSrcRect),
     309             :                      "GFX: source rect too big for source surface");
     310           0 :   MOZ_RELEASE_ASSERT(IntRect(IntPoint(), aDest->GetSize()).Contains(IntRect(aDestPoint, aSrcRect.Size())),
     311             :                      "GFX: dest surface too small");
     312             : 
     313           0 :   if (aSrcRect.IsEmpty()) {
     314           0 :     return false;
     315             :   }
     316             : 
     317           0 :   DataSourceSurface::ScopedMap srcMap(aSrc, DataSourceSurface::READ);
     318           0 :   DataSourceSurface::ScopedMap destMap(aDest, DataSourceSurface::WRITE);
     319           0 :   if (MOZ2D_WARN_IF(!srcMap.IsMapped() || !destMap.IsMapped())) {
     320           0 :     return false;
     321             :   }
     322             : 
     323           0 :   uint8_t* sourceData = DataAtOffset(aSrc, srcMap.GetMappedSurface(), aSrcRect.TopLeft());
     324           0 :   uint8_t* destData = DataAtOffset(aDest, destMap.GetMappedSurface(), aDestPoint);
     325             : 
     326           0 :   SwizzleData(sourceData, srcMap.GetStride(), aSrc->GetFormat(),
     327           0 :               destData, destMap.GetStride(), aDest->GetFormat(),
     328           0 :               aSrcRect.Size());
     329             : 
     330           0 :   return true;
     331             : }
     332             : 
     333             : already_AddRefed<DataSourceSurface>
     334           0 : CreateDataSourceSurfaceByCloning(DataSourceSurface* aSource)
     335             : {
     336             :   RefPtr<DataSourceSurface> copy =
     337           0 :     Factory::CreateDataSourceSurface(aSource->GetSize(), aSource->GetFormat(), true);
     338           0 :   if (copy) {
     339           0 :     CopyRect(aSource, copy, IntRect(IntPoint(), aSource->GetSize()), IntPoint());
     340             :   }
     341           0 :   return copy.forget();
     342             : }
     343             : 
     344             : } // namespace gfx
     345             : } // namespace mozilla

Generated by: LCOV version 1.13