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 */ 8 9 10 #include "Layer.h" 11 12 #include <stdio.h> 13 14 #include <Bitmap.h> 15 #include <Catalog.h> 16 #include <Message.h> 17 18 #include "bitmap_compression.h" 19 #include "blending.h" 20 #include "lab_convert.h" 21 #include "support.h" 22 23 24 #undef B_TRANSLATE_CONTEXT 25 #define B_TRANSLATE_CONTEXT "Layer" 26 27 28 // constructor 29 Layer::Layer() 30 : fBitmap(NULL), 31 fBounds(0.0, 0.0, -1.0, -1.0), 32 fAlpha(1.0), 33 fMode(MODE_NORMAL), 34 fFlags(0) 35 { 36 } 37 38 39 // destructor 40 Layer::~Layer() 41 { 42 delete fBitmap; 43 } 44 45 46 // Compose 47 status_t 48 Layer::Compose(const BBitmap* into, BRect area) 49 { 50 if (!fBitmap || !fBitmap->IsValid() 51 || (fBitmap->ColorSpace() != B_RGBA32 52 && fBitmap->ColorSpace() != B_RGB32)) 53 return B_NO_INIT; 54 55 status_t status = B_BAD_VALUE; 56 if (!into || !area.IsValid() || (status = into->InitCheck()) < B_OK) 57 return status; 58 59 // make sure we don't access memory outside of our bitmap 60 area = area & fBitmap->Bounds(); 61 62 BRect r = ActiveBounds(); 63 if (!r.IsValid() || (fFlags & FLAG_INVISIBLE) || !r.Intersects(area)) 64 return B_OK; 65 66 r = r & area; 67 int32 left, top, right, bottom; 68 rect_to_int(r, left, top, right, bottom); 69 70 uint8* src = (uint8*)fBitmap->Bits(); 71 uint8* dst = (uint8*)into->Bits(); 72 uint32 bpr = into->BytesPerRow(); 73 src += 4 * left + bpr * top; 74 dst += 4 * left + bpr * top; 75 uint8 alphaOverride = (uint8)(fAlpha * 255); 76 77 switch (fMode) { 78 79 case MODE_SOFT_LIGHT: 80 for (; top <= bottom; top++) { 81 uint8* srcHandle = src; 82 uint8* dstHandle = dst; 83 for (int32 x = left; x <= right; x++) { 84 if (srcHandle[3] > 0) { 85 uint8 c1 = dstHandle[0] * srcHandle[0] >> 8; 86 c1 += dstHandle[0] * ( 87 255 - ( 88 (255 - dstHandle[0]) 89 * (255 - srcHandle[0]) 90 >> 8 91 ) - c1 92 ) >> 8; 93 c1 = (c1 * dstHandle[3] 94 + srcHandle[0] * (255 - dstHandle[3]) 95 ) >> 8; 96 97 uint8 c2 = dstHandle[1] * srcHandle[1] >> 8; 98 c2 += dstHandle[1] * ( 99 255 - ( 100 (255 - dstHandle[1]) 101 * (255 - srcHandle[1]) 102 >> 8 103 ) - c2 104 ) >> 8; 105 c2 = (c2 * dstHandle[3] 106 + srcHandle[1] * (255 - dstHandle[3]) 107 ) >> 8; 108 109 uint8 c3 = dstHandle[2] * srcHandle[2] >> 8; 110 c3 += dstHandle[2] * ( 111 255 - ( 112 (255 - dstHandle[2]) 113 * (255 - srcHandle[2]) 114 >> 8 115 ) - c3 116 ) >> 8; 117 c3 = (c3 * dstHandle[3] 118 + srcHandle[2] * (255 - dstHandle[3]) 119 ) >> 8; 120 121 blend_colors(dstHandle, 122 (srcHandle[3] * alphaOverride) >> 8, c1, c2, c3); 123 } 124 srcHandle += 4; 125 dstHandle += 4; 126 } 127 src += bpr; 128 dst += bpr; 129 } 130 break; 131 132 case MODE_LIGHTEN: 133 for (; top <= bottom; top++) { 134 uint8* srcHandle = src; 135 uint8* dstHandle = dst; 136 for (int32 x = left; x <= right; x++) { 137 if (srcHandle[3] > 0) { 138 // compose 139 uint8 c1 140 = (max_c(srcHandle[0], dstHandle[0]) * dstHandle[3] 141 + srcHandle[0] * (255 - dstHandle[3])) / 255; 142 uint8 c2 143 = (max_c(srcHandle[1], dstHandle[1]) * dstHandle[3] 144 + srcHandle[1] * (255 - dstHandle[3])) / 255; 145 uint8 c3 146 = (max_c(srcHandle[2], dstHandle[2]) * dstHandle[3] 147 + srcHandle[2] * (255 - dstHandle[3])) / 255; 148 blend_colors(dstHandle, 149 (srcHandle[3] * alphaOverride) / 255, c1, c2, c3); 150 } 151 srcHandle += 4; 152 dstHandle += 4; 153 } 154 src += bpr; 155 dst += bpr; 156 } 157 break; 158 159 case MODE_DARKEN: 160 for (; top <= bottom; top++) { 161 uint8* srcHandle = src; 162 uint8* dstHandle = dst; 163 for (int32 x = left; x <= right; x++) { 164 if (srcHandle[3] > 0) { 165 // compose 166 uint8 c1 167 = (min_c(srcHandle[0], dstHandle[0]) * dstHandle[3] 168 + srcHandle[0] * (255 - dstHandle[3])) / 255; 169 uint8 c2 170 = (min_c(srcHandle[1], dstHandle[1]) * dstHandle[3] 171 + srcHandle[1] * (255 - dstHandle[3])) / 255; 172 uint8 c3 173 = (min_c(srcHandle[2], dstHandle[2]) * dstHandle[3] 174 + srcHandle[2] * (255 - dstHandle[3])) / 255; 175 blend_colors(dstHandle, 176 (srcHandle[3] * alphaOverride) / 255, c1, c2, c3); 177 } 178 srcHandle += 4; 179 dstHandle += 4; 180 } 181 src += bpr; 182 dst += bpr; 183 } 184 break; 185 186 case MODE_REPLACE_RED: 187 for (; top <= bottom; top++) { 188 uint8* srcHandle = src; 189 uint8* dstHandle = dst; 190 for (int32 x = left; x <= right; x++) { 191 if (srcHandle[3] > 0) { 192 // compose 193 uint32 alpha = srcHandle[3] * alphaOverride; 194 dstHandle[2] = (srcHandle[2] * alpha 195 + dstHandle[2] * (65025 - alpha)) / 65025; 196 } 197 srcHandle += 4; 198 dstHandle += 4; 199 } 200 src += bpr; 201 dst += bpr; 202 } 203 break; 204 205 case MODE_REPLACE_GREEN: 206 for (; top <= bottom; top++) { 207 uint8* srcHandle = src; 208 uint8* dstHandle = dst; 209 for (int32 x = left; x <= right; x++) { 210 if (srcHandle[3] > 0) { 211 // compose 212 uint32 alpha = srcHandle[3] * alphaOverride; 213 dstHandle[1] = (srcHandle[1] * alpha 214 + dstHandle[1] * (65025 - alpha)) / 65025; 215 } 216 srcHandle += 4; 217 dstHandle += 4; 218 } 219 src += bpr; 220 dst += bpr; 221 } 222 break; 223 224 case MODE_REPLACE_BLUE: 225 for (; top <= bottom; top++) { 226 uint8* srcHandle = src; 227 uint8* dstHandle = dst; 228 for (int32 x = left; x <= right; x++) { 229 if (srcHandle[3] > 0) { 230 // compose 231 uint32 alpha = srcHandle[3] * alphaOverride; 232 dstHandle[0] = (srcHandle[0] * alpha 233 + dstHandle[0] * (65025 - alpha)) / 65025; 234 } 235 srcHandle += 4; 236 dstHandle += 4; 237 } 238 src += bpr; 239 dst += bpr; 240 } 241 break; 242 243 case MODE_MULTIPLY_INVERSE_ALPHA: 244 for (; top <= bottom; top++) { 245 uint8* srcHandle = src; 246 uint8* dstHandle = dst; 247 for (int32 x = left; x <= right; x++) { 248 // compose 249 uint8 temp = min_c(dstHandle[3], 255 - srcHandle[3]); 250 dstHandle[3] = ( 251 dstHandle[3] * (255 - alphaOverride) 252 + temp * alphaOverride 253 ) / 255; 254 srcHandle += 4; 255 dstHandle += 4; 256 } 257 src += bpr; 258 dst += bpr; 259 } 260 break; 261 262 case MODE_MULTIPLY_ALPHA: 263 for (; top <= bottom; top++) { 264 uint8* srcHandle = src; 265 uint8* dstHandle = dst; 266 for (int32 x = left; x <= right; x++) { 267 // compose 268 uint8 temp = min_c(dstHandle[3], srcHandle[3]); 269 dstHandle[3] = ( 270 dstHandle[3] * (255 - alphaOverride) 271 + temp * alphaOverride 272 ) / 255; 273 srcHandle += 4; 274 dstHandle += 4; 275 } 276 src += bpr; 277 dst += bpr; 278 } 279 break; 280 281 case MODE_LUMINANCE: 282 for (; top <= bottom; top++) { 283 uint8* srcHandle = src; 284 uint8* dstHandle = dst; 285 for (int32 x = left; x <= right; x++) { 286 if (srcHandle[3] > 0) { 287 // compose 288 uint8 r = dstHandle[2]; 289 uint8 g = dstHandle[1]; 290 uint8 b = dstHandle[0]; 291 uint8 alpha = dstHandle[3]; 292 replace_luminance(r, g, b, srcHandle[2], srcHandle[1], 293 srcHandle[0]); 294 blend_colors(dstHandle, 295 (srcHandle[3] * alphaOverride) / 255, b, g, r); 296 dstHandle[3] = alpha; 297 } 298 srcHandle += 4; 299 dstHandle += 4; 300 } 301 src += bpr; 302 dst += bpr; 303 } 304 break; 305 306 case MODE_INVERSE_MULTIPLY: 307 for (; top <= bottom; top++) { 308 uint8* srcHandle = src; 309 uint8* dstHandle = dst; 310 for (int32 x = left; x <= right; x++) { 311 if (srcHandle[3] > 0) { 312 // compose 313 uint8 c1 = 255 - ( 314 (((255 - srcHandle[0]) * (255 - dstHandle[0])) 315 / 255) * dstHandle[3] 316 + (255 - srcHandle[0]) * (255 - dstHandle[3]) 317 ) / 255; 318 uint8 c2 = 255 - ( 319 (((255 - srcHandle[1]) * (255 - dstHandle[1])) 320 / 255) * dstHandle[3] 321 + (255 - srcHandle[1]) * (255 - dstHandle[3]) 322 ) / 255; 323 uint8 c3 = 255 - ( 324 (((255 - srcHandle[2]) * (255 - dstHandle[2])) 325 / 255) * dstHandle[3] 326 + (255 - srcHandle[2]) * (255 - dstHandle[3]) 327 ) / 255; 328 blend_colors(dstHandle, 329 (srcHandle[3] * alphaOverride) / 255, c1, c2, c3); 330 } 331 srcHandle += 4; 332 dstHandle += 4; 333 } 334 src += bpr; 335 dst += bpr; 336 } 337 break; 338 339 case MODE_MULTIPLY: 340 for (; top <= bottom; top++) { 341 uint8* srcHandle = src; 342 uint8* dstHandle = dst; 343 for (int32 x = left; x <= right; x++) { 344 if (srcHandle[3] > 0) { 345 // compose 346 uint8 c1 = ( 347 ((srcHandle[0] * dstHandle[0]) / 255) 348 * dstHandle[3] 349 + srcHandle[0] * (255 - dstHandle[3]) 350 ) / 255; 351 uint8 c2 = ( 352 ((srcHandle[1] * dstHandle[1]) / 255) 353 * dstHandle[3] 354 + srcHandle[1] * (255 - dstHandle[3]) 355 ) / 255; 356 uint8 c3 = ( 357 ((srcHandle[2] * dstHandle[2]) / 255) 358 * dstHandle[3] 359 + srcHandle[2] * (255 - dstHandle[3]) 360 ) / 255; 361 blend_colors(dstHandle, 362 (srcHandle[3] * alphaOverride) / 255, c1, c2, c3); 363 } 364 srcHandle += 4; 365 dstHandle += 4; 366 } 367 src += bpr; 368 dst += bpr; 369 } 370 break; 371 372 case MODE_NORMAL: 373 default: 374 if (alphaOverride == 255) { 375 // use an optimized version that composes the bitmaps directly 376 for (; top <= bottom; top++) { 377 uint8* srcHandle = src; 378 uint8* dstHandle = dst; 379 for (int32 x = left; x <= right; x++) { 380 blend_colors(dstHandle, srcHandle); 381 srcHandle += 4; 382 dstHandle += 4; 383 } 384 src += bpr; 385 dst += bpr; 386 } 387 } else { 388 for (; top <= bottom; top++) { 389 uint8* srcHandle = src; 390 uint8* dstHandle = dst; 391 for (int32 x = left; x <= right; x++) { 392 blend_colors(dstHandle, srcHandle, alphaOverride); 393 srcHandle += 4; 394 dstHandle += 4; 395 } 396 src += bpr; 397 dst += bpr; 398 } 399 } 400 break; 401 } 402 403 return status; 404 } 405 406 407 // Unarchive 408 status_t 409 Layer::Unarchive(const BMessage* archive) 410 { 411 if (!archive) 412 return B_BAD_VALUE; 413 414 // restore attributes 415 float alpha; 416 if (archive->FindFloat("alpha", &alpha) == B_OK) { 417 constrain(alpha, 0.0, 1.0); 418 fAlpha = alpha; 419 } else 420 fAlpha = 1.0; 421 if (archive->FindInt32("mode", (int32*)&fMode) < B_OK) 422 fMode = MODE_NORMAL; 423 if (archive->FindInt32("flags", (int32*)&fFlags) < B_OK) 424 fFlags = 0; 425 426 // delete current contents 427 delete fBitmap; 428 fBitmap = NULL; 429 430 status_t status = extract_bitmap(&fBitmap, archive, "current bitmap"); 431 if (status < B_OK) 432 return status; 433 434 // "bounds" is where the layer actually has content 435 BRect bounds; 436 if (archive->FindRect("bounds", &bounds) == B_OK) 437 fBounds = bounds; 438 else 439 fBounds.Set(0.0, 0.0, -1.0, -1.0); 440 441 // validate status of fBitmap 442 if (!fBitmap) 443 return B_ERROR; 444 445 status = fBitmap->InitCheck(); 446 if (status < B_OK) { 447 delete fBitmap; 448 fBitmap = NULL; 449 } 450 451 return status; 452 } 453