1 | /* |
2 | * Copyright 2015 Google Inc. |
3 | * |
4 | * Use of this source code is governed by a BSD-style license that can be |
5 | * found in the LICENSE file. |
6 | */ |
7 | |
8 | #include "include/core/SkPixmap.h" |
9 | |
10 | #include "include/core/SkBitmap.h" |
11 | #include "include/core/SkData.h" |
12 | #include "include/core/SkSurface.h" |
13 | #include "include/core/SkUnPreMultiply.h" |
14 | #include "include/private/SkColorData.h" |
15 | #include "include/private/SkHalf.h" |
16 | #include "include/private/SkImageInfoPriv.h" |
17 | #include "include/private/SkNx.h" |
18 | #include "include/private/SkTemplates.h" |
19 | #include "include/private/SkTo.h" |
20 | #include "src/core/SkConvertPixels.h" |
21 | #include "src/core/SkDraw.h" |
22 | #include "src/core/SkMask.h" |
23 | #include "src/core/SkMatrixProvider.h" |
24 | #include "src/core/SkPixmapPriv.h" |
25 | #include "src/core/SkRasterClip.h" |
26 | #include "src/core/SkUtils.h" |
27 | #include "src/image/SkReadPixelsRec.h" |
28 | #include "src/shaders/SkImageShader.h" |
29 | |
30 | #include <utility> |
31 | |
32 | ///////////////////////////////////////////////////////////////////////////////////////////////// |
33 | |
34 | void SkPixmap::reset() { |
35 | fPixels = nullptr; |
36 | fRowBytes = 0; |
37 | fInfo = SkImageInfo::MakeUnknown(); |
38 | } |
39 | |
40 | void SkPixmap::reset(const SkImageInfo& info, const void* addr, size_t rowBytes) { |
41 | if (addr) { |
42 | SkASSERT(info.validRowBytes(rowBytes)); |
43 | } |
44 | fPixels = addr; |
45 | fRowBytes = rowBytes; |
46 | fInfo = info; |
47 | } |
48 | |
49 | bool SkPixmap::reset(const SkMask& src) { |
50 | if (SkMask::kA8_Format == src.fFormat) { |
51 | this->reset(SkImageInfo::MakeA8(src.fBounds.width(), src.fBounds.height()), |
52 | src.fImage, src.fRowBytes); |
53 | return true; |
54 | } |
55 | this->reset(); |
56 | return false; |
57 | } |
58 | |
59 | void SkPixmap::setColorSpace(sk_sp<SkColorSpace> cs) { |
60 | fInfo = fInfo.makeColorSpace(std::move(cs)); |
61 | } |
62 | |
63 | bool SkPixmap::(SkPixmap* result, const SkIRect& subset) const { |
64 | SkIRect srcRect, r; |
65 | srcRect.setWH(this->width(), this->height()); |
66 | if (!r.intersect(srcRect, subset)) { |
67 | return false; // r is empty (i.e. no intersection) |
68 | } |
69 | |
70 | // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have |
71 | // exited above. |
72 | SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width())); |
73 | SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height())); |
74 | |
75 | const void* pixels = nullptr; |
76 | if (fPixels) { |
77 | const size_t bpp = fInfo.bytesPerPixel(); |
78 | pixels = (const uint8_t*)fPixels + r.fTop * fRowBytes + r.fLeft * bpp; |
79 | } |
80 | result->reset(fInfo.makeDimensions(r.size()), pixels, fRowBytes); |
81 | return true; |
82 | } |
83 | |
84 | // This is the same as SkPixmap::addr(x,y), but this version gets inlined, while the public |
85 | // method does not. Perhaps we could bloat it so it can be inlined, but that would grow code-size |
86 | // everywhere, instead of just here (on behalf of getAlphaf()). |
87 | static const void* fast_getaddr(const SkPixmap& pm, int x, int y) { |
88 | x <<= SkColorTypeShiftPerPixel(pm.colorType()); |
89 | return static_cast<const char*>(pm.addr()) + y * pm.rowBytes() + x; |
90 | } |
91 | |
92 | float SkPixmap::getAlphaf(int x, int y) const { |
93 | SkASSERT(this->addr()); |
94 | SkASSERT((unsigned)x < (unsigned)this->width()); |
95 | SkASSERT((unsigned)y < (unsigned)this->height()); |
96 | |
97 | float value = 0; |
98 | const void* srcPtr = fast_getaddr(*this, x, y); |
99 | |
100 | switch (this->colorType()) { |
101 | case kUnknown_SkColorType: |
102 | return 0; |
103 | case kGray_8_SkColorType: |
104 | case kR8G8_unorm_SkColorType: |
105 | case kR16G16_unorm_SkColorType: |
106 | case kR16G16_float_SkColorType: |
107 | case kRGB_565_SkColorType: |
108 | case kRGB_888x_SkColorType: |
109 | case kRGB_101010x_SkColorType: |
110 | case kBGR_101010x_SkColorType: |
111 | return 1; |
112 | case kAlpha_8_SkColorType: |
113 | value = static_cast<const uint8_t*>(srcPtr)[0] * (1.0f/255); |
114 | break; |
115 | case kA16_unorm_SkColorType: |
116 | value = static_cast<const uint16_t*>(srcPtr)[0] * (1.0f/65535); |
117 | break; |
118 | case kA16_float_SkColorType: { |
119 | SkHalf half = static_cast<const SkHalf*>(srcPtr)[0]; |
120 | value = SkHalfToFloat(half); |
121 | break; |
122 | } |
123 | case kARGB_4444_SkColorType: { |
124 | uint16_t u16 = static_cast<const uint16_t*>(srcPtr)[0]; |
125 | value = SkGetPackedA4444(u16) * (1.0f/15); |
126 | break; |
127 | } |
128 | case kRGBA_8888_SkColorType: |
129 | case kBGRA_8888_SkColorType: |
130 | value = static_cast<const uint8_t*>(srcPtr)[3] * (1.0f/255); |
131 | break; |
132 | case kRGBA_1010102_SkColorType: |
133 | case kBGRA_1010102_SkColorType: { |
134 | uint32_t u32 = static_cast<const uint32_t*>(srcPtr)[0]; |
135 | value = (u32 >> 30) * (1.0f/3); |
136 | break; |
137 | } |
138 | case kR16G16B16A16_unorm_SkColorType: { |
139 | uint64_t u64 = static_cast<const uint64_t*>(srcPtr)[0]; |
140 | value = (u64 >> 48) * (1.0f/65535); |
141 | break; |
142 | } |
143 | case kRGBA_F16Norm_SkColorType: |
144 | case kRGBA_F16_SkColorType: { |
145 | uint64_t px; |
146 | memcpy(&px, srcPtr, sizeof(px)); |
147 | value = SkHalfToFloat_finite_ftz(px)[3]; |
148 | break; |
149 | } |
150 | case kRGBA_F32_SkColorType: |
151 | value = static_cast<const float*>(srcPtr)[3]; |
152 | break; |
153 | } |
154 | return value; |
155 | } |
156 | |
157 | bool SkPixmap::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, |
158 | int x, int y) const { |
159 | if (!SkImageInfoValidConversion(dstInfo, fInfo)) { |
160 | return false; |
161 | } |
162 | |
163 | SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, x, y); |
164 | if (!rec.trim(fInfo.width(), fInfo.height())) { |
165 | return false; |
166 | } |
167 | |
168 | const void* srcPixels = this->addr(rec.fX, rec.fY); |
169 | const SkImageInfo srcInfo = fInfo.makeDimensions(rec.fInfo.dimensions()); |
170 | SkConvertPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, srcInfo, srcPixels, this->rowBytes()); |
171 | return true; |
172 | } |
173 | |
174 | bool SkPixmap::erase(SkColor color, const SkIRect& subset) const { |
175 | return this->erase(SkColor4f::FromColor(color), &subset); |
176 | } |
177 | |
178 | bool SkPixmap::erase(const SkColor4f& color, SkColorSpace* cs, const SkIRect* subset) const { |
179 | SkPaint paint; |
180 | paint.setBlendMode(SkBlendMode::kSrc); |
181 | paint.setColor4f(color, cs); |
182 | |
183 | SkIRect clip = this->bounds(); |
184 | if (subset && !clip.intersect(*subset)) { |
185 | return false; |
186 | } |
187 | SkRasterClip rc{clip}; |
188 | |
189 | SkDraw draw; |
190 | SkSimpleMatrixProvider matrixProvider(SkMatrix::I()); |
191 | draw.fDst = *this; |
192 | draw.fMatrixProvider = &matrixProvider; |
193 | draw.fRC = &rc; |
194 | |
195 | draw.drawPaint(paint); |
196 | return true; |
197 | } |
198 | |
199 | bool SkPixmap::scalePixels(const SkPixmap& actualDst, SkFilterQuality quality) const { |
200 | // We may need to tweak how we interpret these just a little below, so we make copies. |
201 | SkPixmap src = *this, |
202 | dst = actualDst; |
203 | |
204 | // Can't do anthing with empty src or dst |
205 | if (src.width() <= 0 || src.height() <= 0 || |
206 | dst.width() <= 0 || dst.height() <= 0) { |
207 | return false; |
208 | } |
209 | |
210 | // no scaling involved? |
211 | if (src.width() == dst.width() && src.height() == dst.height()) { |
212 | return src.readPixels(dst); |
213 | } |
214 | |
215 | // If src and dst are both unpremul, we'll fake the source out to appear as if premul, |
216 | // and mark the destination as opaque. This odd combination allows us to scale unpremul |
217 | // pixels without ever premultiplying them (perhaps losing information in the color channels). |
218 | // This is an idiosyncratic feature of scalePixels(), and is tested by scalepixels_unpremul GM. |
219 | bool clampAsIfUnpremul = false; |
220 | if (src.alphaType() == kUnpremul_SkAlphaType && |
221 | dst.alphaType() == kUnpremul_SkAlphaType) { |
222 | src.reset(src.info().makeAlphaType(kPremul_SkAlphaType), src.addr(), src.rowBytes()); |
223 | dst.reset(dst.info().makeAlphaType(kOpaque_SkAlphaType), dst.addr(), dst.rowBytes()); |
224 | |
225 | // We'll need to tell the image shader to clamp to [0,1] instead of the |
226 | // usual [0,a] when using a bicubic scaling (kHigh_SkFilterQuality). |
227 | clampAsIfUnpremul = true; |
228 | } |
229 | |
230 | SkBitmap bitmap; |
231 | if (!bitmap.installPixels(src)) { |
232 | return false; |
233 | } |
234 | bitmap.setImmutable(); // Don't copy when we create an image. |
235 | |
236 | SkMatrix scale = SkMatrix::MakeRectToRect(SkRect::Make(src.bounds()), |
237 | SkRect::Make(dst.bounds()), |
238 | SkMatrix::kFill_ScaleToFit); |
239 | |
240 | // We'll create a shader to do this draw so we have control over the bicubic clamp. |
241 | sk_sp<SkShader> shader = SkImageShader::Make(SkImage::MakeFromBitmap(bitmap), |
242 | SkTileMode::kClamp, |
243 | SkTileMode::kClamp, |
244 | &scale, |
245 | (SkImageShader::FilterEnum)quality, |
246 | clampAsIfUnpremul); |
247 | |
248 | sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect(dst.info(), |
249 | dst.writable_addr(), |
250 | dst.rowBytes()); |
251 | if (!shader || !surface) { |
252 | return false; |
253 | } |
254 | |
255 | SkPaint paint; |
256 | paint.setBlendMode(SkBlendMode::kSrc); |
257 | paint.setFilterQuality(quality); |
258 | paint.setShader(std::move(shader)); |
259 | surface->getCanvas()->drawPaint(paint); |
260 | return true; |
261 | } |
262 | |
263 | ////////////////////////////////////////////////////////////////////////////////////////////////// |
264 | |
265 | SkColor SkPixmap::getColor(int x, int y) const { |
266 | SkASSERT(this->addr()); |
267 | SkASSERT((unsigned)x < (unsigned)this->width()); |
268 | SkASSERT((unsigned)y < (unsigned)this->height()); |
269 | |
270 | const bool needsUnpremul = (kPremul_SkAlphaType == fInfo.alphaType()); |
271 | auto toColor = [needsUnpremul](uint32_t maybePremulColor) { |
272 | return needsUnpremul ? SkUnPreMultiply::PMColorToColor(maybePremulColor) |
273 | : SkSwizzle_BGRA_to_PMColor(maybePremulColor); |
274 | }; |
275 | |
276 | switch (this->colorType()) { |
277 | case kGray_8_SkColorType: { |
278 | uint8_t value = *this->addr8(x, y); |
279 | return SkColorSetRGB(value, value, value); |
280 | } |
281 | case kAlpha_8_SkColorType: { |
282 | return SkColorSetA(0, *this->addr8(x, y)); |
283 | } |
284 | case kA16_unorm_SkColorType: { |
285 | uint16_t value = *this->addr16(x, y); |
286 | return SkColorSetA(0, value * (255 / 65535.0f)); |
287 | } |
288 | case kA16_float_SkColorType: { |
289 | SkHalf value = *this->addr16(x, y); |
290 | return SkColorSetA(0, 255 * SkHalfToFloat(value)); |
291 | } |
292 | case kRGB_565_SkColorType: { |
293 | return SkPixel16ToColor(*this->addr16(x, y)); |
294 | } |
295 | case kARGB_4444_SkColorType: { |
296 | uint16_t value = *this->addr16(x, y); |
297 | SkPMColor c = SkPixel4444ToPixel32(value); |
298 | return toColor(c); |
299 | } |
300 | case kR8G8_unorm_SkColorType: { |
301 | uint16_t value = *this->addr16(x, y); |
302 | return (uint32_t)( ((value >> 0) & 0xff) ) << 16 |
303 | | (uint32_t)( ((value >> 8) & 0xff) ) << 8 |
304 | | 0xff000000; |
305 | } |
306 | case kR16G16_unorm_SkColorType: { |
307 | uint32_t value = *this->addr32(x, y); |
308 | return (uint32_t)( ((value >> 0) & 0xffff) * (255/65535.0f) ) << 16 |
309 | | (uint32_t)( ((value >> 16) & 0xffff) * (255/65535.0f) ) << 8 |
310 | | 0xff000000; |
311 | } |
312 | case kR16G16_float_SkColorType: { |
313 | uint32_t value = *this->addr32(x, y); |
314 | uint32_t r = 255 * SkHalfToFloat((value >> 0) & 0xffff); |
315 | uint32_t g = 255 * SkHalfToFloat((value >> 16) & 0xffff); |
316 | return (r << 16) | (g << 8) | 0xff000000; |
317 | } |
318 | case kRGB_888x_SkColorType: { |
319 | uint32_t value = *this->addr32(x, y); |
320 | return SkSwizzle_RB(value | 0xff000000); |
321 | } |
322 | case kBGRA_8888_SkColorType: { |
323 | uint32_t value = *this->addr32(x, y); |
324 | SkPMColor c = SkSwizzle_BGRA_to_PMColor(value); |
325 | return toColor(c); |
326 | } |
327 | case kRGBA_8888_SkColorType: { |
328 | uint32_t value = *this->addr32(x, y); |
329 | SkPMColor c = SkSwizzle_RGBA_to_PMColor(value); |
330 | return toColor(c); |
331 | } |
332 | case kRGB_101010x_SkColorType: { |
333 | uint32_t value = *this->addr32(x, y); |
334 | // Convert 10-bit rgb to 8-bit bgr, and mask in 0xff alpha at the top. |
335 | return (uint32_t)( ((value >> 0) & 0x3ff) * (255/1023.0f) ) << 16 |
336 | | (uint32_t)( ((value >> 10) & 0x3ff) * (255/1023.0f) ) << 8 |
337 | | (uint32_t)( ((value >> 20) & 0x3ff) * (255/1023.0f) ) << 0 |
338 | | 0xff000000; |
339 | } |
340 | case kBGR_101010x_SkColorType: { |
341 | uint32_t value = *this->addr32(x, y); |
342 | // Convert 10-bit bgr to 8-bit bgr, and mask in 0xff alpha at the top. |
343 | return (uint32_t)( ((value >> 0) & 0x3ff) * (255/1023.0f) ) << 0 |
344 | | (uint32_t)( ((value >> 10) & 0x3ff) * (255/1023.0f) ) << 8 |
345 | | (uint32_t)( ((value >> 20) & 0x3ff) * (255/1023.0f) ) << 16 |
346 | | 0xff000000; |
347 | } |
348 | case kRGBA_1010102_SkColorType: |
349 | case kBGRA_1010102_SkColorType: { |
350 | uint32_t value = *this->addr32(x, y); |
351 | |
352 | float r = ((value >> 0) & 0x3ff) * (1/1023.0f), |
353 | g = ((value >> 10) & 0x3ff) * (1/1023.0f), |
354 | b = ((value >> 20) & 0x3ff) * (1/1023.0f), |
355 | a = ((value >> 30) & 0x3 ) * (1/ 3.0f); |
356 | if (this->colorType() == kBGRA_1010102_SkColorType) { |
357 | std::swap(r,b); |
358 | } |
359 | if (a != 0 && needsUnpremul) { |
360 | r = SkTPin(r/a, 0.0f, 1.0f); |
361 | g = SkTPin(g/a, 0.0f, 1.0f); |
362 | b = SkTPin(b/a, 0.0f, 1.0f); |
363 | } |
364 | return (uint32_t)( r * 255.0f ) << 16 |
365 | | (uint32_t)( g * 255.0f ) << 8 |
366 | | (uint32_t)( b * 255.0f ) << 0 |
367 | | (uint32_t)( a * 255.0f ) << 24; |
368 | } |
369 | case kR16G16B16A16_unorm_SkColorType: { |
370 | uint64_t value = *this->addr64(x, y); |
371 | |
372 | float r = ((value ) & 0xffff) * (1/65535.0f), |
373 | g = ((value >> 16) & 0xffff) * (1/65535.0f), |
374 | b = ((value >> 32) & 0xffff) * (1/65535.0f), |
375 | a = ((value >> 48) & 0xffff) * (1/65535.0f); |
376 | if (a != 0 && needsUnpremul) { |
377 | r *= (1.0f/a); |
378 | g *= (1.0f/a); |
379 | b *= (1.0f/a); |
380 | } |
381 | return (uint32_t)( r * 255.0f ) << 16 |
382 | | (uint32_t)( g * 255.0f ) << 8 |
383 | | (uint32_t)( b * 255.0f ) << 0 |
384 | | (uint32_t)( a * 255.0f ) << 24; |
385 | } |
386 | case kRGBA_F16Norm_SkColorType: |
387 | case kRGBA_F16_SkColorType: { |
388 | const uint64_t* addr = |
389 | (const uint64_t*)fPixels + y * (fRowBytes >> 3) + x; |
390 | Sk4f p4 = SkHalfToFloat_finite_ftz(*addr); |
391 | if (p4[3] && needsUnpremul) { |
392 | float inva = 1 / p4[3]; |
393 | p4 = p4 * Sk4f(inva, inva, inva, 1); |
394 | } |
395 | SkColor c; |
396 | SkNx_cast<uint8_t>(p4 * Sk4f(255) + Sk4f(0.5f)).store(&c); |
397 | // p4 is RGBA, but we want BGRA, so we need to swap next |
398 | return SkSwizzle_RB(c); |
399 | } |
400 | case kRGBA_F32_SkColorType: { |
401 | const float* rgba = |
402 | (const float*)fPixels + 4*y*(fRowBytes >> 4) + 4*x; |
403 | Sk4f p4 = Sk4f::Load(rgba); |
404 | // From here on, just like F16: |
405 | if (p4[3] && needsUnpremul) { |
406 | float inva = 1 / p4[3]; |
407 | p4 = p4 * Sk4f(inva, inva, inva, 1); |
408 | } |
409 | SkColor c; |
410 | SkNx_cast<uint8_t>(p4 * Sk4f(255) + Sk4f(0.5f)).store(&c); |
411 | // p4 is RGBA, but we want BGRA, so we need to swap next |
412 | return SkSwizzle_RB(c); |
413 | } |
414 | case kUnknown_SkColorType: |
415 | break; |
416 | } |
417 | SkDEBUGFAIL("" ); |
418 | return SkColorSetARGB(0, 0, 0, 0); |
419 | } |
420 | |
421 | bool SkPixmap::computeIsOpaque() const { |
422 | const int height = this->height(); |
423 | const int width = this->width(); |
424 | |
425 | switch (this->colorType()) { |
426 | case kAlpha_8_SkColorType: { |
427 | unsigned a = 0xFF; |
428 | for (int y = 0; y < height; ++y) { |
429 | const uint8_t* row = this->addr8(0, y); |
430 | for (int x = 0; x < width; ++x) { |
431 | a &= row[x]; |
432 | } |
433 | if (0xFF != a) { |
434 | return false; |
435 | } |
436 | } |
437 | return true; |
438 | } |
439 | case kA16_unorm_SkColorType: { |
440 | unsigned a = 0xFFFF; |
441 | for (int y = 0; y < height; ++y) { |
442 | const uint16_t* row = this->addr16(0, y); |
443 | for (int x = 0; x < width; ++x) { |
444 | a &= row[x]; |
445 | } |
446 | if (0xFFFF != a) { |
447 | return false; |
448 | } |
449 | } |
450 | return true; |
451 | } |
452 | case kA16_float_SkColorType: { |
453 | for (int y = 0; y < height; ++y) { |
454 | const SkHalf* row = this->addr16(0, y); |
455 | for (int x = 0; x < width; ++x) { |
456 | if (row[x] < SK_Half1) { |
457 | return false; |
458 | } |
459 | } |
460 | } |
461 | return true; |
462 | } |
463 | case kRGB_565_SkColorType: |
464 | case kGray_8_SkColorType: |
465 | case kR8G8_unorm_SkColorType: |
466 | case kR16G16_unorm_SkColorType: |
467 | case kR16G16_float_SkColorType: |
468 | case kRGB_888x_SkColorType: |
469 | case kRGB_101010x_SkColorType: |
470 | case kBGR_101010x_SkColorType: |
471 | return true; |
472 | break; |
473 | case kARGB_4444_SkColorType: { |
474 | unsigned c = 0xFFFF; |
475 | for (int y = 0; y < height; ++y) { |
476 | const SkPMColor16* row = this->addr16(0, y); |
477 | for (int x = 0; x < width; ++x) { |
478 | c &= row[x]; |
479 | } |
480 | if (0xF != SkGetPackedA4444(c)) { |
481 | return false; |
482 | } |
483 | } |
484 | return true; |
485 | } |
486 | case kBGRA_8888_SkColorType: |
487 | case kRGBA_8888_SkColorType: { |
488 | SkPMColor c = (SkPMColor)~0; |
489 | for (int y = 0; y < height; ++y) { |
490 | const SkPMColor* row = this->addr32(0, y); |
491 | for (int x = 0; x < width; ++x) { |
492 | c &= row[x]; |
493 | } |
494 | if (0xFF != SkGetPackedA32(c)) { |
495 | return false; |
496 | } |
497 | } |
498 | return true; |
499 | } |
500 | case kRGBA_F16Norm_SkColorType: |
501 | case kRGBA_F16_SkColorType: { |
502 | const SkHalf* row = (const SkHalf*)this->addr(); |
503 | for (int y = 0; y < height; ++y) { |
504 | for (int x = 0; x < width; ++x) { |
505 | if (row[4 * x + 3] < SK_Half1) { |
506 | return false; |
507 | } |
508 | } |
509 | row += this->rowBytes() >> 1; |
510 | } |
511 | return true; |
512 | } |
513 | case kRGBA_F32_SkColorType: { |
514 | const float* row = (const float*)this->addr(); |
515 | for (int y = 0; y < height; ++y) { |
516 | for (int x = 0; x < width; ++x) { |
517 | if (row[4 * x + 3] < 1.0f) { |
518 | return false; |
519 | } |
520 | } |
521 | row += this->rowBytes() >> 2; |
522 | } |
523 | return true; |
524 | } |
525 | case kRGBA_1010102_SkColorType: |
526 | case kBGRA_1010102_SkColorType: { |
527 | uint32_t c = ~0; |
528 | for (int y = 0; y < height; ++y) { |
529 | const uint32_t* row = this->addr32(0, y); |
530 | for (int x = 0; x < width; ++x) { |
531 | c &= row[x]; |
532 | } |
533 | if (0b11 != c >> 30) { |
534 | return false; |
535 | } |
536 | } |
537 | return true; |
538 | } |
539 | case kR16G16B16A16_unorm_SkColorType: { |
540 | uint16_t acc = 0xFFFF; |
541 | for (int y = 0; y < height; ++y) { |
542 | const uint64_t* row = this->addr64(0, y); |
543 | for (int x = 0; x < width; ++x) { |
544 | acc &= (row[x] >> 48); |
545 | } |
546 | if (0xFFFF != acc) { |
547 | return false; |
548 | } |
549 | } |
550 | return true; |
551 | } |
552 | case kUnknown_SkColorType: |
553 | SkDEBUGFAIL("" ); |
554 | break; |
555 | } |
556 | return false; |
557 | } |
558 | |
559 | ////////////////////////////////////////////////////////////////////////////////////////////////// |
560 | |
561 | static bool draw_orientation(const SkPixmap& dst, const SkPixmap& src, SkEncodedOrigin origin) { |
562 | auto surf = SkSurface::MakeRasterDirect(dst.info(), dst.writable_addr(), dst.rowBytes()); |
563 | if (!surf) { |
564 | return false; |
565 | } |
566 | |
567 | SkBitmap bm; |
568 | bm.installPixels(src); |
569 | |
570 | SkMatrix m = SkEncodedOriginToMatrix(origin, src.width(), src.height()); |
571 | |
572 | SkPaint p; |
573 | p.setBlendMode(SkBlendMode::kSrc); |
574 | surf->getCanvas()->concat(m); |
575 | surf->getCanvas()->drawBitmap(bm, 0, 0, &p); |
576 | return true; |
577 | } |
578 | |
579 | bool SkPixmapPriv::Orient(const SkPixmap& dst, const SkPixmap& src, SkEncodedOrigin origin) { |
580 | if (src.colorType() != dst.colorType()) { |
581 | return false; |
582 | } |
583 | // note: we just ignore alphaType and colorSpace for this transformation |
584 | |
585 | int w = src.width(); |
586 | int h = src.height(); |
587 | if (ShouldSwapWidthHeight(origin)) { |
588 | using std::swap; |
589 | swap(w, h); |
590 | } |
591 | if (dst.width() != w || dst.height() != h) { |
592 | return false; |
593 | } |
594 | if (w == 0 || h == 0) { |
595 | return true; |
596 | } |
597 | |
598 | // check for aliasing to self |
599 | if (src.addr() == dst.addr()) { |
600 | return kTopLeft_SkEncodedOrigin == origin; |
601 | } |
602 | return draw_orientation(dst, src, origin); |
603 | } |
604 | |
605 | bool SkPixmapPriv::ShouldSwapWidthHeight(SkEncodedOrigin origin) { |
606 | // The last four SkEncodedOrigin values involve 90 degree rotations |
607 | return origin >= kLeftTop_SkEncodedOrigin; |
608 | } |
609 | |
610 | SkImageInfo SkPixmapPriv::SwapWidthHeight(const SkImageInfo& info) { |
611 | return info.makeWH(info.height(), info.width()); |
612 | } |
613 | |
614 | |