gfx/2d/DataSurfaceHelpers.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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/. */
     6 #include "2D.h"
     7 #include "DataSurfaceHelpers.h"
     8 #include "Logging.h"
     9 #include "mozilla/CheckedInt.h"
    10 #include "mozilla/MathAlgorithms.h"
    12 namespace mozilla {
    13 namespace gfx {
    15 void
    16 ConvertBGRXToBGRA(uint8_t* aData, const IntSize &aSize, int32_t aStride)
    17 {
    18   uint32_t* pixel = reinterpret_cast<uint32_t*>(aData);
    20   for (int row = 0; row < aSize.height; ++row) {
    21     for (int column = 0; column < aSize.width; ++column) {
    22 #ifdef IS_BIG_ENDIAN
    23       pixel[column] |= 0x000000FF;
    24 #else
    25       pixel[column] |= 0xFF000000;
    26 #endif
    27     }
    28     pixel += (aStride/4);
    29   }
    30 }
    32 void
    33 CopySurfaceDataToPackedArray(uint8_t* aSrc, uint8_t* aDst, IntSize aSrcSize,
    34                              int32_t aSrcStride, int32_t aBytesPerPixel)
    35 {
    36   MOZ_ASSERT(aBytesPerPixel > 0,
    37              "Negative stride for aDst not currently supported");
    38   MOZ_ASSERT(BufferSizeFromStrideAndHeight(aSrcStride, aSrcSize.height) > 0,
    39              "How did we end up with a surface with such a big buffer?");
    41   int packedStride = aSrcSize.width * aBytesPerPixel;
    43   if (aSrcStride == packedStride) {
    44     // aSrc is already packed, so we can copy with a single memcpy.
    45     memcpy(aDst, aSrc, packedStride * aSrcSize.height);
    46   } else {
    47     // memcpy one row at a time.
    48     for (int row = 0; row < aSrcSize.height; ++row) {
    49       memcpy(aDst, aSrc, packedStride);
    50       aSrc += aSrcStride;
    51       aDst += packedStride;
    52     }
    53   }
    54 }
    56 void
    57 CopyBGRXSurfaceDataToPackedBGRArray(uint8_t* aSrc, uint8_t* aDst,
    58                                     IntSize aSrcSize, int32_t aSrcStride)
    59 {
    60   int packedStride = aSrcSize.width * 3;
    62   uint8_t* srcPx = aSrc;
    63   uint8_t* dstPx = aDst;
    65   for (int row = 0; row < aSrcSize.height; ++row) {
    66     for (int col = 0; col < aSrcSize.height; ++col) {
    67       dstPx[0] = srcPx[0];
    68       dstPx[1] = srcPx[1];
    69       dstPx[2] = srcPx[2];
    70       // srcPx[3] (unused or alpha component) dropped on floor
    71       srcPx += 4;
    72       dstPx += 3;
    73     }
    74     srcPx = aSrc += aSrcStride;
    75     dstPx = aDst += packedStride;
    76   }
    77 }
    79 uint8_t*
    80 SurfaceToPackedBGRA(DataSourceSurface *aSurface)
    81 {
    82   SurfaceFormat format = aSurface->GetFormat();
    83   if (format != SurfaceFormat::B8G8R8A8 && format != SurfaceFormat::B8G8R8X8) {
    84     return nullptr;
    85   }
    87   IntSize size = aSurface->GetSize();
    89   uint8_t* imageBuffer = new (std::nothrow) uint8_t[size.width * size.height * sizeof(uint32_t)];
    90   if (!imageBuffer) {
    91     return nullptr;
    92   }
    94   DataSourceSurface::MappedSurface map;
    95   if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) {
    96     delete [] imageBuffer;
    97     return nullptr;
    98   }
   100   CopySurfaceDataToPackedArray(map.mData, imageBuffer, size,
   101                                map.mStride, 4 * sizeof(uint8_t));
   103   aSurface->Unmap();
   105   if (format == SurfaceFormat::B8G8R8X8) {
   106     // Convert BGRX to BGRA by setting a to 255.
   107     ConvertBGRXToBGRA(reinterpret_cast<uint8_t *>(imageBuffer), size, size.width * sizeof(uint32_t));
   108   }
   110   return imageBuffer;
   111 }
   113 uint8_t*
   114 SurfaceToPackedBGR(DataSourceSurface *aSurface)
   115 {
   116   SurfaceFormat format = aSurface->GetFormat();
   117   MOZ_ASSERT(format == SurfaceFormat::B8G8R8X8, "Format not supported");
   119   if (format != SurfaceFormat::B8G8R8X8) {
   120     // To support B8G8R8A8 we'd need to un-pre-multiply alpha
   121     return nullptr;
   122   }
   124   IntSize size = aSurface->GetSize();
   126   uint8_t* imageBuffer = new (std::nothrow) uint8_t[size.width * size.height * 3 * sizeof(uint8_t)];
   127   if (!imageBuffer) {
   128     return nullptr;
   129   }
   131   DataSourceSurface::MappedSurface map;
   132   if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) {
   133     delete [] imageBuffer;
   134     return nullptr;
   135   }
   137   CopyBGRXSurfaceDataToPackedBGRArray(map.mData, imageBuffer, size,
   138                                       map.mStride);
   140   aSurface->Unmap();
   142   return imageBuffer;
   143 }
   145 size_t
   146 BufferSizeFromStrideAndHeight(int32_t aStride,
   147                               int32_t aHeight,
   148                               int32_t aExtraBytes)
   149 {
   150   if (MOZ_UNLIKELY(aHeight <= 0)) {
   151     return 0;
   152   }
   154   // We limit the length returned to values that can be represented by int32_t
   155   // because we don't want to allocate buffers any bigger than that. This
   156   // allows for a buffer size of over 2 GiB which is already rediculously
   157   // large and will make the process janky. (Note the choice of the signed type
   158   // is deliberate because we specifically don't want the returned value to
   159   // overflow if someone stores the buffer length in an int32_t variable.)
   161   CheckedInt32 requiredBytes =
   162     CheckedInt32(aStride) * CheckedInt32(aHeight) + CheckedInt32(aExtraBytes);
   163   if (MOZ_UNLIKELY(!requiredBytes.isValid())) {
   164     gfxWarning() << "Buffer size too big; returning zero";
   165     return 0;
   166   }
   167   return requiredBytes.value();
   168 }
   170 }
   171 }

mercurial