gfx/2d/ImageScaling.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 "ImageScaling.h"
michael@0 7 #include "2D.h"
michael@0 8 #include "DataSurfaceHelpers.h"
michael@0 9
michael@0 10 #include <math.h>
michael@0 11 #include <algorithm>
michael@0 12
michael@0 13 using namespace std;
michael@0 14
michael@0 15 namespace mozilla {
michael@0 16 namespace gfx {
michael@0 17
michael@0 18 inline uint32_t Avg2x2(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
michael@0 19 {
michael@0 20 // Prepare half-adder work
michael@0 21 uint32_t sum = a ^ b ^ c;
michael@0 22 uint32_t carry = (a & b) | (a & c) | (b & c);
michael@0 23
michael@0 24 // Before shifting, mask lower order bits of each byte to avoid underflow.
michael@0 25 uint32_t mask = 0xfefefefe;
michael@0 26
michael@0 27 // Add d to sum and divide by 2.
michael@0 28 sum = (((sum ^ d) & mask) >> 1) + (sum & d);
michael@0 29
michael@0 30 // Sum is now shifted into place relative to carry, add them together.
michael@0 31 return (((sum ^ carry) & mask) >> 1) + (sum & carry);
michael@0 32 }
michael@0 33
michael@0 34 inline uint32_t Avg2(uint32_t a, uint32_t b)
michael@0 35 {
michael@0 36 // Prepare half-adder work
michael@0 37 uint32_t sum = a ^ b;
michael@0 38 uint32_t carry = (a & b);
michael@0 39
michael@0 40 // Before shifting, mask lower order bits of each byte to avoid underflow.
michael@0 41 uint32_t mask = 0xfefefefe;
michael@0 42
michael@0 43 // Add d to sum and divide by 2.
michael@0 44 return ((sum & mask) >> 1) + carry;
michael@0 45 }
michael@0 46
michael@0 47 void
michael@0 48 ImageHalfScaler::ScaleForSize(const IntSize &aSize)
michael@0 49 {
michael@0 50 uint32_t horizontalDownscales = 0;
michael@0 51 uint32_t verticalDownscales = 0;
michael@0 52
michael@0 53 IntSize scaleSize = mOrigSize;
michael@0 54 while ((scaleSize.height / 2) > aSize.height) {
michael@0 55 verticalDownscales++;
michael@0 56 scaleSize.height /= 2;
michael@0 57 }
michael@0 58
michael@0 59 while ((scaleSize.width / 2) > aSize.width) {
michael@0 60 horizontalDownscales++;
michael@0 61 scaleSize.width /= 2;
michael@0 62 }
michael@0 63
michael@0 64 if (scaleSize == mOrigSize) {
michael@0 65 return;
michael@0 66 }
michael@0 67
michael@0 68 IntSize internalSurfSize;
michael@0 69
michael@0 70 internalSurfSize.width = max(scaleSize.width, mOrigSize.width / 2);
michael@0 71 internalSurfSize.height = max(scaleSize.height, mOrigSize.height / 2);
michael@0 72
michael@0 73 mStride = internalSurfSize.width * 4;
michael@0 74 if (mStride % 16) {
michael@0 75 mStride += 16 - (mStride % 16);
michael@0 76 }
michael@0 77
michael@0 78 delete [] mDataStorage;
michael@0 79 // Allocate 15 bytes extra to make sure we can get 16 byte alignment. We
michael@0 80 // should add tools for this, see bug 751696.
michael@0 81 size_t bufLen = BufferSizeFromStrideAndHeight(mStride, internalSurfSize.height, 15);
michael@0 82 if (bufLen == 0) {
michael@0 83 mSize.SizeTo(0, 0);
michael@0 84 mDataStorage = nullptr;
michael@0 85 return;
michael@0 86 }
michael@0 87 mDataStorage = new uint8_t[bufLen];
michael@0 88
michael@0 89 if (uintptr_t(mDataStorage) % 16) {
michael@0 90 // Our storage does not start at a 16-byte boundary. Make sure mData does!
michael@0 91 mData = (uint8_t*)(uintptr_t(mDataStorage) +
michael@0 92 (16 - (uintptr_t(mDataStorage) % 16)));
michael@0 93 } else {
michael@0 94 mData = mDataStorage;
michael@0 95 }
michael@0 96
michael@0 97 mSize = scaleSize;
michael@0 98
michael@0 99 /* The surface we sample from might not be even sized, if it's not we will
michael@0 100 * ignore the last row/column. This means we lose some data but it keeps the
michael@0 101 * code very simple. There's also no perfect answer that provides a better
michael@0 102 * solution.
michael@0 103 */
michael@0 104 IntSize currentSampledSize = mOrigSize;
michael@0 105 uint32_t currentSampledStride = mOrigStride;
michael@0 106 uint8_t *currentSampledData = mOrigData;
michael@0 107
michael@0 108 while (verticalDownscales && horizontalDownscales) {
michael@0 109 if (currentSampledSize.width % 2) {
michael@0 110 currentSampledSize.width -= 1;
michael@0 111 }
michael@0 112 if (currentSampledSize.height % 2) {
michael@0 113 currentSampledSize.height -= 1;
michael@0 114 }
michael@0 115
michael@0 116 HalfImage2D(currentSampledData, currentSampledStride, currentSampledSize,
michael@0 117 mData, mStride);
michael@0 118
michael@0 119 verticalDownscales--;
michael@0 120 horizontalDownscales--;
michael@0 121 currentSampledSize.width /= 2;
michael@0 122 currentSampledSize.height /= 2;
michael@0 123 currentSampledData = mData;
michael@0 124 currentSampledStride = mStride;
michael@0 125 }
michael@0 126
michael@0 127 while (verticalDownscales) {
michael@0 128 if (currentSampledSize.height % 2) {
michael@0 129 currentSampledSize.height -= 1;
michael@0 130 }
michael@0 131
michael@0 132 HalfImageVertical(currentSampledData, currentSampledStride, currentSampledSize,
michael@0 133 mData, mStride);
michael@0 134
michael@0 135 verticalDownscales--;
michael@0 136 currentSampledSize.height /= 2;
michael@0 137 currentSampledData = mData;
michael@0 138 currentSampledStride = mStride;
michael@0 139 }
michael@0 140
michael@0 141
michael@0 142 while (horizontalDownscales) {
michael@0 143 if (currentSampledSize.width % 2) {
michael@0 144 currentSampledSize.width -= 1;
michael@0 145 }
michael@0 146
michael@0 147 HalfImageHorizontal(currentSampledData, currentSampledStride, currentSampledSize,
michael@0 148 mData, mStride);
michael@0 149
michael@0 150 horizontalDownscales--;
michael@0 151 currentSampledSize.width /= 2;
michael@0 152 currentSampledData = mData;
michael@0 153 currentSampledStride = mStride;
michael@0 154 }
michael@0 155 }
michael@0 156
michael@0 157 void
michael@0 158 ImageHalfScaler::HalfImage2D(uint8_t *aSource, int32_t aSourceStride,
michael@0 159 const IntSize &aSourceSize, uint8_t *aDest,
michael@0 160 uint32_t aDestStride)
michael@0 161 {
michael@0 162 #ifdef USE_SSE2
michael@0 163 if (Factory::HasSSE2()) {
michael@0 164 HalfImage2D_SSE2(aSource, aSourceStride, aSourceSize, aDest, aDestStride);
michael@0 165 } else
michael@0 166 #endif
michael@0 167 {
michael@0 168 HalfImage2D_C(aSource, aSourceStride, aSourceSize, aDest, aDestStride);
michael@0 169 }
michael@0 170 }
michael@0 171
michael@0 172 void
michael@0 173 ImageHalfScaler::HalfImageVertical(uint8_t *aSource, int32_t aSourceStride,
michael@0 174 const IntSize &aSourceSize, uint8_t *aDest,
michael@0 175 uint32_t aDestStride)
michael@0 176 {
michael@0 177 #ifdef USE_SSE2
michael@0 178 if (Factory::HasSSE2()) {
michael@0 179 HalfImageVertical_SSE2(aSource, aSourceStride, aSourceSize, aDest, aDestStride);
michael@0 180 } else
michael@0 181 #endif
michael@0 182 {
michael@0 183 HalfImageVertical_C(aSource, aSourceStride, aSourceSize, aDest, aDestStride);
michael@0 184 }
michael@0 185 }
michael@0 186
michael@0 187 void
michael@0 188 ImageHalfScaler::HalfImageHorizontal(uint8_t *aSource, int32_t aSourceStride,
michael@0 189 const IntSize &aSourceSize, uint8_t *aDest,
michael@0 190 uint32_t aDestStride)
michael@0 191 {
michael@0 192 #ifdef USE_SSE2
michael@0 193 if (Factory::HasSSE2()) {
michael@0 194 HalfImageHorizontal_SSE2(aSource, aSourceStride, aSourceSize, aDest, aDestStride);
michael@0 195 } else
michael@0 196 #endif
michael@0 197 {
michael@0 198 HalfImageHorizontal_C(aSource, aSourceStride, aSourceSize, aDest, aDestStride);
michael@0 199 }
michael@0 200 }
michael@0 201
michael@0 202 void
michael@0 203 ImageHalfScaler::HalfImage2D_C(uint8_t *aSource, int32_t aSourceStride,
michael@0 204 const IntSize &aSourceSize, uint8_t *aDest,
michael@0 205 uint32_t aDestStride)
michael@0 206 {
michael@0 207 for (int y = 0; y < aSourceSize.height; y += 2) {
michael@0 208 uint32_t *storage = (uint32_t*)(aDest + (y / 2) * aDestStride);
michael@0 209 for (int x = 0; x < aSourceSize.width; x += 2) {
michael@0 210 uint8_t *upperRow = aSource + (y * aSourceStride + x * 4);
michael@0 211 uint8_t *lowerRow = aSource + ((y + 1) * aSourceStride + x * 4);
michael@0 212
michael@0 213 *storage++ = Avg2x2(*(uint32_t*)upperRow, *((uint32_t*)upperRow + 1),
michael@0 214 *(uint32_t*)lowerRow, *((uint32_t*)lowerRow + 1));
michael@0 215 }
michael@0 216 }
michael@0 217 }
michael@0 218
michael@0 219 void
michael@0 220 ImageHalfScaler::HalfImageVertical_C(uint8_t *aSource, int32_t aSourceStride,
michael@0 221 const IntSize &aSourceSize, uint8_t *aDest,
michael@0 222 uint32_t aDestStride)
michael@0 223 {
michael@0 224 for (int y = 0; y < aSourceSize.height; y += 2) {
michael@0 225 uint32_t *storage = (uint32_t*)(aDest + (y / 2) * aDestStride);
michael@0 226 for (int x = 0; x < aSourceSize.width; x++) {
michael@0 227 uint32_t *upperRow = (uint32_t*)(aSource + (y * aSourceStride + x * 4));
michael@0 228 uint32_t *lowerRow = (uint32_t*)(aSource + ((y + 1) * aSourceStride + x * 4));
michael@0 229
michael@0 230 *storage++ = Avg2(*upperRow, *lowerRow);
michael@0 231 }
michael@0 232 }
michael@0 233 }
michael@0 234
michael@0 235 void
michael@0 236 ImageHalfScaler::HalfImageHorizontal_C(uint8_t *aSource, int32_t aSourceStride,
michael@0 237 const IntSize &aSourceSize, uint8_t *aDest,
michael@0 238 uint32_t aDestStride)
michael@0 239 {
michael@0 240 for (int y = 0; y < aSourceSize.height; y++) {
michael@0 241 uint32_t *storage = (uint32_t*)(aDest + y * aDestStride);
michael@0 242 for (int x = 0; x < aSourceSize.width; x+= 2) {
michael@0 243 uint32_t *pixels = (uint32_t*)(aSource + (y * aSourceStride + x * 4));
michael@0 244
michael@0 245 *storage++ = Avg2(*pixels, *(pixels + 1));
michael@0 246 }
michael@0 247 }
michael@0 248 }
michael@0 249
michael@0 250 }
michael@0 251 }

mercurial