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.

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

mercurial