1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "Bitmap.h"
17 
18 #include "HardwareBitmapUploader.h"
19 #include "Properties.h"
20 #ifdef __ANDROID__  // Layoutlib does not support render thread
21 #include <private/android/AHardwareBufferHelpers.h>
22 #include <ui/GraphicBuffer.h>
23 #include <ui/GraphicBufferMapper.h>
24 
25 #include "renderthread/RenderProxy.h"
26 #endif
27 #include "utils/Color.h"
28 #include <utils/Trace.h>
29 
30 #ifndef _WIN32
31 #include <sys/mman.h>
32 #endif
33 
34 #include <cutils/ashmem.h>
35 #include <log/log.h>
36 
37 #ifndef _WIN32
38 #include <binder/IServiceManager.h>
39 #endif
40 
41 #include <Gainmap.h>
42 #include <SkCanvas.h>
43 #include <SkColor.h>
44 #include <SkEncodedImageFormat.h>
45 #include <SkHighContrastFilter.h>
46 #include <SkImage.h>
47 #include <SkImageAndroid.h>
48 #include <SkImagePriv.h>
49 #include <SkJpegGainmapEncoder.h>
50 #include <SkPixmap.h>
51 #include <SkRect.h>
52 #include <SkStream.h>
53 #include <SkJpegEncoder.h>
54 #include <SkPngEncoder.h>
55 #include <SkWebpEncoder.h>
56 
57 #include <limits>
58 
59 namespace android {
60 
61 #ifdef __ANDROID__
AHardwareBuffer_getAllocationSize(AHardwareBuffer * aHardwareBuffer)62 static uint64_t AHardwareBuffer_getAllocationSize(AHardwareBuffer* aHardwareBuffer) {
63     GraphicBuffer* buffer = AHardwareBuffer_to_GraphicBuffer(aHardwareBuffer);
64     auto& mapper = GraphicBufferMapper::get();
65     uint64_t size = 0;
66     auto err = mapper.getAllocationSize(buffer->handle, &size);
67     if (err == OK) {
68         if (size > 0) {
69             return size;
70         } else {
71             ALOGW("Mapper returned size = 0 for buffer format: 0x%x size: %d x %d", buffer->format,
72                   buffer->width, buffer->height);
73             // Fall-through to estimate
74         }
75     }
76 
77     // Estimation time!
78     // Stride could be = 0 if it's ill-defined (eg, compressed buffer), in which case we use the
79     // width of the buffer instead
80     size = std::max(buffer->width, buffer->stride) * buffer->height;
81     // Require bpp to be at least 1. This is too low for many formats, but it's better than 0
82     // Also while we could make increasingly better estimates, the reality is that mapper@4
83     // should be common enough at this point that we won't ever hit this anyway
84     size *= std::max(1u, bytesPerPixel(buffer->format));
85     return size;
86 }
87 #endif
88 
computeAllocationSize(size_t rowBytes,int height,size_t * size)89 bool Bitmap::computeAllocationSize(size_t rowBytes, int height, size_t* size) {
90     return 0 <= height && height <= std::numeric_limits<size_t>::max() &&
91            !__builtin_mul_overflow(rowBytes, (size_t)height, size) &&
92            *size <= std::numeric_limits<int32_t>::max();
93 }
94 
95 typedef sk_sp<Bitmap> (*AllocPixelRef)(size_t allocSize, const SkImageInfo& info, size_t rowBytes);
96 
allocateBitmap(SkBitmap * bitmap,AllocPixelRef alloc)97 static sk_sp<Bitmap> allocateBitmap(SkBitmap* bitmap, AllocPixelRef alloc) {
98     const SkImageInfo& info = bitmap->info();
99     if (info.colorType() == kUnknown_SkColorType) {
100         LOG_ALWAYS_FATAL("unknown bitmap configuration");
101         return nullptr;
102     }
103 
104     size_t size;
105 
106     // we must respect the rowBytes value already set on the bitmap instead of
107     // attempting to compute our own.
108     const size_t rowBytes = bitmap->rowBytes();
109     if (!Bitmap::computeAllocationSize(rowBytes, bitmap->height(), &size)) {
110         return nullptr;
111     }
112 
113     auto wrapper = alloc(size, info, rowBytes);
114     if (wrapper) {
115         wrapper->getSkBitmap(bitmap);
116     }
117     return wrapper;
118 }
119 
allocateAshmemBitmap(SkBitmap * bitmap)120 sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(SkBitmap* bitmap) {
121     return allocateBitmap(bitmap, &Bitmap::allocateAshmemBitmap);
122 }
123 
allocateAshmemBitmap(size_t size,const SkImageInfo & info,size_t rowBytes)124 sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
125 #ifdef __ANDROID__
126     // Create new ashmem region with read/write priv
127     int fd = ashmem_create_region("bitmap", size);
128     if (fd < 0) {
129         return nullptr;
130     }
131 
132     void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
133     if (addr == MAP_FAILED) {
134         close(fd);
135         return nullptr;
136     }
137 
138     if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
139         munmap(addr, size);
140         close(fd);
141         return nullptr;
142     }
143     return sk_sp<Bitmap>(new Bitmap(addr, fd, size, info, rowBytes));
144 #else
145     return Bitmap::allocateHeapBitmap(size, info, rowBytes);
146 #endif
147 }
148 
allocateHardwareBitmap(const SkBitmap & bitmap)149 sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(const SkBitmap& bitmap) {
150 #ifdef __ANDROID__  // Layoutlib does not support hardware acceleration
151     return uirenderer::HardwareBitmapUploader::allocateHardwareBitmap(bitmap);
152 #else
153     return Bitmap::allocateHeapBitmap(bitmap.info());
154 #endif
155 }
156 
allocateHeapBitmap(SkBitmap * bitmap)157 sk_sp<Bitmap> Bitmap::allocateHeapBitmap(SkBitmap* bitmap) {
158     return allocateBitmap(bitmap, &Bitmap::allocateHeapBitmap);
159 }
160 
allocateHeapBitmap(const SkImageInfo & info)161 sk_sp<Bitmap> Bitmap::allocateHeapBitmap(const SkImageInfo& info) {
162     size_t size;
163     if (!computeAllocationSize(info.minRowBytes(), info.height(), &size)) {
164         LOG_ALWAYS_FATAL("trying to allocate too large bitmap");
165         return nullptr;
166     }
167     return allocateHeapBitmap(size, info, info.minRowBytes());
168 }
169 
allocateHeapBitmap(size_t size,const SkImageInfo & info,size_t rowBytes)170 sk_sp<Bitmap> Bitmap::allocateHeapBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
171     void* addr = calloc(size, 1);
172     if (!addr) {
173         return nullptr;
174     }
175     return sk_sp<Bitmap>(new Bitmap(addr, size, info, rowBytes));
176 }
177 
createFrom(const SkImageInfo & info,SkPixelRef & pixelRef)178 sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) {
179     return sk_sp<Bitmap>(new Bitmap(pixelRef, info));
180 }
181 
182 
183 #ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
createFrom(AHardwareBuffer * hardwareBuffer,sk_sp<SkColorSpace> colorSpace,BitmapPalette palette)184 sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, sk_sp<SkColorSpace> colorSpace,
185                                  BitmapPalette palette) {
186     AHardwareBuffer_Desc bufferDesc;
187     AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
188     SkImageInfo info = uirenderer::BufferDescriptionToImageInfo(bufferDesc, colorSpace);
189     return createFrom(hardwareBuffer, info, bufferDesc, palette);
190 }
191 
createFrom(AHardwareBuffer * hardwareBuffer,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,SkAlphaType alphaType,BitmapPalette palette)192 sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, SkColorType colorType,
193                                  sk_sp<SkColorSpace> colorSpace, SkAlphaType alphaType,
194                                  BitmapPalette palette) {
195     AHardwareBuffer_Desc bufferDesc;
196     AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
197     SkImageInfo info = SkImageInfo::Make(bufferDesc.width, bufferDesc.height,
198                                          colorType, alphaType, colorSpace);
199     return createFrom(hardwareBuffer, info, bufferDesc, palette);
200 }
201 
createFrom(AHardwareBuffer * hardwareBuffer,const SkImageInfo & info,const AHardwareBuffer_Desc & bufferDesc,BitmapPalette palette)202 sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, const SkImageInfo& info,
203                                  const AHardwareBuffer_Desc& bufferDesc, BitmapPalette palette) {
204     // If the stride is 0 we have to use the width as an approximation (eg, compressed buffer)
205     const auto bufferStride = bufferDesc.stride > 0 ? bufferDesc.stride : bufferDesc.width;
206     const size_t rowBytes = info.bytesPerPixel() * bufferStride;
207     return sk_sp<Bitmap>(new Bitmap(hardwareBuffer, info, rowBytes, palette));
208 }
209 #endif
210 
createFrom(const SkImageInfo & info,size_t rowBytes,int fd,void * addr,size_t size,bool readOnly)211 sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, size_t rowBytes, int fd, void* addr,
212                                  size_t size, bool readOnly) {
213 #ifdef _WIN32 // ashmem not implemented on Windows
214      return nullptr;
215 #else
216     if (info.colorType() == kUnknown_SkColorType) {
217         LOG_ALWAYS_FATAL("unknown bitmap configuration");
218         return nullptr;
219     }
220 
221     if (!addr) {
222         // Map existing ashmem region if not already mapped.
223         int flags = readOnly ? (PROT_READ) : (PROT_READ | PROT_WRITE);
224         size = ashmem_get_size_region(fd);
225         addr = mmap(NULL, size, flags, MAP_SHARED, fd, 0);
226         if (addr == MAP_FAILED) {
227             return nullptr;
228         }
229     }
230 
231     sk_sp<Bitmap> bitmap(new Bitmap(addr, fd, size, info, rowBytes));
232     if (readOnly) {
233         bitmap->setImmutable();
234     }
235     return bitmap;
236 #endif
237 }
238 
setColorSpace(sk_sp<SkColorSpace> colorSpace)239 void Bitmap::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
240     mInfo = mInfo.makeColorSpace(std::move(colorSpace));
241 }
242 
validateAlpha(const SkImageInfo & info)243 static SkImageInfo validateAlpha(const SkImageInfo& info) {
244     // Need to validate the alpha type to filter against the color type
245     // to prevent things like a non-opaque RGB565 bitmap
246     SkAlphaType alphaType;
247     LOG_ALWAYS_FATAL_IF(
248             !SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &alphaType),
249             "Failed to validate alpha type!");
250     return info.makeAlphaType(alphaType);
251 }
252 
reconfigure(const SkImageInfo & newInfo,size_t rowBytes)253 void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes) {
254     mInfo = validateAlpha(newInfo);
255 
256     // TODO: Skia intends for SkPixelRef to be immutable, but this method
257     // modifies it. Find another way to support reusing the same pixel memory.
258     this->android_only_reset(mInfo.width(), mInfo.height(), rowBytes);
259 }
260 
Bitmap(void * address,size_t size,const SkImageInfo & info,size_t rowBytes)261 Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes)
262         : SkPixelRef(info.width(), info.height(), address, rowBytes)
263         , mInfo(validateAlpha(info))
264         , mPixelStorageType(PixelStorageType::Heap) {
265     mPixelStorage.heap.address = address;
266     mPixelStorage.heap.size = size;
267 }
268 
Bitmap(SkPixelRef & pixelRef,const SkImageInfo & info)269 Bitmap::Bitmap(SkPixelRef& pixelRef, const SkImageInfo& info)
270         : SkPixelRef(info.width(), info.height(), pixelRef.pixels(), pixelRef.rowBytes())
271         , mInfo(validateAlpha(info))
272         , mPixelStorageType(PixelStorageType::WrappedPixelRef) {
273     pixelRef.ref();
274     mPixelStorage.wrapped.pixelRef = &pixelRef;
275 }
276 
Bitmap(void * address,int fd,size_t mappedSize,const SkImageInfo & info,size_t rowBytes)277 Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes)
278         : SkPixelRef(info.width(), info.height(), address, rowBytes)
279         , mInfo(validateAlpha(info))
280         , mPixelStorageType(PixelStorageType::Ashmem) {
281     mPixelStorage.ashmem.address = address;
282     mPixelStorage.ashmem.fd = fd;
283     mPixelStorage.ashmem.size = mappedSize;
284 }
285 
286 #ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
Bitmap(AHardwareBuffer * buffer,const SkImageInfo & info,size_t rowBytes,BitmapPalette palette)287 Bitmap::Bitmap(AHardwareBuffer* buffer, const SkImageInfo& info, size_t rowBytes,
288                BitmapPalette palette)
289         : SkPixelRef(info.width(), info.height(), nullptr, rowBytes)
290         , mInfo(validateAlpha(info))
291         , mPixelStorageType(PixelStorageType::Hardware)
292         , mPalette(palette)
293         , mPaletteGenerationId(getGenerationID()) {
294     mPixelStorage.hardware.buffer = buffer;
295     mPixelStorage.hardware.size = AHardwareBuffer_getAllocationSize(buffer);
296     AHardwareBuffer_acquire(buffer);
297     setImmutable();  // HW bitmaps are always immutable
298     mImage = SkImages::DeferredFromAHardwareBuffer(buffer, mInfo.alphaType(),
299                                                    mInfo.refColorSpace());
300 }
301 #endif
302 
~Bitmap()303 Bitmap::~Bitmap() {
304     switch (mPixelStorageType) {
305         case PixelStorageType::WrappedPixelRef:
306             mPixelStorage.wrapped.pixelRef->unref();
307             break;
308         case PixelStorageType::Ashmem:
309 #ifndef _WIN32 // ashmem not implemented on Windows
310             munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
311 #endif
312             close(mPixelStorage.ashmem.fd);
313             break;
314         case PixelStorageType::Heap:
315             free(mPixelStorage.heap.address);
316 #ifdef __ANDROID__
317             mallopt(M_PURGE, 0);
318 #endif
319             break;
320         case PixelStorageType::Hardware:
321 #ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
322             auto buffer = mPixelStorage.hardware.buffer;
323             AHardwareBuffer_release(buffer);
324             mPixelStorage.hardware.buffer = nullptr;
325 #endif
326             break;
327     }
328 }
329 
hasHardwareMipMap() const330 bool Bitmap::hasHardwareMipMap() const {
331     return mHasHardwareMipMap;
332 }
333 
setHasHardwareMipMap(bool hasMipMap)334 void Bitmap::setHasHardwareMipMap(bool hasMipMap) {
335     mHasHardwareMipMap = hasMipMap;
336 }
337 
getAshmemFd() const338 int Bitmap::getAshmemFd() const {
339     switch (mPixelStorageType) {
340         case PixelStorageType::Ashmem:
341             return mPixelStorage.ashmem.fd;
342         default:
343             return -1;
344     }
345 }
346 
getAllocationByteCount() const347 size_t Bitmap::getAllocationByteCount() const {
348     switch (mPixelStorageType) {
349         case PixelStorageType::Heap:
350             return mPixelStorage.heap.size;
351         case PixelStorageType::Ashmem:
352             return mPixelStorage.ashmem.size;
353 #ifdef __ANDROID__
354         case PixelStorageType::Hardware:
355             return mPixelStorage.hardware.size;
356 #endif
357         default:
358             return rowBytes() * height();
359     }
360 }
361 
reconfigure(const SkImageInfo & info)362 void Bitmap::reconfigure(const SkImageInfo& info) {
363     reconfigure(info, info.minRowBytes());
364 }
365 
setAlphaType(SkAlphaType alphaType)366 void Bitmap::setAlphaType(SkAlphaType alphaType) {
367     if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
368         return;
369     }
370 
371     mInfo = mInfo.makeAlphaType(alphaType);
372 }
373 
getSkBitmap(SkBitmap * outBitmap)374 void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
375 #ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
376     if (isHardware()) {
377         outBitmap->allocPixels(mInfo);
378         uirenderer::renderthread::RenderProxy::copyHWBitmapInto(this, outBitmap);
379         return;
380     }
381 #endif
382     outBitmap->setInfo(mInfo, rowBytes());
383     outBitmap->setPixelRef(sk_ref_sp(this), 0, 0);
384 }
385 
getBounds(SkRect * bounds) const386 void Bitmap::getBounds(SkRect* bounds) const {
387     SkASSERT(bounds);
388     bounds->setIWH(width(), height());
389 }
390 
391 #ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
hardwareBuffer()392 AHardwareBuffer* Bitmap::hardwareBuffer() {
393     if (isHardware()) {
394         return mPixelStorage.hardware.buffer;
395     }
396     return nullptr;
397 }
398 #endif
399 
makeImage()400 sk_sp<SkImage> Bitmap::makeImage() {
401     sk_sp<SkImage> image = mImage;
402     if (!image) {
403         SkASSERT(!isHardware());
404         SkBitmap skiaBitmap;
405         skiaBitmap.setInfo(info(), rowBytes());
406         skiaBitmap.setPixelRef(sk_ref_sp(this), 0, 0);
407         // Note we don't cache in this case, because the raster image holds a pointer to this Bitmap
408         // internally and ~Bitmap won't be invoked.
409         // TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here.
410 #ifdef __ANDROID__
411         // pinnable images are only supported with the Ganesh GPU backend compiled in.
412         image = SkImages::PinnableRasterFromBitmap(skiaBitmap);
413 #else
414         image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
415 #endif
416     }
417     return image;
418 }
419 
420 class MinMaxAverage {
421 public:
add(float sample)422     void add(float sample) {
423         if (mCount == 0) {
424             mMin = sample;
425             mMax = sample;
426         } else {
427             mMin = std::min(mMin, sample);
428             mMax = std::max(mMax, sample);
429         }
430         mTotal += sample;
431         mCount++;
432     }
433 
average()434     float average() { return mTotal / mCount; }
435 
min()436     float min() { return mMin; }
437 
max()438     float max() { return mMax; }
439 
delta()440     float delta() { return mMax - mMin; }
441 
442 private:
443     float mMin = 0.0f;
444     float mMax = 0.0f;
445     float mTotal = 0.0f;
446     int mCount = 0;
447 };
448 
computePalette(const SkImageInfo & info,const void * addr,size_t rowBytes)449 BitmapPalette Bitmap::computePalette(const SkImageInfo& info, const void* addr, size_t rowBytes) {
450     ATRACE_CALL();
451 
452     SkPixmap pixmap{info, addr, rowBytes};
453 
454     // TODO: This calculation of converting to HSV & tracking min/max is probably overkill
455     // Experiment with something simpler since we just want to figure out if it's "color-ful"
456     // and then the average perceptual lightness.
457 
458     MinMaxAverage hue, saturation, value;
459     int sampledCount = 0;
460 
461     // Sample a grid of 100 pixels to get an overall estimation of the colors in play
462     const int x_step = std::max(1, pixmap.width() / 10);
463     const int y_step = std::max(1, pixmap.height() / 10);
464     for (int x = 0; x < pixmap.width(); x += x_step) {
465         for (int y = 0; y < pixmap.height(); y += y_step) {
466             SkColor color = pixmap.getColor(x, y);
467             if (!info.isOpaque() && SkColorGetA(color) < 75) {
468                 continue;
469             }
470 
471             sampledCount++;
472             float hsv[3];
473             SkColorToHSV(color, hsv);
474             hue.add(hsv[0]);
475             saturation.add(hsv[1]);
476             value.add(hsv[2]);
477         }
478     }
479 
480     // TODO: Tune the coverage threshold
481     if (sampledCount < 5) {
482         ALOGV("Not enough samples, only found %d for image sized %dx%d, format = %d, alpha = %d",
483               sampledCount, info.width(), info.height(), (int)info.colorType(),
484               (int)info.alphaType());
485         return BitmapPalette::Unknown;
486     }
487 
488     ALOGV("samples = %d, hue [min = %f, max = %f, avg = %f]; saturation [min = %f, max = %f, avg = "
489           "%f]",
490           sampledCount, hue.min(), hue.max(), hue.average(), saturation.min(), saturation.max(),
491           saturation.average());
492 
493     if (hue.delta() <= 20 && saturation.delta() <= .1f) {
494         if (value.average() >= .5f) {
495             return BitmapPalette::Light;
496         } else {
497             return BitmapPalette::Dark;
498         }
499     }
500     return BitmapPalette::Unknown;
501 }
502 
compress(JavaCompressFormat format,int32_t quality,SkWStream * stream)503 bool Bitmap::compress(JavaCompressFormat format, int32_t quality, SkWStream* stream) {
504 #ifdef __ANDROID__  // TODO: This isn't built for host for some reason?
505     if (hasGainmap() && format == JavaCompressFormat::Jpeg) {
506         SkBitmap baseBitmap = getSkBitmap();
507         SkBitmap gainmapBitmap = gainmap()->bitmap->getSkBitmap();
508         if (gainmapBitmap.colorType() == SkColorType::kAlpha_8_SkColorType) {
509             SkBitmap greyGainmap;
510             auto greyInfo = gainmapBitmap.info().makeColorType(SkColorType::kGray_8_SkColorType);
511             greyGainmap.setInfo(greyInfo, gainmapBitmap.rowBytes());
512             greyGainmap.setPixelRef(sk_ref_sp(gainmapBitmap.pixelRef()), 0, 0);
513             gainmapBitmap = std::move(greyGainmap);
514         }
515         SkJpegEncoder::Options options{.fQuality = quality};
516         return SkJpegGainmapEncoder::EncodeHDRGM(stream, baseBitmap.pixmap(), options,
517                                                  gainmapBitmap.pixmap(), options, gainmap()->info);
518     }
519 #endif
520 
521     SkBitmap skbitmap;
522     getSkBitmap(&skbitmap);
523     return compress(skbitmap, format, quality, stream);
524 }
525 
compress(const SkBitmap & bitmap,JavaCompressFormat format,int32_t quality,SkWStream * stream)526 bool Bitmap::compress(const SkBitmap& bitmap, JavaCompressFormat format,
527                       int32_t quality, SkWStream* stream) {
528     if (bitmap.colorType() == kAlpha_8_SkColorType) {
529         // None of the JavaCompressFormats have a sensible way to compress an
530         // ALPHA_8 Bitmap. SkPngEncoder will compress one, but it uses a non-
531         // standard format that most decoders do not understand, so this is
532         // likely not useful.
533         return false;
534     }
535 
536     switch (format) {
537         case JavaCompressFormat::Jpeg: {
538             SkJpegEncoder::Options options;
539             options.fQuality = quality;
540             return SkJpegEncoder::Encode(stream, bitmap.pixmap(), options);
541         }
542         case JavaCompressFormat::Png:
543             return SkPngEncoder::Encode(stream, bitmap.pixmap(), {});
544         case JavaCompressFormat::Webp: {
545             SkWebpEncoder::Options options;
546             if (quality >= 100) {
547                 options.fCompression = SkWebpEncoder::Compression::kLossless;
548                 options.fQuality = 75; // This is effort to compress
549             } else {
550                 options.fCompression = SkWebpEncoder::Compression::kLossy;
551                 options.fQuality = quality;
552             }
553             return SkWebpEncoder::Encode(stream, bitmap.pixmap(), options);
554         }
555         case JavaCompressFormat::WebpLossy:
556         case JavaCompressFormat::WebpLossless: {
557             SkWebpEncoder::Options options;
558             options.fQuality = quality;
559             options.fCompression = format == JavaCompressFormat::WebpLossy ?
560                     SkWebpEncoder::Compression::kLossy : SkWebpEncoder::Compression::kLossless;
561             return SkWebpEncoder::Encode(stream, bitmap.pixmap(), options);
562         }
563     }
564 }
565 
gainmap() const566 sp<uirenderer::Gainmap> Bitmap::gainmap() const {
567     LOG_ALWAYS_FATAL_IF(!hasGainmap(), "Bitmap doesn't have a gainmap");
568     return mGainmap;
569 }
570 
setGainmap(sp<uirenderer::Gainmap> && gainmap)571 void Bitmap::setGainmap(sp<uirenderer::Gainmap>&& gainmap) {
572     mGainmap = std::move(gainmap);
573 }
574 
575 }  // namespace android
576