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.
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 "mozilla/layers/YCbCrImageDataSerializer.h" |
michael@0 | 7 | #include <string.h> // for memcpy |
michael@0 | 8 | #include "gfx2DGlue.h" // for ToIntSize |
michael@0 | 9 | #include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory |
michael@0 | 10 | #include "mozilla/gfx/BaseSize.h" // for BaseSize |
michael@0 | 11 | #include "mozilla/gfx/Types.h" |
michael@0 | 12 | #include "mozilla/mozalloc.h" // for operator delete |
michael@0 | 13 | #include "yuv_convert.h" // for ConvertYCbCrToRGB32, etc |
michael@0 | 14 | |
michael@0 | 15 | #define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3) |
michael@0 | 16 | |
michael@0 | 17 | namespace mozilla { |
michael@0 | 18 | |
michael@0 | 19 | using namespace gfx; |
michael@0 | 20 | |
michael@0 | 21 | namespace layers { |
michael@0 | 22 | |
michael@0 | 23 | // The Data is layed out as follows: |
michael@0 | 24 | // |
michael@0 | 25 | // +-----------------+ -++ --+ --+ <-- Beginning of the buffer |
michael@0 | 26 | // | YCbCrBufferInfo | | | | |
michael@0 | 27 | // +-----------------+ --+ | | |
michael@0 | 28 | // | data | | | YCbCrBufferInfo->[mY/mCb/mCr]Offset |
michael@0 | 29 | // +-----------------+ ------+ | |
michael@0 | 30 | // | data | | |
michael@0 | 31 | // +-----------------+ ----------+ |
michael@0 | 32 | // | data | |
michael@0 | 33 | // +-----------------+ |
michael@0 | 34 | // |
michael@0 | 35 | // There can be padding between the blocks above to keep word alignment. |
michael@0 | 36 | |
michael@0 | 37 | // Structure written at the beginning og the data blob containing the image |
michael@0 | 38 | // (as shown in the figure above). It contains the necessary informations to |
michael@0 | 39 | // read the image in the blob. |
michael@0 | 40 | struct YCbCrBufferInfo |
michael@0 | 41 | { |
michael@0 | 42 | uint32_t mYOffset; |
michael@0 | 43 | uint32_t mCbOffset; |
michael@0 | 44 | uint32_t mCrOffset; |
michael@0 | 45 | uint32_t mYStride; |
michael@0 | 46 | uint32_t mYWidth; |
michael@0 | 47 | uint32_t mYHeight; |
michael@0 | 48 | uint32_t mCbCrStride; |
michael@0 | 49 | uint32_t mCbCrWidth; |
michael@0 | 50 | uint32_t mCbCrHeight; |
michael@0 | 51 | StereoMode mStereoMode; |
michael@0 | 52 | }; |
michael@0 | 53 | |
michael@0 | 54 | static YCbCrBufferInfo* GetYCbCrBufferInfo(uint8_t* aData, size_t aDataSize) |
michael@0 | 55 | { |
michael@0 | 56 | return aDataSize >= sizeof(YCbCrBufferInfo) |
michael@0 | 57 | ? reinterpret_cast<YCbCrBufferInfo*>(aData) |
michael@0 | 58 | : nullptr; |
michael@0 | 59 | } |
michael@0 | 60 | |
michael@0 | 61 | void YCbCrImageDataDeserializerBase::Validate() |
michael@0 | 62 | { |
michael@0 | 63 | mIsValid = false; |
michael@0 | 64 | if (!mData) { |
michael@0 | 65 | return; |
michael@0 | 66 | } |
michael@0 | 67 | YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
michael@0 | 68 | if (!info) { |
michael@0 | 69 | return; |
michael@0 | 70 | } |
michael@0 | 71 | size_t requiredSize = ComputeMinBufferSize( |
michael@0 | 72 | IntSize(info->mYWidth, info->mYHeight), |
michael@0 | 73 | info->mYStride, |
michael@0 | 74 | IntSize(info->mCbCrWidth, info->mCbCrHeight), |
michael@0 | 75 | info->mCbCrStride); |
michael@0 | 76 | mIsValid = requiredSize <= mDataSize; |
michael@0 | 77 | |
michael@0 | 78 | } |
michael@0 | 79 | |
michael@0 | 80 | uint8_t* YCbCrImageDataDeserializerBase::GetYData() |
michael@0 | 81 | { |
michael@0 | 82 | YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
michael@0 | 83 | return reinterpret_cast<uint8_t*>(info) + info->mYOffset; |
michael@0 | 84 | } |
michael@0 | 85 | |
michael@0 | 86 | uint8_t* YCbCrImageDataDeserializerBase::GetCbData() |
michael@0 | 87 | { |
michael@0 | 88 | YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
michael@0 | 89 | return reinterpret_cast<uint8_t*>(info) + info->mCbOffset; |
michael@0 | 90 | } |
michael@0 | 91 | |
michael@0 | 92 | uint8_t* YCbCrImageDataDeserializerBase::GetCrData() |
michael@0 | 93 | { |
michael@0 | 94 | YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
michael@0 | 95 | return reinterpret_cast<uint8_t*>(info) + info->mCrOffset; |
michael@0 | 96 | } |
michael@0 | 97 | |
michael@0 | 98 | uint8_t* YCbCrImageDataDeserializerBase::GetData() |
michael@0 | 99 | { |
michael@0 | 100 | YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
michael@0 | 101 | return (reinterpret_cast<uint8_t*>(info)) + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo)); |
michael@0 | 102 | } |
michael@0 | 103 | |
michael@0 | 104 | uint32_t YCbCrImageDataDeserializerBase::GetYStride() |
michael@0 | 105 | { |
michael@0 | 106 | YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
michael@0 | 107 | return info->mYStride; |
michael@0 | 108 | } |
michael@0 | 109 | |
michael@0 | 110 | uint32_t YCbCrImageDataDeserializerBase::GetCbCrStride() |
michael@0 | 111 | { |
michael@0 | 112 | YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
michael@0 | 113 | return info->mCbCrStride; |
michael@0 | 114 | } |
michael@0 | 115 | |
michael@0 | 116 | gfx::IntSize YCbCrImageDataDeserializerBase::GetYSize() |
michael@0 | 117 | { |
michael@0 | 118 | YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
michael@0 | 119 | return gfx::IntSize(info->mYWidth, info->mYHeight); |
michael@0 | 120 | } |
michael@0 | 121 | |
michael@0 | 122 | gfx::IntSize YCbCrImageDataDeserializerBase::GetCbCrSize() |
michael@0 | 123 | { |
michael@0 | 124 | YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
michael@0 | 125 | return gfx::IntSize(info->mCbCrWidth, info->mCbCrHeight); |
michael@0 | 126 | } |
michael@0 | 127 | |
michael@0 | 128 | StereoMode YCbCrImageDataDeserializerBase::GetStereoMode() |
michael@0 | 129 | { |
michael@0 | 130 | YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
michael@0 | 131 | return info->mStereoMode; |
michael@0 | 132 | } |
michael@0 | 133 | |
michael@0 | 134 | // Offset in bytes |
michael@0 | 135 | static size_t ComputeOffset(uint32_t aHeight, uint32_t aStride) |
michael@0 | 136 | { |
michael@0 | 137 | return MOZ_ALIGN_WORD(aHeight * aStride); |
michael@0 | 138 | } |
michael@0 | 139 | |
michael@0 | 140 | // Minimum required shmem size in bytes |
michael@0 | 141 | size_t |
michael@0 | 142 | YCbCrImageDataDeserializerBase::ComputeMinBufferSize(const gfx::IntSize& aYSize, |
michael@0 | 143 | uint32_t aYStride, |
michael@0 | 144 | const gfx::IntSize& aCbCrSize, |
michael@0 | 145 | uint32_t aCbCrStride) |
michael@0 | 146 | { |
michael@0 | 147 | return ComputeOffset(aYSize.height, aYStride) |
michael@0 | 148 | + 2 * ComputeOffset(aCbCrSize.height, aCbCrStride) |
michael@0 | 149 | + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo)); |
michael@0 | 150 | } |
michael@0 | 151 | |
michael@0 | 152 | // Minimum required shmem size in bytes |
michael@0 | 153 | size_t |
michael@0 | 154 | YCbCrImageDataDeserializerBase::ComputeMinBufferSize(const gfx::IntSize& aYSize, |
michael@0 | 155 | const gfx::IntSize& aCbCrSize) |
michael@0 | 156 | { |
michael@0 | 157 | return ComputeMinBufferSize(aYSize, aYSize.width, aCbCrSize, aCbCrSize.width); |
michael@0 | 158 | } |
michael@0 | 159 | |
michael@0 | 160 | // Offset in bytes |
michael@0 | 161 | static size_t ComputeOffset(uint32_t aSize) |
michael@0 | 162 | { |
michael@0 | 163 | return MOZ_ALIGN_WORD(aSize); |
michael@0 | 164 | } |
michael@0 | 165 | |
michael@0 | 166 | // Minimum required shmem size in bytes |
michael@0 | 167 | size_t |
michael@0 | 168 | YCbCrImageDataDeserializerBase::ComputeMinBufferSize(uint32_t aSize) |
michael@0 | 169 | { |
michael@0 | 170 | return ComputeOffset(aSize) + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo)); |
michael@0 | 171 | } |
michael@0 | 172 | |
michael@0 | 173 | void |
michael@0 | 174 | YCbCrImageDataSerializer::InitializeBufferInfo(uint32_t aYOffset, |
michael@0 | 175 | uint32_t aCbOffset, |
michael@0 | 176 | uint32_t aCrOffset, |
michael@0 | 177 | uint32_t aYStride, |
michael@0 | 178 | uint32_t aCbCrStride, |
michael@0 | 179 | const gfx::IntSize& aYSize, |
michael@0 | 180 | const gfx::IntSize& aCbCrSize, |
michael@0 | 181 | StereoMode aStereoMode) |
michael@0 | 182 | { |
michael@0 | 183 | YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
michael@0 | 184 | MOZ_ASSERT(info); // OK to assert here, this method is client-side-only |
michael@0 | 185 | uint32_t info_size = MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo)); |
michael@0 | 186 | info->mYOffset = info_size + aYOffset; |
michael@0 | 187 | info->mCbOffset = info_size + aCbOffset; |
michael@0 | 188 | info->mCrOffset = info_size + aCrOffset; |
michael@0 | 189 | info->mYStride = aYStride; |
michael@0 | 190 | info->mYWidth = aYSize.width; |
michael@0 | 191 | info->mYHeight = aYSize.height; |
michael@0 | 192 | info->mCbCrStride = aCbCrStride; |
michael@0 | 193 | info->mCbCrWidth = aCbCrSize.width; |
michael@0 | 194 | info->mCbCrHeight = aCbCrSize.height; |
michael@0 | 195 | info->mStereoMode = aStereoMode; |
michael@0 | 196 | Validate(); |
michael@0 | 197 | } |
michael@0 | 198 | |
michael@0 | 199 | void |
michael@0 | 200 | YCbCrImageDataSerializer::InitializeBufferInfo(uint32_t aYStride, |
michael@0 | 201 | uint32_t aCbCrStride, |
michael@0 | 202 | const gfx::IntSize& aYSize, |
michael@0 | 203 | const gfx::IntSize& aCbCrSize, |
michael@0 | 204 | StereoMode aStereoMode) |
michael@0 | 205 | { |
michael@0 | 206 | uint32_t yOffset = 0; |
michael@0 | 207 | uint32_t cbOffset = yOffset + MOZ_ALIGN_WORD(aYStride * aYSize.height); |
michael@0 | 208 | uint32_t crOffset = cbOffset + MOZ_ALIGN_WORD(aCbCrStride * aCbCrSize.height); |
michael@0 | 209 | return InitializeBufferInfo(yOffset, cbOffset, crOffset, |
michael@0 | 210 | aYStride, aCbCrStride, aYSize, aCbCrSize, aStereoMode); |
michael@0 | 211 | } |
michael@0 | 212 | |
michael@0 | 213 | void |
michael@0 | 214 | YCbCrImageDataSerializer::InitializeBufferInfo(const gfx::IntSize& aYSize, |
michael@0 | 215 | const gfx::IntSize& aCbCrSize, |
michael@0 | 216 | StereoMode aStereoMode) |
michael@0 | 217 | { |
michael@0 | 218 | return InitializeBufferInfo(aYSize.width, aCbCrSize.width, aYSize, aCbCrSize, aStereoMode); |
michael@0 | 219 | } |
michael@0 | 220 | |
michael@0 | 221 | static void CopyLineWithSkip(const uint8_t* src, uint8_t* dst, uint32_t len, uint32_t skip) { |
michael@0 | 222 | for (uint32_t i = 0; i < len; ++i) { |
michael@0 | 223 | *dst = *src; |
michael@0 | 224 | src += 1 + skip; |
michael@0 | 225 | ++dst; |
michael@0 | 226 | } |
michael@0 | 227 | } |
michael@0 | 228 | |
michael@0 | 229 | bool |
michael@0 | 230 | YCbCrImageDataSerializer::CopyData(const uint8_t* aYData, |
michael@0 | 231 | const uint8_t* aCbData, const uint8_t* aCrData, |
michael@0 | 232 | gfx::IntSize aYSize, uint32_t aYStride, |
michael@0 | 233 | gfx::IntSize aCbCrSize, uint32_t aCbCrStride, |
michael@0 | 234 | uint32_t aYSkip, uint32_t aCbCrSkip) |
michael@0 | 235 | { |
michael@0 | 236 | if (!IsValid() || GetYSize() != aYSize || GetCbCrSize() != aCbCrSize) { |
michael@0 | 237 | return false; |
michael@0 | 238 | } |
michael@0 | 239 | for (int i = 0; i < aYSize.height; ++i) { |
michael@0 | 240 | if (aYSkip == 0) { |
michael@0 | 241 | // fast path |
michael@0 | 242 | memcpy(GetYData() + i * GetYStride(), |
michael@0 | 243 | aYData + i * aYStride, |
michael@0 | 244 | aYSize.width); |
michael@0 | 245 | } else { |
michael@0 | 246 | // slower path |
michael@0 | 247 | CopyLineWithSkip(aYData + i * aYStride, |
michael@0 | 248 | GetYData() + i * GetYStride(), |
michael@0 | 249 | aYSize.width, aYSkip); |
michael@0 | 250 | } |
michael@0 | 251 | } |
michael@0 | 252 | for (int i = 0; i < aCbCrSize.height; ++i) { |
michael@0 | 253 | if (aCbCrSkip == 0) { |
michael@0 | 254 | // fast path |
michael@0 | 255 | memcpy(GetCbData() + i * GetCbCrStride(), |
michael@0 | 256 | aCbData + i * aCbCrStride, |
michael@0 | 257 | aCbCrSize.width); |
michael@0 | 258 | memcpy(GetCrData() + i * GetCbCrStride(), |
michael@0 | 259 | aCrData + i * aCbCrStride, |
michael@0 | 260 | aCbCrSize.width); |
michael@0 | 261 | } else { |
michael@0 | 262 | // slower path |
michael@0 | 263 | CopyLineWithSkip(aCbData + i * aCbCrStride, |
michael@0 | 264 | GetCbData() + i * GetCbCrStride(), |
michael@0 | 265 | aCbCrSize.width, aCbCrSkip); |
michael@0 | 266 | CopyLineWithSkip(aCrData + i * aCbCrStride, |
michael@0 | 267 | GetCrData() + i * GetCbCrStride(), |
michael@0 | 268 | aCbCrSize.width, aCbCrSkip); |
michael@0 | 269 | } |
michael@0 | 270 | } |
michael@0 | 271 | return true; |
michael@0 | 272 | } |
michael@0 | 273 | |
michael@0 | 274 | TemporaryRef<DataSourceSurface> |
michael@0 | 275 | YCbCrImageDataDeserializer::ToDataSourceSurface() |
michael@0 | 276 | { |
michael@0 | 277 | RefPtr<DataSourceSurface> result = |
michael@0 | 278 | Factory::CreateDataSourceSurface(GetYSize(), gfx::SurfaceFormat::B8G8R8X8); |
michael@0 | 279 | |
michael@0 | 280 | DataSourceSurface::MappedSurface map; |
michael@0 | 281 | result->Map(DataSourceSurface::MapType::WRITE, &map); |
michael@0 | 282 | |
michael@0 | 283 | gfx::ConvertYCbCrToRGB32(GetYData(), GetCbData(), GetCrData(), |
michael@0 | 284 | map.mData, |
michael@0 | 285 | 0, 0, //pic x and y |
michael@0 | 286 | GetYSize().width, GetYSize().height, |
michael@0 | 287 | GetYStride(), GetCbCrStride(), |
michael@0 | 288 | map.mStride, |
michael@0 | 289 | gfx::YV12); |
michael@0 | 290 | result->Unmap(); |
michael@0 | 291 | return result.forget(); |
michael@0 | 292 | } |
michael@0 | 293 | |
michael@0 | 294 | |
michael@0 | 295 | } // namespace |
michael@0 | 296 | } // namespace |