blob: a1be5b72a5c5aa596b2731cb3c1bb312be7c2aed [file] [log] [blame]
sergeyv163f8812016-10-07 16:57:29 -07001/*
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 */
sergeyvc1c54062016-10-19 18:47:26 -070016#include "Bitmap.h"
sergeyv163f8812016-10-07 16:57:29 -070017
John Recke170fb62018-05-07 08:12:07 -070018#include "HardwareBitmapUploader.h"
John Reck339cf9b2018-07-18 16:32:27 -070019#include "Properties.h"
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +010020#ifdef __ANDROID__ // Layoutlib does not support render thread
sergeyv694d4992016-10-27 10:23:13 -070021#include "renderthread/RenderProxy.h"
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +010022#endif
Romain Guycaaaa662017-03-27 00:40:21 -070023#include "utils/Color.h"
Stan Iliev564ca3e2018-09-04 22:00:00 +000024#include <utils/Trace.h>
sergeyv163f8812016-10-07 16:57:29 -070025
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +010026#ifndef _WIN32
sergeyv163f8812016-10-07 16:57:29 -070027#include <sys/mman.h>
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +010028#endif
Mark Salyzyn6f773a02016-09-28 16:15:30 -070029
sergeyv163f8812016-10-07 16:57:29 -070030#include <cutils/ashmem.h>
John Reck1bcacfd2017-11-03 10:12:19 -070031#include <log/log.h>
sergeyv163f8812016-10-07 16:57:29 -070032
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +010033#ifndef _WIN32
sergeyv694d4992016-10-27 10:23:13 -070034#include <binder/IServiceManager.h>
John Reck1bcacfd2017-11-03 10:12:19 -070035#include <private/gui/ComposerService.h>
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +010036#endif
sergeyv694d4992016-10-27 10:23:13 -070037#include <ui/PixelFormat.h>
38
39#include <SkCanvas.h>
Stan Iliev7bc3bc62017-05-24 13:28:36 -040040#include <SkImagePriv.h>
sergeyv694d4992016-10-27 10:23:13 -070041
John Reck339cf9b2018-07-18 16:32:27 -070042#include <SkHighContrastFilter.h>
John Reck8f45d4a2018-08-15 10:17:12 -070043#include <limits>
Ben Wagnerdbbc74c2018-05-18 17:46:48 -040044
sergeyv163f8812016-10-07 16:57:29 -070045namespace android {
46
Ben Wagnerdbbc74c2018-05-18 17:46:48 -040047// returns true if rowBytes * height can be represented by a positive int32_t value
48// and places that value in size.
sergeyvfc9999502016-10-17 13:07:38 -070049static bool computeAllocationSize(size_t rowBytes, int height, size_t* size) {
Ben Wagnerdbbc74c2018-05-18 17:46:48 -040050 return 0 <= height && height <= std::numeric_limits<size_t>::max() &&
51 !__builtin_mul_overflow(rowBytes, (size_t)height, size) &&
52 *size <= std::numeric_limits<int32_t>::max();
sergeyvc36bd6c2016-10-11 15:49:16 -070053}
54
John Reck1bcacfd2017-11-03 10:12:19 -070055typedef sk_sp<Bitmap> (*AllocPixelRef)(size_t allocSize, const SkImageInfo& info, size_t rowBytes);
sergeyvc36bd6c2016-10-11 15:49:16 -070056
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -040057static sk_sp<Bitmap> allocateBitmap(SkBitmap* bitmap, AllocPixelRef alloc) {
sergeyvc36bd6c2016-10-11 15:49:16 -070058 const SkImageInfo& info = bitmap->info();
59 if (info.colorType() == kUnknown_SkColorType) {
60 LOG_ALWAYS_FATAL("unknown bitmap configuration");
61 return nullptr;
62 }
63
64 size_t size;
sergeyvc36bd6c2016-10-11 15:49:16 -070065
66 // we must respect the rowBytes value already set on the bitmap instead of
67 // attempting to compute our own.
68 const size_t rowBytes = bitmap->rowBytes();
sergeyvfc9999502016-10-17 13:07:38 -070069 if (!computeAllocationSize(rowBytes, bitmap->height(), &size)) {
70 return nullptr;
71 }
72
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -040073 auto wrapper = alloc(size, info, rowBytes);
sergeyvc36bd6c2016-10-11 15:49:16 -070074 if (wrapper) {
75 wrapper->getSkBitmap(bitmap);
sergeyvc36bd6c2016-10-11 15:49:16 -070076 }
77 return wrapper;
78}
79
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -040080sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(SkBitmap* bitmap) {
John Reck1bcacfd2017-11-03 10:12:19 -070081 return allocateBitmap(bitmap, &Bitmap::allocateAshmemBitmap);
sergeyvc36bd6c2016-10-11 15:49:16 -070082}
83
John Reck1bcacfd2017-11-03 10:12:19 -070084sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +010085#ifdef __ANDROID__
sergeyvc36bd6c2016-10-11 15:49:16 -070086 // Create new ashmem region with read/write priv
87 int fd = ashmem_create_region("bitmap", size);
88 if (fd < 0) {
89 return nullptr;
90 }
91
92 void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
93 if (addr == MAP_FAILED) {
94 close(fd);
95 return nullptr;
96 }
97
98 if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
99 munmap(addr, size);
100 close(fd);
101 return nullptr;
102 }
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -0400103 return sk_sp<Bitmap>(new Bitmap(addr, fd, size, info, rowBytes));
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100104#else
105 return Bitmap::allocateHeapBitmap(size, info, rowBytes);
106#endif
sergeyvc36bd6c2016-10-11 15:49:16 -0700107}
108
Derek Sollenbergere2169482018-11-20 10:57:20 -0500109sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(const SkBitmap& bitmap) {
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100110#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
Derek Sollenbergere2169482018-11-20 10:57:20 -0500111 return uirenderer::HardwareBitmapUploader::allocateHardwareBitmap(bitmap);
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100112#else
113 return Bitmap::allocateHeapBitmap(bitmap.info());
114#endif
Derek Sollenbergere2169482018-11-20 10:57:20 -0500115}
116
117sk_sp<Bitmap> Bitmap::allocateHeapBitmap(SkBitmap* bitmap) {
118 return allocateBitmap(bitmap, &Bitmap::allocateHeapBitmap);
119}
120
121sk_sp<Bitmap> Bitmap::allocateHeapBitmap(const SkImageInfo& info) {
122 size_t size;
123 if (!computeAllocationSize(info.minRowBytes(), info.height(), &size)) {
124 LOG_ALWAYS_FATAL("trying to allocate too large bitmap");
125 return nullptr;
126 }
127 return allocateHeapBitmap(size, info, info.minRowBytes());
128}
129
130sk_sp<Bitmap> Bitmap::allocateHeapBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
131 void* addr = calloc(size, 1);
132 if (!addr) {
133 return nullptr;
134 }
135 return sk_sp<Bitmap>(new Bitmap(addr, size, info, rowBytes));
136}
137
sergeyvaed7f582016-10-14 16:30:21 -0700138void FreePixelRef(void* addr, void* context) {
John Reck1bcacfd2017-11-03 10:12:19 -0700139 auto pixelRef = (SkPixelRef*)context;
sergeyvaed7f582016-10-14 16:30:21 -0700140 pixelRef->unref();
141}
142
143sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) {
144 pixelRef.ref();
John Reck1bcacfd2017-11-03 10:12:19 -0700145 return sk_sp<Bitmap>(new Bitmap((void*)pixelRef.pixels(), (void*)&pixelRef, FreePixelRef, info,
146 pixelRef.rowBytes()));
sergeyvaed7f582016-10-14 16:30:21 -0700147}
148
Derek Sollenbergere2169482018-11-20 10:57:20 -0500149
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100150#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
Derek Sollenbergere78f7c92019-07-31 15:18:47 -0400151sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, sk_sp<SkColorSpace> colorSpace,
152 BitmapPalette palette) {
153 AHardwareBuffer_Desc bufferDesc;
154 AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
155 SkImageInfo info = uirenderer::BufferDescriptionToImageInfo(bufferDesc, colorSpace);
156
157 const size_t rowBytes = info.bytesPerPixel() * bufferDesc.stride;
158 return sk_sp<Bitmap>(new Bitmap(hardwareBuffer, info, rowBytes, palette));
159}
160
161sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, SkColorType colorType,
Derek Sollenberger6e35e632019-01-22 13:56:25 -0500162 sk_sp<SkColorSpace> colorSpace, SkAlphaType alphaType,
163 BitmapPalette palette) {
Derek Sollenbergere78f7c92019-07-31 15:18:47 -0400164 AHardwareBuffer_Desc bufferDesc;
165 AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
166 SkImageInfo info = SkImageInfo::Make(bufferDesc.width, bufferDesc.height,
Derek Sollenberger6e35e632019-01-22 13:56:25 -0500167 colorType, alphaType, colorSpace);
Derek Sollenbergere78f7c92019-07-31 15:18:47 -0400168
169 const size_t rowBytes = info.bytesPerPixel() * bufferDesc.stride;
170 return sk_sp<Bitmap>(new Bitmap(hardwareBuffer, info, rowBytes, palette));
rennb2e9f522018-09-26 10:49:00 -0700171}
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100172#endif
rennb2e9f522018-09-26 10:49:00 -0700173
Derek Sollenbergere2169482018-11-20 10:57:20 -0500174sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, size_t rowBytes, int fd, void* addr,
175 size_t size, bool readOnly) {
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100176#ifdef _WIN32 // ashmem not implemented on Windows
177 return nullptr;
178#else
Derek Sollenbergere2169482018-11-20 10:57:20 -0500179 if (info.colorType() == kUnknown_SkColorType) {
180 LOG_ALWAYS_FATAL("unknown bitmap configuration");
181 return nullptr;
182 }
183
184 if (!addr) {
185 // Map existing ashmem region if not already mapped.
186 int flags = readOnly ? (PROT_READ) : (PROT_READ | PROT_WRITE);
187 size = ashmem_get_size_region(fd);
188 addr = mmap(NULL, size, flags, MAP_SHARED, fd, 0);
189 if (addr == MAP_FAILED) {
190 return nullptr;
191 }
192 }
193
194 sk_sp<Bitmap> bitmap(new Bitmap(addr, fd, size, info, rowBytes));
195 if (readOnly) {
196 bitmap->setImmutable();
197 }
198 return bitmap;
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100199#endif
sergeyv9a029872016-11-29 10:13:28 -0800200}
201
Romain Guy82426562017-04-04 19:38:50 -0700202void Bitmap::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
Matt Sarett489cfff2017-04-21 18:08:40 -0400203 mInfo = mInfo.makeColorSpace(std::move(colorSpace));
204}
205
206static SkImageInfo validateAlpha(const SkImageInfo& info) {
207 // Need to validate the alpha type to filter against the color type
208 // to prevent things like a non-opaque RGB565 bitmap
209 SkAlphaType alphaType;
John Reck1bcacfd2017-11-03 10:12:19 -0700210 LOG_ALWAYS_FATAL_IF(
211 !SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &alphaType),
Matt Sarett489cfff2017-04-21 18:08:40 -0400212 "Failed to validate alpha type!");
213 return info.makeAlphaType(alphaType);
Romain Guy82426562017-04-04 19:38:50 -0700214}
215
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -0400216void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes) {
Matt Sarett489cfff2017-04-21 18:08:40 -0400217 mInfo = validateAlpha(newInfo);
sergeyv163f8812016-10-07 16:57:29 -0700218
219 // Dirty hack is dirty
220 // TODO: Figure something out here, Skia's current design makes this
221 // really hard to work with. Skia really, really wants immutable objects,
222 // but with the nested-ref-count hackery going on that's just not
223 // feasible without going insane trying to figure it out
Mike Reed81397c42017-07-18 17:04:16 -0400224 this->android_only_reset(mInfo.width(), mInfo.height(), rowBytes);
sergeyv163f8812016-10-07 16:57:29 -0700225}
226
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -0400227Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes)
John Reck1bcacfd2017-11-03 10:12:19 -0700228 : SkPixelRef(info.width(), info.height(), address, rowBytes)
229 , mInfo(validateAlpha(info))
230 , mPixelStorageType(PixelStorageType::Heap) {
sergeyv163f8812016-10-07 16:57:29 -0700231 mPixelStorage.heap.address = address;
232 mPixelStorage.heap.size = size;
sergeyv163f8812016-10-07 16:57:29 -0700233}
234
John Reck1bcacfd2017-11-03 10:12:19 -0700235Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info,
236 size_t rowBytes)
237 : SkPixelRef(info.width(), info.height(), address, rowBytes)
238 , mInfo(validateAlpha(info))
239 , mPixelStorageType(PixelStorageType::External) {
sergeyv163f8812016-10-07 16:57:29 -0700240 mPixelStorage.external.address = address;
241 mPixelStorage.external.context = context;
242 mPixelStorage.external.freeFunc = freeFunc;
sergeyv163f8812016-10-07 16:57:29 -0700243}
244
John Reck1bcacfd2017-11-03 10:12:19 -0700245Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes)
246 : SkPixelRef(info.width(), info.height(), address, rowBytes)
247 , mInfo(validateAlpha(info))
248 , mPixelStorageType(PixelStorageType::Ashmem) {
sergeyv163f8812016-10-07 16:57:29 -0700249 mPixelStorage.ashmem.address = address;
250 mPixelStorage.ashmem.fd = fd;
251 mPixelStorage.ashmem.size = mappedSize;
sergeyv163f8812016-10-07 16:57:29 -0700252}
253
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100254#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
Derek Sollenbergere78f7c92019-07-31 15:18:47 -0400255Bitmap::Bitmap(AHardwareBuffer* buffer, const SkImageInfo& info, size_t rowBytes,
256 BitmapPalette palette)
257 : SkPixelRef(info.width(), info.height(), nullptr, rowBytes)
Matt Sarett489cfff2017-04-21 18:08:40 -0400258 , mInfo(validateAlpha(info))
John Reck339cf9b2018-07-18 16:32:27 -0700259 , mPixelStorageType(PixelStorageType::Hardware)
260 , mPalette(palette)
261 , mPaletteGenerationId(getGenerationID()) {
sergeyv9a029872016-11-29 10:13:28 -0800262 mPixelStorage.hardware.buffer = buffer;
Derek Sollenbergere78f7c92019-07-31 15:18:47 -0400263 AHardwareBuffer_acquire(buffer);
John Reck1bcacfd2017-11-03 10:12:19 -0700264 setImmutable(); // HW bitmaps are always immutable
Derek Sollenbergere78f7c92019-07-31 15:18:47 -0400265 mImage = SkImage::MakeFromAHardwareBuffer(buffer, mInfo.alphaType(), mInfo.refColorSpace());
sergeyv694d4992016-10-27 10:23:13 -0700266}
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100267#endif
sergeyv9a029872016-11-29 10:13:28 -0800268
sergeyvc1c54062016-10-19 18:47:26 -0700269Bitmap::~Bitmap() {
sergeyv163f8812016-10-07 16:57:29 -0700270 switch (mPixelStorageType) {
John Reck1bcacfd2017-11-03 10:12:19 -0700271 case PixelStorageType::External:
272 mPixelStorage.external.freeFunc(mPixelStorage.external.address,
273 mPixelStorage.external.context);
274 break;
275 case PixelStorageType::Ashmem:
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100276#ifndef _WIN32 // ashmem not implemented on Windows
John Reck1bcacfd2017-11-03 10:12:19 -0700277 munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100278#endif
John Reck1bcacfd2017-11-03 10:12:19 -0700279 close(mPixelStorage.ashmem.fd);
280 break;
281 case PixelStorageType::Heap:
282 free(mPixelStorage.heap.address);
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100283#ifdef __ANDROID__
Tim Murraye0b5e842018-10-15 16:29:15 -0700284 mallopt(M_PURGE, 0);
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100285#endif
John Reck1bcacfd2017-11-03 10:12:19 -0700286 break;
287 case PixelStorageType::Hardware:
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100288#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
John Reck1bcacfd2017-11-03 10:12:19 -0700289 auto buffer = mPixelStorage.hardware.buffer;
Derek Sollenbergere78f7c92019-07-31 15:18:47 -0400290 AHardwareBuffer_release(buffer);
John Reck1bcacfd2017-11-03 10:12:19 -0700291 mPixelStorage.hardware.buffer = nullptr;
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100292#endif
John Reck1bcacfd2017-11-03 10:12:19 -0700293 break;
sergeyv163f8812016-10-07 16:57:29 -0700294 }
sergeyv163f8812016-10-07 16:57:29 -0700295}
296
sergeyvc1c54062016-10-19 18:47:26 -0700297bool Bitmap::hasHardwareMipMap() const {
sergeyv163f8812016-10-07 16:57:29 -0700298 return mHasHardwareMipMap;
299}
300
sergeyvc1c54062016-10-19 18:47:26 -0700301void Bitmap::setHasHardwareMipMap(bool hasMipMap) {
sergeyv163f8812016-10-07 16:57:29 -0700302 mHasHardwareMipMap = hasMipMap;
303}
304
sergeyvc1c54062016-10-19 18:47:26 -0700305void* Bitmap::getStorage() const {
sergeyv163f8812016-10-07 16:57:29 -0700306 switch (mPixelStorageType) {
John Reck1bcacfd2017-11-03 10:12:19 -0700307 case PixelStorageType::External:
308 return mPixelStorage.external.address;
309 case PixelStorageType::Ashmem:
310 return mPixelStorage.ashmem.address;
311 case PixelStorageType::Heap:
312 return mPixelStorage.heap.address;
313 case PixelStorageType::Hardware:
314 return nullptr;
sergeyv163f8812016-10-07 16:57:29 -0700315 }
316}
317
sergeyvc1c54062016-10-19 18:47:26 -0700318int Bitmap::getAshmemFd() const {
sergeyv163f8812016-10-07 16:57:29 -0700319 switch (mPixelStorageType) {
John Reck1bcacfd2017-11-03 10:12:19 -0700320 case PixelStorageType::Ashmem:
321 return mPixelStorage.ashmem.fd;
322 default:
323 return -1;
sergeyv163f8812016-10-07 16:57:29 -0700324 }
325}
326
sergeyvc1c54062016-10-19 18:47:26 -0700327size_t Bitmap::getAllocationByteCount() const {
sergeyv163f8812016-10-07 16:57:29 -0700328 switch (mPixelStorageType) {
John Reck1bcacfd2017-11-03 10:12:19 -0700329 case PixelStorageType::Heap:
330 return mPixelStorage.heap.size;
Leon Scroggins IIIbbdb7312019-01-31 14:35:54 -0500331 case PixelStorageType::Ashmem:
332 return mPixelStorage.ashmem.size;
John Reck1bcacfd2017-11-03 10:12:19 -0700333 default:
334 return rowBytes() * height();
sergeyv163f8812016-10-07 16:57:29 -0700335 }
336}
337
sergeyvc1c54062016-10-19 18:47:26 -0700338void Bitmap::reconfigure(const SkImageInfo& info) {
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -0400339 reconfigure(info, info.minRowBytes());
sergeyv163f8812016-10-07 16:57:29 -0700340}
341
sergeyvc1c54062016-10-19 18:47:26 -0700342void Bitmap::setAlphaType(SkAlphaType alphaType) {
sergeyv163f8812016-10-07 16:57:29 -0700343 if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
344 return;
345 }
346
Matt Sarett489cfff2017-04-21 18:08:40 -0400347 mInfo = mInfo.makeAlphaType(alphaType);
sergeyv163f8812016-10-07 16:57:29 -0700348}
349
sergeyvc1c54062016-10-19 18:47:26 -0700350void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100351#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
sergeyv694d4992016-10-27 10:23:13 -0700352 if (isHardware()) {
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400353 outBitmap->allocPixels(mInfo);
Stan Iliev1a025a72018-09-05 16:35:11 -0400354 uirenderer::renderthread::RenderProxy::copyHWBitmapInto(this, outBitmap);
sergeyv694d4992016-10-27 10:23:13 -0700355 return;
356 }
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100357#endif
Matt Sarett489cfff2017-04-21 18:08:40 -0400358 outBitmap->setInfo(mInfo, rowBytes());
Mike Reed826deef2017-04-04 15:32:04 -0400359 outBitmap->setPixelRef(sk_ref_sp(this), 0, 0);
sergeyv163f8812016-10-07 16:57:29 -0700360}
361
sergeyvec4a4b12016-10-20 18:39:04 -0700362void Bitmap::getBounds(SkRect* bounds) const {
363 SkASSERT(bounds);
Matt Sarett489cfff2017-04-21 18:08:40 -0400364 bounds->set(0, 0, SkIntToScalar(width()), SkIntToScalar(height()));
sergeyvec4a4b12016-10-20 18:39:04 -0700365}
366
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100367#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
Derek Sollenbergere78f7c92019-07-31 15:18:47 -0400368AHardwareBuffer* Bitmap::hardwareBuffer() {
sergeyv694d4992016-10-27 10:23:13 -0700369 if (isHardware()) {
370 return mPixelStorage.hardware.buffer;
371 }
372 return nullptr;
373}
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100374#endif
sergeyv694d4992016-10-27 10:23:13 -0700375
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400376sk_sp<SkImage> Bitmap::makeImage() {
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400377 sk_sp<SkImage> image = mImage;
378 if (!image) {
John Reck1072fff2018-04-12 15:20:09 -0700379 SkASSERT(!isHardware());
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400380 SkBitmap skiaBitmap;
381 skiaBitmap.setInfo(info(), rowBytes());
382 skiaBitmap.setPixelRef(sk_ref_sp(this), 0, 0);
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400383 // Note we don't cache in this case, because the raster image holds a pointer to this Bitmap
384 // internally and ~Bitmap won't be invoked.
385 // TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here.
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400386 image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
387 }
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400388 return image;
389}
390
John Reck339cf9b2018-07-18 16:32:27 -0700391class MinMaxAverage {
392public:
John Reck339cf9b2018-07-18 16:32:27 -0700393 void add(float sample) {
394 if (mCount == 0) {
395 mMin = sample;
396 mMax = sample;
397 } else {
398 mMin = std::min(mMin, sample);
399 mMax = std::max(mMax, sample);
400 }
401 mTotal += sample;
402 mCount++;
403 }
404
John Reck8f45d4a2018-08-15 10:17:12 -0700405 float average() { return mTotal / mCount; }
John Reck339cf9b2018-07-18 16:32:27 -0700406
John Reck8f45d4a2018-08-15 10:17:12 -0700407 float min() { return mMin; }
John Reck339cf9b2018-07-18 16:32:27 -0700408
John Reck8f45d4a2018-08-15 10:17:12 -0700409 float max() { return mMax; }
John Reck339cf9b2018-07-18 16:32:27 -0700410
John Reck8f45d4a2018-08-15 10:17:12 -0700411 float delta() { return mMax - mMin; }
John Reck339cf9b2018-07-18 16:32:27 -0700412
413private:
414 float mMin = 0.0f;
415 float mMax = 0.0f;
416 float mTotal = 0.0f;
417 int mCount = 0;
418};
419
420BitmapPalette Bitmap::computePalette(const SkImageInfo& info, const void* addr, size_t rowBytes) {
421 ATRACE_CALL();
422
423 SkPixmap pixmap{info, addr, rowBytes};
424
425 // TODO: This calculation of converting to HSV & tracking min/max is probably overkill
426 // Experiment with something simpler since we just want to figure out if it's "color-ful"
427 // and then the average perceptual lightness.
428
429 MinMaxAverage hue, saturation, value;
430 int sampledCount = 0;
431
432 // Sample a grid of 100 pixels to get an overall estimation of the colors in play
433 const int x_step = std::max(1, pixmap.width() / 10);
434 const int y_step = std::max(1, pixmap.height() / 10);
435 for (int x = 0; x < pixmap.width(); x += x_step) {
436 for (int y = 0; y < pixmap.height(); y += y_step) {
437 SkColor color = pixmap.getColor(x, y);
438 if (!info.isOpaque() && SkColorGetA(color) < 75) {
439 continue;
440 }
441
442 sampledCount++;
443 float hsv[3];
444 SkColorToHSV(color, hsv);
445 hue.add(hsv[0]);
446 saturation.add(hsv[1]);
447 value.add(hsv[2]);
448 }
449 }
450
451 // TODO: Tune the coverage threshold
452 if (sampledCount < 5) {
453 ALOGV("Not enough samples, only found %d for image sized %dx%d, format = %d, alpha = %d",
John Reck8f45d4a2018-08-15 10:17:12 -0700454 sampledCount, info.width(), info.height(), (int)info.colorType(),
455 (int)info.alphaType());
John Reck339cf9b2018-07-18 16:32:27 -0700456 return BitmapPalette::Unknown;
457 }
458
John Reck8f45d4a2018-08-15 10:17:12 -0700459 ALOGV("samples = %d, hue [min = %f, max = %f, avg = %f]; saturation [min = %f, max = %f, avg = "
460 "%f]",
461 sampledCount, hue.min(), hue.max(), hue.average(), saturation.min(), saturation.max(),
462 saturation.average());
John Reck339cf9b2018-07-18 16:32:27 -0700463
464 if (hue.delta() <= 20 && saturation.delta() <= .1f) {
465 if (value.average() >= .5f) {
466 return BitmapPalette::Light;
467 } else {
468 return BitmapPalette::Dark;
469 }
470 }
471 return BitmapPalette::Unknown;
472}
473
John Reck1bcacfd2017-11-03 10:12:19 -0700474} // namespace android