blob: f842afd8ce6d730d8f5db9f5a7733cbf4f806813 [file] [log] [blame]
reed92fc2ae2015-05-22 08:06:21 -07001/*
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
Hal Canaryc640d0d2018-06-13 09:59:02 -04008#include "SkPixmap.h"
9
Hal Canary4cba3fe2016-12-07 14:59:27 -050010#include "SkBitmap.h"
11#include "SkCanvas.h"
Cary Clarka4083c92017-09-15 11:59:23 -040012#include "SkColorData.h"
Matt Sarett485c4992017-02-14 14:18:27 -050013#include "SkConvertPixels.h"
fmalita3a94c6c2016-02-04 13:09:59 -080014#include "SkData.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040015#include "SkHalf.h"
Matt Sarettcb6266b2017-01-17 10:48:53 -050016#include "SkImageInfoPriv.h"
Mike Klein1f313092018-01-03 10:30:21 -050017#include "SkImageShader.h"
reed183b57f2015-06-05 14:33:17 -070018#include "SkMask.h"
Hal Canary4cba3fe2016-12-07 14:59:27 -050019#include "SkNx.h"
reeddd9ffea2016-02-18 12:39:14 -080020#include "SkPM4f.h"
Mike Reed43798692017-10-17 18:04:32 +000021#include "SkPixmapPriv.h"
Matt Sarett03dd6d52017-01-23 12:15:09 -050022#include "SkReadPixelsRec.h"
Hal Canary4cba3fe2016-12-07 14:59:27 -050023#include "SkSurface.h"
Mike Reed43798692017-10-17 18:04:32 +000024#include "SkTemplates.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040025#include "SkTo.h"
Mike Reed5dd202d2018-02-06 23:05:36 +000026#include "SkUnPreMultiply.h"
Hal Canary4cba3fe2016-12-07 14:59:27 -050027#include "SkUtils.h"
reed92fc2ae2015-05-22 08:06:21 -070028
Ben Wagnerf08d1d02018-06-18 15:11:00 -040029#include <utility>
30
reed95d343f2015-05-23 13:21:06 -070031/////////////////////////////////////////////////////////////////////////////////////////////////
32
reed884e97c2015-05-26 11:31:54 -070033void SkPixmap::reset() {
halcanary96fcdcc2015-08-27 07:41:13 -070034 fPixels = nullptr;
reed884e97c2015-05-26 11:31:54 -070035 fRowBytes = 0;
36 fInfo = SkImageInfo::MakeUnknown();
37}
38
Mike Reed086a4272017-07-18 10:53:11 -040039void SkPixmap::reset(const SkImageInfo& info, const void* addr, size_t rowBytes) {
reed884e97c2015-05-26 11:31:54 -070040 if (addr) {
41 SkASSERT(info.validRowBytes(rowBytes));
42 }
43 fPixels = addr;
reed884e97c2015-05-26 11:31:54 -070044 fRowBytes = rowBytes;
45 fInfo = info;
46}
47
reed183b57f2015-06-05 14:33:17 -070048bool SkPixmap::reset(const SkMask& src) {
49 if (SkMask::kA8_Format == src.fFormat) {
50 this->reset(SkImageInfo::MakeA8(src.fBounds.width(), src.fBounds.height()),
Mike Reed086a4272017-07-18 10:53:11 -040051 src.fImage, src.fRowBytes);
reed183b57f2015-06-05 14:33:17 -070052 return true;
53 }
54 this->reset();
55 return false;
56}
57
msarett804b4612016-06-09 11:03:45 -070058void SkPixmap::setColorSpace(sk_sp<SkColorSpace> cs) {
59 fInfo = fInfo.makeColorSpace(std::move(cs));
60}
61
reed183b57f2015-06-05 14:33:17 -070062bool SkPixmap::extractSubset(SkPixmap* result, const SkIRect& subset) const {
63 SkIRect srcRect, r;
64 srcRect.set(0, 0, this->width(), this->height());
65 if (!r.intersect(srcRect, subset)) {
66 return false; // r is empty (i.e. no intersection)
67 }
halcanary9d524f22016-03-29 09:03:52 -070068
reed183b57f2015-06-05 14:33:17 -070069 // 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
halcanary96fcdcc2015-08-27 07:41:13 -070074 const void* pixels = nullptr;
reed183b57f2015-06-05 14:33:17 -070075 if (fPixels) {
76 const size_t bpp = fInfo.bytesPerPixel();
77 pixels = (const uint8_t*)fPixels + r.fTop * fRowBytes + r.fLeft * bpp;
78 }
Mike Reed26e9ddd2017-07-17 17:33:53 -040079 result->reset(fInfo.makeWH(r.width(), r.height()), pixels, fRowBytes);
reed183b57f2015-06-05 14:33:17 -070080 return true;
81}
82
Brian Osmanf6db4952018-07-16 13:06:02 -040083bool SkPixmap::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
84 int x, int y) const {
Matt Sarett03dd6d52017-01-23 12:15:09 -050085 if (!SkImageInfoValidConversion(dstInfo, fInfo)) {
reed95d343f2015-05-23 13:21:06 -070086 return false;
87 }
Matt Sarettcb6266b2017-01-17 10:48:53 -050088
Matt Sarett03dd6d52017-01-23 12:15:09 -050089 SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, x, y);
90 if (!rec.trim(fInfo.width(), fInfo.height())) {
reed95d343f2015-05-23 13:21:06 -070091 return false;
92 }
halcanary9d524f22016-03-29 09:03:52 -070093
Matt Sarett03dd6d52017-01-23 12:15:09 -050094 const void* srcPixels = this->addr(rec.fX, rec.fY);
95 const SkImageInfo srcInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height());
Brian Osmanb62f50c2018-07-12 14:44:27 -040096 SkConvertPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, srcInfo, srcPixels, this->rowBytes());
Matt Sarett8572d852017-02-14 11:21:02 -050097 return true;
reed95d343f2015-05-23 13:21:06 -070098}
reed183b57f2015-06-05 14:33:17 -070099
Mike Klein9ec77b52018-09-18 12:19:57 +0000100static uint16_t pack_8888_to_4444(unsigned a, unsigned r, unsigned g, unsigned b) {
101 unsigned pixel = (SkA32To4444(a) << SK_A4444_SHIFT) |
102 (SkR32To4444(r) << SK_R4444_SHIFT) |
103 (SkG32To4444(g) << SK_G4444_SHIFT) |
104 (SkB32To4444(b) << SK_B4444_SHIFT);
105 return SkToU16(pixel);
reed7aefe032015-06-08 10:22:22 -0700106}
107
Mike Klein9ec77b52018-09-18 12:19:57 +0000108bool SkPixmap::erase(SkColor color, const SkIRect& inArea) const {
109 if (nullptr == fPixels) {
110 return false;
111 }
112 SkIRect area;
113 if (!area.intersect(this->bounds(), inArea)) {
114 return false;
115 }
reed7aefe032015-06-08 10:22:22 -0700116
Mike Klein9ec77b52018-09-18 12:19:57 +0000117 U8CPU a = SkColorGetA(color);
118 U8CPU r = SkColorGetR(color);
119 U8CPU g = SkColorGetG(color);
120 U8CPU b = SkColorGetB(color);
reed7aefe032015-06-08 10:22:22 -0700121
Mike Klein9ec77b52018-09-18 12:19:57 +0000122 int height = area.height();
123 const int width = area.width();
124 const int rowBytes = this->rowBytes();
125
126 if (color == 0
127 && width == this->rowBytesAsPixels()
128 && inArea == this->bounds()) {
129 // All formats represent SkColor(0) as byte 0.
130 memset(this->writable_addr(), 0, (int64_t)height * rowBytes);
Mike Klein37854712018-06-26 11:43:06 -0400131 return true;
reed3601f282016-02-05 11:18:39 -0800132 }
Mike Klein9ec77b52018-09-18 12:19:57 +0000133
134 switch (this->colorType()) {
135 case kGray_8_SkColorType: {
136 if (255 != a) {
137 r = SkMulDiv255Round(r, a);
138 g = SkMulDiv255Round(g, a);
139 b = SkMulDiv255Round(b, a);
140 }
141 int gray = SkComputeLuminance(r, g, b);
142 uint8_t* p = this->writable_addr8(area.fLeft, area.fTop);
143 while (--height >= 0) {
144 memset(p, gray, width);
145 p += rowBytes;
146 }
147 break;
148 }
149 case kAlpha_8_SkColorType: {
150 uint8_t* p = this->writable_addr8(area.fLeft, area.fTop);
151 while (--height >= 0) {
152 memset(p, a, width);
153 p += rowBytes;
154 }
155 break;
156 }
157
158 case kARGB_4444_SkColorType:
159 case kRGB_565_SkColorType: {
160 uint16_t* p = this->writable_addr16(area.fLeft, area.fTop);
161 uint16_t v;
162
163 // make rgb premultiplied
164 if (255 != a) {
165 r = SkMulDiv255Round(r, a);
166 g = SkMulDiv255Round(g, a);
167 b = SkMulDiv255Round(b, a);
168 }
169
170 if (kARGB_4444_SkColorType == this->colorType()) {
171 v = pack_8888_to_4444(a, r, g, b);
172 } else {
173 v = SkPackRGB16(r >> (8 - SK_R16_BITS),
174 g >> (8 - SK_G16_BITS),
175 b >> (8 - SK_B16_BITS));
176 }
177 while (--height >= 0) {
178 sk_memset16(p, v, width);
179 p = (uint16_t*)((char*)p + rowBytes);
180 }
181 break;
182 }
183
184 case kRGB_888x_SkColorType:
185 a = 255; // then fallthrough to 8888
186 case kRGBA_8888_SkColorType:
187 case kBGRA_8888_SkColorType: {
188 uint32_t* p = this->writable_addr32(area.fLeft, area.fTop);
189
190 if (255 != a && kPremul_SkAlphaType == this->alphaType()) {
191 r = SkMulDiv255Round(r, a);
192 g = SkMulDiv255Round(g, a);
193 b = SkMulDiv255Round(b, a);
194 }
195 uint32_t v = kBGRA_8888_SkColorType == this->colorType()
196 ? SkPackARGB_as_BGRA(a, r, g, b) // bgra 8888
197 : SkPackARGB_as_RGBA(a, r, g, b); // rgba 8888 or rgb 888
198
199 while (--height >= 0) {
200 sk_memset32(p, v, width);
201 p = (uint32_t*)((char*)p + rowBytes);
202 }
203 break;
204 }
205
206 case kRGB_101010x_SkColorType:
207 a = 255; // then fallthrough to 1010102
208 case kRGBA_1010102_SkColorType: {
209 uint32_t* p = this->writable_addr32(area.fLeft, area.fTop);
210
211 float R = r * (1/255.0f),
212 G = g * (1/255.0f),
213 B = b * (1/255.0f),
214 A = a * (1/255.0f);
215 if (a != 255 && this->alphaType() == kPremul_SkAlphaType) {
216 R *= A;
217 G *= A;
218 B *= A;
219 }
220 uint32_t v = (uint32_t)(R * 1023.0f) << 0
221 | (uint32_t)(G * 1023.0f) << 10
222 | (uint32_t)(B * 1023.0f) << 20
223 | (uint32_t)(A * 3.0f) << 30;
224 while (--height >= 0) {
225 sk_memset32(p, v, width);
226 p = (uint32_t*)((char*)p + rowBytes);
227 }
228 break;
229 }
230
231 case kRGBA_F16_SkColorType:
232 case kRGBA_F32_SkColorType:
233 // The colorspace is unspecified, so assume linear just like getColor().
234 this->erase(SkColor4f{(1 / 255.0f) * r,
235 (1 / 255.0f) * g,
236 (1 / 255.0f) * b,
237 (1 / 255.0f) * a}, &area);
238 break;
239 default:
240 return false; // no change, so don't call notifyPixelsChanged()
241 }
242 return true;
243}
244
245bool SkPixmap::erase(const SkColor4f& origColor, const SkIRect* subset) const {
246 SkPixmap pm;
247 if (subset) {
248 if (!this->extractSubset(&pm, *subset)) {
249 return false;
250 }
251 } else {
252 pm = *this;
253 }
254
255 const SkColor4f color = origColor.pin();
256
257 if (pm.colorType() == kRGBA_F16_SkColorType) {
258 const uint64_t half4 = color.premul().toF16();
259 for (int y = 0; y < pm.height(); ++y) {
260 sk_memset64(pm.writable_addr64(0, y), half4, pm.width());
261 }
262 return true;
263 }
264
265 if (pm.colorType() == kRGBA_F32_SkColorType) {
266 const SkPM4f rgba = color.premul();
267 for (int y = 0; y < pm.height(); ++y) {
268 auto row = (float*)pm.writable_addr(0, y);
269 for (int x = 0; x < pm.width(); ++x) {
270 row[4*x+0] = rgba.r();
271 row[4*x+1] = rgba.g();
272 row[4*x+2] = rgba.b();
273 row[4*x+3] = rgba.a();
274 }
275 }
276 return true;
277 }
278
279 return pm.erase(color.toSkColor());
reed3601f282016-02-05 11:18:39 -0800280}
281
Mike Klein1f313092018-01-03 10:30:21 -0500282bool SkPixmap::scalePixels(const SkPixmap& actualDst, SkFilterQuality quality) const {
283 // We may need to tweak how we interpret these just a little below, so we make copies.
284 SkPixmap src = *this,
285 dst = actualDst;
Mike Klein47cf0482018-02-09 18:57:54 +0000286
reed09553032015-11-23 12:32:16 -0800287 // Can't do anthing with empty src or dst
Mike Klein1f313092018-01-03 10:30:21 -0500288 if (src.width() <= 0 || src.height() <= 0 ||
289 dst.width() <= 0 || dst.height() <= 0) {
reed09553032015-11-23 12:32:16 -0800290 return false;
291 }
292
293 // no scaling involved?
Mike Klein1f313092018-01-03 10:30:21 -0500294 if (src.width() == dst.width() && src.height() == dst.height()) {
295 return src.readPixels(dst);
reed09553032015-11-23 12:32:16 -0800296 }
297
Mike Kleinfc9624c2018-09-06 11:25:21 -0400298 // If src and dst are both unpremul, we'll fake the source out to appear as if premul,
299 // and mark the destination as opaque. This odd combination allows us to scale unpremul
300 // pixels without ever premultiplying them (perhaps losing information in the color channels).
301 // This is an idiosyncratic feature of scalePixels(), and is tested by scalepixels_unpremul GM.
Mike Klein1f313092018-01-03 10:30:21 -0500302 bool clampAsIfUnpremul = false;
303 if (src.alphaType() == kUnpremul_SkAlphaType &&
304 dst.alphaType() == kUnpremul_SkAlphaType) {
305 src.reset(src.info().makeAlphaType(kPremul_SkAlphaType), src.addr(), src.rowBytes());
Mike Kleinfc9624c2018-09-06 11:25:21 -0400306 dst.reset(dst.info().makeAlphaType(kOpaque_SkAlphaType), dst.addr(), dst.rowBytes());
Mike Klein47cf0482018-02-09 18:57:54 +0000307
Mike Kleinfc9624c2018-09-06 11:25:21 -0400308 // We'll need to tell the image shader to clamp to [0,1] instead of the
309 // usual [0,a] when using a bicubic scaling (kHigh_SkFilterQuality).
Mike Klein1f313092018-01-03 10:30:21 -0500310 clampAsIfUnpremul = true;
Mike Klein47cf0482018-02-09 18:57:54 +0000311 }
312
reed09553032015-11-23 12:32:16 -0800313 SkBitmap bitmap;
Mike Klein1f313092018-01-03 10:30:21 -0500314 if (!bitmap.installPixels(src)) {
reed09553032015-11-23 12:32:16 -0800315 return false;
316 }
Mike Klein1f313092018-01-03 10:30:21 -0500317 bitmap.setImmutable(); // Don't copy when we create an image.
318 bitmap.setIsVolatile(true); // Disable any caching.
reed09553032015-11-23 12:32:16 -0800319
Mike Klein1f313092018-01-03 10:30:21 -0500320 SkMatrix scale = SkMatrix::MakeRectToRect(SkRect::Make(src.bounds()),
321 SkRect::Make(dst.bounds()),
322 SkMatrix::kFill_ScaleToFit);
323
324 // We'll create a shader to do this draw so we have control over the bicubic clamp.
325 sk_sp<SkShader> shader = SkImageShader::Make(SkImage::MakeFromBitmap(bitmap),
326 SkShader::kClamp_TileMode,
327 SkShader::kClamp_TileMode,
328 &scale,
329 clampAsIfUnpremul);
330
331 sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect(dst.info(),
332 dst.writable_addr(),
333 dst.rowBytes());
334 if (!shader || !surface) {
reed09553032015-11-23 12:32:16 -0800335 return false;
336 }
337
338 SkPaint paint;
Mike Klein47cf0482018-02-09 18:57:54 +0000339 paint.setBlendMode(SkBlendMode::kSrc);
Mike Klein1f313092018-01-03 10:30:21 -0500340 paint.setFilterQuality(quality);
341 paint.setShader(std::move(shader));
342 surface->getCanvas()->drawPaint(paint);
reed09553032015-11-23 12:32:16 -0800343 return true;
344}
345
reed183b57f2015-06-05 14:33:17 -0700346//////////////////////////////////////////////////////////////////////////////////////////////////
Hal Canary94e1a2f2016-10-31 09:38:12 -0400347
348SkColor SkPixmap::getColor(int x, int y) const {
349 SkASSERT(this->addr());
350 SkASSERT((unsigned)x < (unsigned)this->width());
351 SkASSERT((unsigned)y < (unsigned)this->height());
Matt Sarett9466bf52017-06-09 09:54:55 -0400352
Mike Klein29a49bd2018-09-17 21:04:20 +0000353 const bool needsUnpremul = (kPremul_SkAlphaType == fInfo.alphaType());
354 auto toColor = [needsUnpremul](uint32_t maybePremulColor) {
355 return needsUnpremul ? SkUnPreMultiply::PMColorToColor(maybePremulColor)
356 : SkSwizzle_BGRA_to_PMColor(maybePremulColor);
357 };
358
359 switch (this->colorType()) {
360 case kGray_8_SkColorType: {
361 uint8_t value = *this->addr8(x, y);
362 return SkColorSetRGB(value, value, value);
363 }
364 case kAlpha_8_SkColorType: {
365 return SkColorSetA(0, *this->addr8(x, y));
366 }
367 case kRGB_565_SkColorType: {
368 return SkPixel16ToColor(*this->addr16(x, y));
369 }
370 case kARGB_4444_SkColorType: {
371 uint16_t value = *this->addr16(x, y);
372 SkPMColor c = SkPixel4444ToPixel32(value);
373 return toColor(c);
374 }
375 case kRGB_888x_SkColorType: {
376 uint32_t value = *this->addr32(x, y);
377 return SkSwizzle_RB(value | 0xff000000);
378 }
379 case kBGRA_8888_SkColorType: {
380 uint32_t value = *this->addr32(x, y);
381 SkPMColor c = SkSwizzle_BGRA_to_PMColor(value);
382 return toColor(c);
383 }
384 case kRGBA_8888_SkColorType: {
385 uint32_t value = *this->addr32(x, y);
386 SkPMColor c = SkSwizzle_RGBA_to_PMColor(value);
387 return toColor(c);
388 }
389 case kRGB_101010x_SkColorType: {
390 uint32_t value = *this->addr32(x, y);
391 // Convert 10-bit rgb to 8-bit bgr, and mask in 0xff alpha at the top.
392 return (uint32_t)( ((value >> 0) & 0x3ff) * (255/1023.0f) ) << 16
393 | (uint32_t)( ((value >> 10) & 0x3ff) * (255/1023.0f) ) << 8
394 | (uint32_t)( ((value >> 20) & 0x3ff) * (255/1023.0f) ) << 0
395 | 0xff000000;
396 }
397 case kRGBA_1010102_SkColorType: {
398 uint32_t value = *this->addr32(x, y);
399
400 float r = ((value >> 0) & 0x3ff) * (1/1023.0f),
401 g = ((value >> 10) & 0x3ff) * (1/1023.0f),
402 b = ((value >> 20) & 0x3ff) * (1/1023.0f),
403 a = ((value >> 30) & 0x3 ) * (1/ 3.0f);
404 if (a != 0 && needsUnpremul) {
405 r *= (1.0f/a);
406 g *= (1.0f/a);
407 b *= (1.0f/a);
408 }
409 return (uint32_t)( r * 255.0f ) << 16
410 | (uint32_t)( g * 255.0f ) << 8
411 | (uint32_t)( b * 255.0f ) << 0
412 | (uint32_t)( a * 255.0f ) << 24;
413 }
414 case kRGBA_F16_SkColorType: {
415 const uint64_t* addr =
416 (const uint64_t*)fPixels + y * (fRowBytes >> 3) + x;
417 Sk4f p4 = SkHalfToFloat_finite_ftz(*addr);
418 if (p4[3] && needsUnpremul) {
419 float inva = 1 / p4[3];
420 p4 = p4 * Sk4f(inva, inva, inva, 1);
421 }
422 SkColor c;
423 SkNx_cast<uint8_t>(p4 * Sk4f(255) + Sk4f(0.5f)).store(&c);
424 // p4 is RGBA, but we want BGRA, so we need to swap next
425 return SkSwizzle_RB(c);
426 }
427 case kRGBA_F32_SkColorType: {
428 const float* rgba =
429 (const float*)fPixels + 4*y*(fRowBytes >> 4) + 4*x;
430 Sk4f p4 = Sk4f::Load(rgba);
431 // From here on, just like F16:
432 if (p4[3] && needsUnpremul) {
433 float inva = 1 / p4[3];
434 p4 = p4 * Sk4f(inva, inva, inva, 1);
435 }
436 SkColor c;
437 SkNx_cast<uint8_t>(p4 * Sk4f(255) + Sk4f(0.5f)).store(&c);
438 // p4 is RGBA, but we want BGRA, so we need to swap next
439 return SkSwizzle_RB(c);
440 }
441 default:
442 SkDEBUGFAIL("");
443 return SkColorSetARGB(0, 0, 0, 0);
444 }
Hal Canary94e1a2f2016-10-31 09:38:12 -0400445}
Hal Canary58a76942016-12-07 15:24:59 -0500446
447bool SkPixmap::computeIsOpaque() const {
448 const int height = this->height();
449 const int width = this->width();
450
451 switch (this->colorType()) {
452 case kAlpha_8_SkColorType: {
453 unsigned a = 0xFF;
454 for (int y = 0; y < height; ++y) {
455 const uint8_t* row = this->addr8(0, y);
456 for (int x = 0; x < width; ++x) {
457 a &= row[x];
458 }
459 if (0xFF != a) {
460 return false;
461 }
462 }
463 return true;
464 } break;
Hal Canary58a76942016-12-07 15:24:59 -0500465 case kRGB_565_SkColorType:
466 case kGray_8_SkColorType:
467 return true;
468 break;
469 case kARGB_4444_SkColorType: {
470 unsigned c = 0xFFFF;
471 for (int y = 0; y < height; ++y) {
472 const SkPMColor16* row = this->addr16(0, y);
473 for (int x = 0; x < width; ++x) {
474 c &= row[x];
475 }
476 if (0xF != SkGetPackedA4444(c)) {
477 return false;
478 }
479 }
480 return true;
481 } break;
482 case kBGRA_8888_SkColorType:
483 case kRGBA_8888_SkColorType: {
484 SkPMColor c = (SkPMColor)~0;
485 for (int y = 0; y < height; ++y) {
486 const SkPMColor* row = this->addr32(0, y);
487 for (int x = 0; x < width; ++x) {
488 c &= row[x];
489 }
490 if (0xFF != SkGetPackedA32(c)) {
491 return false;
492 }
493 }
494 return true;
495 }
496 case kRGBA_F16_SkColorType: {
497 const SkHalf* row = (const SkHalf*)this->addr();
498 for (int y = 0; y < height; ++y) {
499 for (int x = 0; x < width; ++x) {
500 if (row[4 * x + 3] < SK_Half1) {
501 return false;
502 }
503 }
504 row += this->rowBytes() >> 1;
505 }
506 return true;
507 }
508 default:
509 break;
510 }
511 return false;
512}
Mike Reed43798692017-10-17 18:04:32 +0000513
514//////////////////////////////////////////////////////////////////////////////////////////////////
515
Mike Reed7306bcd2017-10-25 10:37:30 -0400516static bool draw_orientation(const SkPixmap& dst, const SkPixmap& src, unsigned flags) {
517 auto surf = SkSurface::MakeRasterDirect(dst.info(), dst.writable_addr(), dst.rowBytes());
518 if (!surf) {
519 return false;
Mike Reed43798692017-10-17 18:04:32 +0000520 }
Mike Reed43798692017-10-17 18:04:32 +0000521
Mike Reed7306bcd2017-10-25 10:37:30 -0400522 SkBitmap bm;
523 bm.installPixels(src);
Mike Reed43798692017-10-17 18:04:32 +0000524
Mike Reed7306bcd2017-10-25 10:37:30 -0400525 SkMatrix m;
526 m.setIdentity();
527
528 SkScalar W = SkIntToScalar(src.width());
529 SkScalar H = SkIntToScalar(src.height());
530 if (flags & SkPixmapPriv::kSwapXY) {
531 SkMatrix s;
532 s.setAll(0, 1, 0, 1, 0, 0, 0, 0, 1);
533 m.postConcat(s);
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400534 using std::swap;
535 swap(W, H);
Mike Reed43798692017-10-17 18:04:32 +0000536 }
Mike Reed7306bcd2017-10-25 10:37:30 -0400537 if (flags & SkPixmapPriv::kMirrorX) {
538 m.postScale(-1, 1);
539 m.postTranslate(W, 0);
540 }
541 if (flags & SkPixmapPriv::kMirrorY) {
542 m.postScale(1, -1);
543 m.postTranslate(0, H);
544 }
545 SkPaint p;
546 p.setBlendMode(SkBlendMode::kSrc);
547 surf->getCanvas()->concat(m);
548 surf->getCanvas()->drawBitmap(bm, 0, 0, &p);
Mike Reed43798692017-10-17 18:04:32 +0000549 return true;
550}
551
552bool SkPixmapPriv::Orient(const SkPixmap& dst, const SkPixmap& src, OrientFlags flags) {
553 SkASSERT((flags & ~(kMirrorX | kMirrorY | kSwapXY)) == 0);
554 if (src.colorType() != dst.colorType()) {
555 return false;
556 }
557 // note: we just ignore alphaType and colorSpace for this transformation
558
559 int w = src.width();
560 int h = src.height();
561 if (flags & kSwapXY) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400562 using std::swap;
563 swap(w, h);
Mike Reed43798692017-10-17 18:04:32 +0000564 }
565 if (dst.width() != w || dst.height() != h) {
566 return false;
567 }
568 if (w == 0 || h == 0) {
569 return true;
570 }
571
572 // check for aliasing to self
573 if (src.addr() == dst.addr()) {
574 return flags == 0;
575 }
Mike Reed7306bcd2017-10-25 10:37:30 -0400576 return draw_orientation(dst, src, flags);
Mike Reed43798692017-10-17 18:04:32 +0000577}
578
Leon Scroggins III0cbc10f2017-10-30 09:07:53 -0400579#define kMirrorX SkPixmapPriv::kMirrorX
580#define kMirrorY SkPixmapPriv::kMirrorY
581#define kSwapXY SkPixmapPriv::kSwapXY
582
583static constexpr uint8_t gOrientationFlags[] = {
584 0, // kTopLeft_SkEncodedOrigin
585 kMirrorX, // kTopRight_SkEncodedOrigin
586 kMirrorX | kMirrorY, // kBottomRight_SkEncodedOrigin
587 kMirrorY, // kBottomLeft_SkEncodedOrigin
588 kSwapXY, // kLeftTop_SkEncodedOrigin
589 kMirrorX | kSwapXY, // kRightTop_SkEncodedOrigin
590 kMirrorX | kMirrorY | kSwapXY, // kRightBottom_SkEncodedOrigin
591 kMirrorY | kSwapXY, // kLeftBottom_SkEncodedOrigin
592};
593
594SkPixmapPriv::OrientFlags SkPixmapPriv::OriginToOrient(SkEncodedOrigin o) {
595 unsigned io = static_cast<int>(o) - 1;
596 SkASSERT(io < SK_ARRAY_COUNT(gOrientationFlags));
597 return static_cast<SkPixmapPriv::OrientFlags>(gOrientationFlags[io]);
598}
599
600bool SkPixmapPriv::ShouldSwapWidthHeight(SkEncodedOrigin o) {
601 return SkToBool(OriginToOrient(o) & kSwapXY);
602}
603
604SkImageInfo SkPixmapPriv::SwapWidthHeight(const SkImageInfo& info) {
605 return info.makeWH(info.height(), info.width());
606}
607