Coverage Report

Created: 2018-09-25 14:53

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