1 /* 2 * Copyright 2006, Haiku. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus <superstippi@gmx.de> 7 * Ingo Weinhold <bonefish@cs.tu-berlin.de> 8 */ 9 10 #include "IconUtils.h" 11 12 #include <new> 13 #include <fs_attr.h> 14 15 #include <Bitmap.h> 16 #include <Node.h> 17 #include <TypeConstants.h> 18 19 #include "Icon.h" 20 #include "IconRenderer.h" 21 #include "FlatIconImporter.h" 22 23 using std::nothrow; 24 25 26 // TODO: put into HaikuBuildCompatibility.h 27 #ifndef __HAIKU__ 28 # define B_BITMAP_NO_SERVER_LINK 0 29 # define B_BAD_DATA B_ERROR 30 # define B_MINI_ICON_TYPE 'MICN' 31 # define B_LARGE_ICON_TYPE 'ICON' 32 #endif 33 34 35 // GetIcon 36 status_t 37 BIconUtils::GetIcon(BNode* node, 38 const char* vectorIconAttrName, 39 const char* smallIconAttrName, 40 const char* largeIconAttrName, 41 icon_size size, 42 BBitmap* result) 43 { 44 if (!result || result->InitCheck()) 45 return B_BAD_VALUE; 46 47 status_t ret = B_ERROR; 48 49 switch (result->ColorSpace()) { 50 case B_RGBA32: 51 case B_RGB32: 52 // prefer vector icon 53 ret = GetVectorIcon(node, vectorIconAttrName, result); 54 if (ret < B_OK) { 55 // try to fallback to B_CMAP8 icons 56 // (converting to B_RGBA32 is handled) 57 ret = GetCMAP8Icon(node, 58 smallIconAttrName, 59 largeIconAttrName, 60 size, result); 61 } 62 break; 63 64 case B_CMAP8: 65 // prefer old B_CMAP8 icons 66 ret = GetCMAP8Icon(node, 67 smallIconAttrName, 68 largeIconAttrName, 69 size, result); 70 if (ret < B_OK) { 71 // try to fallback to vector icon 72 BBitmap temp(result->Bounds(), 73 B_BITMAP_NO_SERVER_LINK, B_RGBA32); 74 ret = temp.InitCheck(); 75 if (ret < B_OK) 76 break; 77 ret = GetVectorIcon(node, vectorIconAttrName, &temp); 78 if (ret < B_OK) 79 break; 80 uint32 width = temp.Bounds().IntegerWidth() + 1; 81 uint32 height = temp.Bounds().IntegerHeight() + 1; 82 uint32 bytesPerRow = temp.BytesPerRow(); 83 ret = ConvertFromCMAP8((uint8*)temp.Bits(), 84 width,height, bytesPerRow, result); 85 } 86 break; 87 default: 88 break; 89 } 90 91 return ret; 92 } 93 94 // #pragma mark - 95 96 // GetVectorIcon 97 status_t 98 BIconUtils::GetVectorIcon(BNode* node, const char* attrName, 99 BBitmap* result) 100 { 101 if (!node || node->InitCheck() < B_OK || !attrName) 102 return B_BAD_VALUE; 103 104 #if TIME_VECTOR_ICONS 105 bigtime_t startTime = system_time(); 106 #endif 107 108 // get the attribute info and check type and size of the attr contents 109 attr_info attrInfo; 110 status_t ret = node->GetAttrInfo(attrName, &attrInfo); 111 if (ret < B_OK) 112 return ret; 113 114 type_code attrType = B_RAW_TYPE; 115 // TODO: introduce special type? 116 117 if (attrInfo.type != attrType) 118 return B_BAD_TYPE; 119 120 // chicken out on unrealisticly large attributes 121 if (attrInfo.size > 16 * 1024) 122 return B_BAD_VALUE; 123 124 uint8 buffer[attrInfo.size]; 125 node->ReadAttr(attrName, attrType, 0, buffer, attrInfo.size); 126 127 #if TIME_VECTOR_ICONS 128 bigtime_t importTime = system_time(); 129 #endif 130 131 ret = GetVectorIcon(buffer, attrInfo.size, result); 132 if (ret < B_OK) 133 return ret; 134 135 #if TIME_VECTOR_ICONS 136 bigtime_t finishTime = system_time(); 137 printf("read: %lld, import: %lld\n", importTime - startTime, finishTime - importTime); 138 #endif 139 140 return B_OK; 141 } 142 143 // GetVectorIcon 144 status_t 145 BIconUtils::GetVectorIcon(const uint8* buffer, size_t size, 146 BBitmap* result) 147 { 148 if (!result) 149 return B_BAD_VALUE; 150 151 status_t ret = result->InitCheck(); 152 if (ret < B_OK) 153 return ret; 154 155 if (result->ColorSpace() != B_RGBA32 && result->ColorSpace() != B_RGB32) 156 return B_BAD_VALUE; 157 158 Icon icon; 159 ret = icon.InitCheck(); 160 if (ret < B_OK) 161 return ret; 162 163 FlatIconImporter importer; 164 ret = importer.Import(&icon, const_cast<uint8*>(buffer), size); 165 if (ret < B_OK) 166 return ret; 167 168 IconRenderer renderer(result); 169 renderer.SetIcon(&icon); 170 renderer.SetScale((result->Bounds().Width() + 1.0) / 64.0); 171 renderer.Render(); 172 173 // TODO: would be nice to get rid of this 174 // (B_RGBA32_PREMULTIPLIED or better yet, new blending_mode) 175 // NOTE: probably not necessary only because 176 // transparent colors are "black" in all existing icons 177 // lighter transparent colors should be too dark if 178 // app_server uses correct blending 179 // renderer.Demultiply(); 180 181 return B_OK; 182 } 183 184 // #pragma mark - 185 186 status_t 187 BIconUtils::GetCMAP8Icon(BNode* node, 188 const char* smallIconAttrName, 189 const char* largeIconAttrName, 190 icon_size size, 191 BBitmap* icon) 192 { 193 // check parameters and initialization 194 if (!icon || icon->InitCheck() != B_OK 195 || !node || node->InitCheck() != B_OK 196 || !smallIconAttrName || !largeIconAttrName) 197 return B_BAD_VALUE; 198 199 status_t ret = B_OK; 200 // set some icon size related variables 201 const char *attribute = NULL; 202 BRect bounds; 203 uint32 attrType = 0; 204 size_t attrSize = 0; 205 switch (size) { 206 case B_MINI_ICON: 207 attribute = smallIconAttrName; 208 bounds.Set(0, 0, 15, 15); 209 attrType = B_MINI_ICON_TYPE; 210 attrSize = 16 * 16; 211 break; 212 case B_LARGE_ICON: 213 attribute = largeIconAttrName; 214 bounds.Set(0, 0, 31, 31); 215 attrType = B_LARGE_ICON_TYPE; 216 attrSize = 32 * 32; 217 break; 218 default: 219 ret = B_BAD_VALUE; 220 break; 221 } 222 223 // TODO: relax this requirement? 224 if (icon->Bounds() != bounds) 225 return B_BAD_VALUE; 226 227 // get the attribute info and check type and size of the attr contents 228 attr_info attrInfo; 229 if (ret == B_OK) 230 ret = node->GetAttrInfo(attribute, &attrInfo); 231 if (ret == B_OK && attrInfo.type != attrType) 232 ret = B_BAD_TYPE; 233 if (ret == B_OK && attrInfo.size != attrSize) 234 ret = B_BAD_DATA; 235 236 // read the attribute 237 if (ret == B_OK) { 238 bool otherColorSpace = (icon->ColorSpace() != B_CMAP8); 239 uint8* buffer = NULL; 240 ssize_t read; 241 if (otherColorSpace) { 242 // other color space than stored in attribute 243 buffer = new(nothrow) uint8[attrSize]; 244 if (!buffer) 245 ret = B_NO_MEMORY; 246 if (ret == B_OK) { 247 read = node->ReadAttr(attribute, attrType, 0, buffer, 248 attrSize); 249 } 250 } else { 251 read = node->ReadAttr(attribute, attrType, 0, icon->Bits(), 252 attrSize); 253 } 254 if (ret == B_OK) { 255 if (read < 0) 256 ret = read; 257 else if (read != attrInfo.size) 258 ret = B_ERROR; 259 } 260 if (otherColorSpace) { 261 // other color space than stored in attribute 262 if (ret == B_OK) { 263 ret = ConvertFromCMAP8(buffer, 264 (uint32)size, (uint32)size, 265 (uint32)size, icon); 266 } 267 delete[] buffer; 268 } 269 } 270 return ret; 271 } 272 273 // #pragma mark - 274 275 // ConvertFromCMAP8 276 status_t 277 BIconUtils::ConvertFromCMAP8(BBitmap* source, BBitmap* result) 278 { 279 if (!source) 280 return B_BAD_VALUE; 281 282 status_t ret = source->InitCheck(); 283 if (ret < B_OK) 284 return ret; 285 286 if (source->ColorSpace() != B_CMAP8) 287 return B_BAD_VALUE; 288 289 uint8* src = (uint8*)source->Bits(); 290 uint32 srcBPR = source->BytesPerRow(); 291 uint32 width = source->Bounds().IntegerWidth() + 1; 292 uint32 height = source->Bounds().IntegerHeight() + 1; 293 294 return ConvertFromCMAP8(src, width, height, srcBPR, result); 295 } 296 297 // ConvertFromCMAP8 298 status_t 299 BIconUtils::ConvertFromCMAP8(const uint8* src, 300 uint32 width, uint32 height, uint32 srcBPR, 301 BBitmap* result) 302 { 303 if (!src || !result || srcBPR == 0) 304 return B_BAD_VALUE; 305 306 status_t ret = result->InitCheck(); 307 if (ret < B_OK) 308 return ret; 309 310 uint32 dstWidth = result->Bounds().IntegerWidth() + 1; 311 uint32 dstHeight = result->Bounds().IntegerHeight() + 1; 312 313 if (dstWidth < width || dstHeight < height) { 314 // TODO: down scaling 315 return B_ERROR; 316 } else if (dstWidth > width || dstHeight > height) { 317 // TODO: up scaling 318 // (currently copies bitmap into result at left-top) 319 } 320 321 #if __HAIKU__ 322 323 return result->ImportBits(src, height * srcBPR, srcBPR, 0, B_CMAP8); 324 325 #else 326 327 if (result->ColorSpace() != B_RGBA32 && result->ColorSpace() != B_RGB32) { 328 // TODO: support other color spaces 329 return B_BAD_VALUE; 330 } 331 332 uint8* dst = (uint8*)result->Bits(); 333 uint32 dstBPR = result->BytesPerRow(); 334 335 const rgb_color* colorMap = system_colors()->color_list; 336 337 for (uint32 y = 0; y < dstHeight; y++) { 338 uint32* d = (uint32*)dst; 339 const uint8* s = src; 340 for (uint32 x = 0; x < dstWidth; x++) { 341 const rgb_color c = colorMap[*s]; 342 uint8 alpha = 255; 343 if (*s == B_TRANSPARENT_MAGIC_CMAP8) 344 alpha = 0; 345 *d = (alpha << 24) | (c.red << 16) | (c.green << 8) | (c.blue); 346 s++; 347 d++; 348 } 349 src += srcBPR; 350 dst += dstBPR; 351 } 352 353 return B_OK; 354 355 #endif // __HAIKU__ 356 } 357 358 // #pragma mark - forbidden 359 360 BIconUtils::BIconUtils() {} 361 BIconUtils::~BIconUtils() {} 362 BIconUtils::BIconUtils(const BIconUtils&) {} 363 BIconUtils& BIconUtils::operator=(const BIconUtils&) { return *this; } 364 365