OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkCodecPriv.h" | 8 #include "SkCodecPriv.h" |
9 #include "SkScaledCodec.h" | 9 #include "SkScaledCodec.h" |
10 #include "SkStream.h" | 10 #include "SkStream.h" |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 int scaledHeight = get_scaled_dimension(this->getInfo().height(), sampleSize
); | 93 int scaledHeight = get_scaled_dimension(this->getInfo().height(), sampleSize
); |
94 | 94 |
95 // Return the calculated output dimensions for the given scale | 95 // Return the calculated output dimensions for the given scale |
96 scaledCodecDimensions = SkISize::Make(scaledWidth, scaledHeight); | 96 scaledCodecDimensions = SkISize::Make(scaledWidth, scaledHeight); |
97 | 97 |
98 return best_scaled_dimensions(this->getInfo().dimensions(), nativeDimensions
, | 98 return best_scaled_dimensions(this->getInfo().dimensions(), nativeDimensions
, |
99 scaledCodecDimensions, desiredScale); | 99 scaledCodecDimensions, desiredScale); |
100 } | 100 } |
101 | 101 |
102 // check if scaling to dstInfo size from srcInfo size using sampleSize is possib
le | 102 // check if scaling to dstInfo size from srcInfo size using sampleSize is possib
le |
103 static bool scaling_supported(const SkImageInfo& dstInfo, const SkImageInfo& src
Info, | 103 static bool scaling_supported(const SkISize& dstDim, const SkISize& srcDim, |
104 int* sampleX, int* sampleY) { | 104 int* sampleX, int* sampleY) { |
105 SkScaledCodec::ComputeSampleSize(dstInfo, srcInfo, sampleX, sampleY); | 105 SkScaledCodec::ComputeSampleSize(dstDim, srcDim, sampleX, sampleY); |
106 const int dstWidth = dstInfo.width(); | 106 const int dstWidth = dstDim.width(); |
107 const int dstHeight = dstInfo.height(); | 107 const int dstHeight = dstDim.height(); |
108 const int srcWidth = srcInfo.width(); | 108 const int srcWidth = srcDim.width(); |
109 const int srcHeight = srcInfo.height(); | 109 const int srcHeight = srcDim.height(); |
110 // only support down sampling, not up sampling | 110 // only support down sampling, not up sampling |
111 if (dstWidth > srcWidth || dstHeight > srcHeight) { | 111 if (dstWidth > srcWidth || dstHeight > srcHeight) { |
112 return false; | 112 return false; |
113 } | 113 } |
114 // check that srcWidth is scaled down by an integer value | 114 // check that srcWidth is scaled down by an integer value |
115 if (get_scaled_dimension(srcWidth, *sampleX) != dstWidth) { | 115 if (get_scaled_dimension(srcWidth, *sampleX) != dstWidth) { |
116 return false; | 116 return false; |
117 } | 117 } |
118 // check that src height is scaled down by an integer value | 118 // check that src height is scaled down by an integer value |
119 if (get_scaled_dimension(srcHeight, *sampleY) != dstHeight) { | 119 if (get_scaled_dimension(srcHeight, *sampleY) != dstHeight) { |
120 return false; | 120 return false; |
121 } | 121 } |
122 // sampleX and sampleY should be equal unless the original sampleSize reques
ted was larger | 122 // sampleX and sampleY should be equal unless the original sampleSize reques
ted was larger |
123 // than srcWidth or srcHeight. If so, the result of this is dstWidth or dstH
eight = 1. | 123 // than srcWidth or srcHeight. If so, the result of this is dstWidth or dstH
eight = 1. |
124 // This functionality allows for tall thin images to still be scaled down by
scaling factors. | 124 // This functionality allows for tall thin images to still be scaled down by
scaling factors. |
125 if (*sampleX != *sampleY){ | 125 if (*sampleX != *sampleY){ |
126 if (1 != dstWidth && 1 != dstHeight) { | 126 if (1 != dstWidth && 1 != dstHeight) { |
127 return false; | 127 return false; |
128 } | 128 } |
129 } | 129 } |
130 return true; | 130 return true; |
131 } | 131 } |
132 | 132 |
| 133 bool SkScaledCodec::onDimensionsSupported(const SkISize& dim) { |
| 134 // Check with fCodec first. No need to call the non-virtual version, which |
| 135 // just checks if it matches the original, since a match means this method |
| 136 // will not be called. |
| 137 if (fCodec->onDimensionsSupported(dim)) { |
| 138 return true; |
| 139 } |
| 140 |
| 141 // FIXME: These variables are unused, but are needed by scaling_supported. |
| 142 // This class could also cache these values, and avoid calling this in |
| 143 // onGetPixels (since getPixels already calls it). |
| 144 int sampleX; |
| 145 int sampleY; |
| 146 return scaling_supported(dim, this->getInfo().dimensions(), &sampleX, &sampl
eY); |
| 147 } |
| 148 |
133 // calculates sampleSize in x and y direction | 149 // calculates sampleSize in x and y direction |
134 void SkScaledCodec::ComputeSampleSize(const SkImageInfo& dstInfo, const SkImageI
nfo& srcInfo, | 150 void SkScaledCodec::ComputeSampleSize(const SkISize& dstDim, const SkISize& srcD
im, |
135 int* sampleXPtr, int* sampleYPtr) { | 151 int* sampleXPtr, int* sampleYPtr) { |
136 int srcWidth = srcInfo.width(); | 152 int srcWidth = srcDim.width(); |
137 int dstWidth = dstInfo.width(); | 153 int dstWidth = dstDim.width(); |
138 int srcHeight = srcInfo.height(); | 154 int srcHeight = srcDim.height(); |
139 int dstHeight = dstInfo.height(); | 155 int dstHeight = dstDim.height(); |
140 | 156 |
141 int sampleX = srcWidth / dstWidth; | 157 int sampleX = srcWidth / dstWidth; |
142 int sampleY = srcHeight / dstHeight; | 158 int sampleY = srcHeight / dstHeight; |
143 | 159 |
144 // only support down sampling, not up sampling | 160 // only support down sampling, not up sampling |
145 SkASSERT(dstWidth <= srcWidth); | 161 SkASSERT(dstWidth <= srcWidth); |
146 SkASSERT(dstHeight <= srcHeight); | 162 SkASSERT(dstHeight <= srcHeight); |
147 | 163 |
148 // sampleX and sampleY should be equal unless the original sampleSize reques
ted was | 164 // sampleX and sampleY should be equal unless the original sampleSize reques
ted was |
149 // larger than srcWidth or srcHeight. | 165 // larger than srcWidth or srcHeight. |
(...skipping 26 matching lines...) Expand all Loading... |
176 | 192 |
177 // TODO: Implement subsetting in onGetPixels which works when and when not sampl
ing | 193 // TODO: Implement subsetting in onGetPixels which works when and when not sampl
ing |
178 | 194 |
179 SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, voi
d* dst, | 195 SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, voi
d* dst, |
180 size_t rowBytes, const Options& optio
ns, | 196 size_t rowBytes, const Options& optio
ns, |
181 SkPMColor ctable[], int* ctableCount)
{ | 197 SkPMColor ctable[], int* ctableCount)
{ |
182 | 198 |
183 if (options.fSubset) { | 199 if (options.fSubset) { |
184 // Subsets are not supported. | 200 // Subsets are not supported. |
185 return kUnimplemented; | 201 return kUnimplemented; |
186 } | |
187 | |
188 // FIXME: If no scaling/subsets are requested, we can call fCodec->getPixels
. | |
189 Result result = fCodec->startScanlineDecode(requestedInfo, &options, ctable,
ctableCount); | |
190 if (kSuccess == result) { | |
191 // native decode supported | |
192 switch (fCodec->getScanlineOrder()) { | |
193 case SkCodec::kTopDown_SkScanlineOrder: | |
194 case SkCodec::kBottomUp_SkScanlineOrder: | |
195 case SkCodec::kNone_SkScanlineOrder: | |
196 return fCodec->getScanlines(dst, requestedInfo.height(), rowByte
s); | |
197 case SkCodec::kOutOfOrder_SkScanlineOrder: { | |
198 for (int y = 0; y < requestedInfo.height(); y++) { | |
199 int dstY = fCodec->nextScanline(); | |
200 void* dstPtr = SkTAddOffset<void>(dst, rowBytes * dstY); | |
201 result = fCodec->getScanlines(dstPtr, 1, rowBytes); | |
202 // FIXME (msarett): Make the SkCodec base class take care of
filling | |
203 // uninitialized pixels so we can return immediately on kInc
ompleteInput. | |
204 if (kSuccess != result && kIncompleteInput != result) { | |
205 return result; | |
206 } | |
207 } | |
208 return result; | |
209 } | |
210 } | |
211 } | 202 } |
212 | 203 |
213 if (kInvalidScale != result) { | 204 if (fCodec->dimensionsSupported(requestedInfo.dimensions())) { |
214 // no scaling requested | 205 return fCodec->getPixels(requestedInfo, dst, rowBytes, &options, ctable,
ctableCount); |
215 return result; | |
216 } | 206 } |
217 | 207 |
218 // scaling requested | 208 // scaling requested |
219 int sampleX; | 209 int sampleX; |
220 int sampleY; | 210 int sampleY; |
221 if (!scaling_supported(requestedInfo, fCodec->getInfo(), &sampleX, &sampleY)
) { | 211 if (!scaling_supported(requestedInfo.dimensions(), fCodec->getInfo().dimensi
ons(), |
| 212 &sampleX, &sampleY)) { |
| 213 // onDimensionsSupported would have returned false, meaning we should ne
ver reach here. |
| 214 SkASSERT(false); |
222 return kInvalidScale; | 215 return kInvalidScale; |
223 } | 216 } |
| 217 |
224 // set first sample pixel in y direction | 218 // set first sample pixel in y direction |
225 int Y0 = get_start_coord(sampleY); | 219 const int Y0 = get_start_coord(sampleY); |
226 | 220 |
227 int dstHeight = requestedInfo.height(); | 221 const int dstHeight = requestedInfo.height(); |
228 int srcHeight = fCodec->getInfo().height(); | 222 const int srcWidth = fCodec->getInfo().width(); |
229 | 223 const int srcHeight = fCodec->getInfo().height(); |
230 SkImageInfo info = requestedInfo; | |
231 // use original height as codec does not support y sampling natively | |
232 info = info.makeWH(requestedInfo.width(), srcHeight); | |
233 | 224 |
234 // update codec with new info | 225 const SkImageInfo info = requestedInfo.makeWH(srcWidth, srcHeight); |
235 // FIXME: The previous call to start returned kInvalidScale. This call may | 226 |
236 // require a rewind. (skbug.com/4284) | 227 Result result = fCodec->startScanlineDecode(info, &options, ctable, ctableCo
unt); |
237 result = fCodec->startScanlineDecode(info, &options, ctable, ctableCount); | 228 |
238 if (kSuccess != result) { | 229 if (kSuccess != result) { |
239 return result; | 230 return result; |
240 } | 231 } |
241 | 232 |
| 233 SkSampler* sampler = fCodec->getSampler(); |
| 234 if (!sampler) { |
| 235 return kUnimplemented; |
| 236 } |
| 237 |
| 238 if (sampler->setSampleX(sampleX) != requestedInfo.width()) { |
| 239 return kInvalidScale; |
| 240 } |
| 241 |
242 switch(fCodec->getScanlineOrder()) { | 242 switch(fCodec->getScanlineOrder()) { |
243 case SkCodec::kTopDown_SkScanlineOrder: { | 243 case SkCodec::kTopDown_SkScanlineOrder: { |
244 result = fCodec->skipScanlines(Y0); | 244 result = fCodec->skipScanlines(Y0); |
245 if (kSuccess != result && kIncompleteInput != result) { | 245 if (kSuccess != result && kIncompleteInput != result) { |
246 return result; | 246 return result; |
247 } | 247 } |
248 for (int y = 0; y < dstHeight; y++) { | 248 for (int y = 0; y < dstHeight; y++) { |
249 result = fCodec->getScanlines(dst, 1, rowBytes); | 249 result = fCodec->getScanlines(dst, 1, rowBytes); |
250 if (kSuccess != result && kIncompleteInput != result) { | 250 if (kSuccess != result && kIncompleteInput != result) { |
251 return result; | 251 return result; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 storagePtr += sampleY * rowBytes; | 292 storagePtr += sampleY * rowBytes; |
293 dst = SkTAddOffset<void>(dst, rowBytes); | 293 dst = SkTAddOffset<void>(dst, rowBytes); |
294 } | 294 } |
295 return result; | 295 return result; |
296 } | 296 } |
297 default: | 297 default: |
298 SkASSERT(false); | 298 SkASSERT(false); |
299 return kUnimplemented; | 299 return kUnimplemented; |
300 } | 300 } |
301 } | 301 } |
OLD | NEW |