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.

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

mercurial