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