Tue, 06 Jan 2015 21:39:09 +0100
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 }