Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2008 The Android Open Source Project | 3 * Copyright 2008 The Android Open Source Project |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 | 9 |
| 10 #include "SkBitmap.h" | 10 #include "SkBitmap.h" |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 136 SkTSwap(fColorTable, other.fColorTable); | 136 SkTSwap(fColorTable, other.fColorTable); |
| 137 SkTSwap(fPixelRef, other.fPixelRef); | 137 SkTSwap(fPixelRef, other.fPixelRef); |
| 138 SkTSwap(fPixelRefOffset, other.fPixelRefOffset); | 138 SkTSwap(fPixelRefOffset, other.fPixelRefOffset); |
| 139 SkTSwap(fPixelLockCount, other.fPixelLockCount); | 139 SkTSwap(fPixelLockCount, other.fPixelLockCount); |
| 140 SkTSwap(fMipMap, other.fMipMap); | 140 SkTSwap(fMipMap, other.fMipMap); |
| 141 SkTSwap(fPixels, other.fPixels); | 141 SkTSwap(fPixels, other.fPixels); |
| 142 SkTSwap(fRowBytes, other.fRowBytes); | 142 SkTSwap(fRowBytes, other.fRowBytes); |
| 143 SkTSwap(fWidth, other.fWidth); | 143 SkTSwap(fWidth, other.fWidth); |
| 144 SkTSwap(fHeight, other.fHeight); | 144 SkTSwap(fHeight, other.fHeight); |
| 145 SkTSwap(fConfig, other.fConfig); | 145 SkTSwap(fConfig, other.fConfig); |
| 146 SkTSwap(fAlphaType, other.fAlphaType); | |
| 146 SkTSwap(fFlags, other.fFlags); | 147 SkTSwap(fFlags, other.fFlags); |
| 147 SkTSwap(fBytesPerPixel, other.fBytesPerPixel); | 148 SkTSwap(fBytesPerPixel, other.fBytesPerPixel); |
| 148 | 149 |
| 149 SkDEBUGCODE(this->validate();) | 150 SkDEBUGCODE(this->validate();) |
| 150 } | 151 } |
| 151 | 152 |
| 152 void SkBitmap::reset() { | 153 void SkBitmap::reset() { |
| 153 this->freePixels(); | 154 this->freePixels(); |
| 154 sk_bzero(this, sizeof(*this)); | 155 sk_bzero(this, sizeof(*this)); |
| 155 } | 156 } |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 259 SkIntToScalar(fWidth), SkIntToScalar(fHeight)); | 260 SkIntToScalar(fWidth), SkIntToScalar(fHeight)); |
| 260 } | 261 } |
| 261 | 262 |
| 262 void SkBitmap::getBounds(SkIRect* bounds) const { | 263 void SkBitmap::getBounds(SkIRect* bounds) const { |
| 263 SkASSERT(bounds); | 264 SkASSERT(bounds); |
| 264 bounds->set(0, 0, fWidth, fHeight); | 265 bounds->set(0, 0, fWidth, fHeight); |
| 265 } | 266 } |
| 266 | 267 |
| 267 /////////////////////////////////////////////////////////////////////////////// | 268 /////////////////////////////////////////////////////////////////////////////// |
| 268 | 269 |
| 269 void SkBitmap::setConfig(Config c, int width, int height, size_t rowBytes) { | 270 static bool validate_alphaType(SkBitmap::Config config, SkAlphaType alphaType, |
| 270 this->freePixels(); | 271 SkAlphaType* canonical) { |
| 272 switch (config) { | |
| 273 case SkBitmap::kNo_Config: | |
| 274 alphaType = kIgnore_SkAlphaType; | |
| 275 break; | |
| 276 case SkBitmap::kA1_Config: | |
| 277 case SkBitmap::kA8_Config: | |
| 278 if (kUnpremul_SkAlphaType == alphaType) { | |
| 279 alphaType = kPremul_SkAlphaType; | |
|
scroggo
2014/06/10 20:11:59
Looking back at this as I write tests for Android.
| |
| 280 } | |
| 281 // fall-through | |
| 282 case SkBitmap::kIndex8_Config: | |
| 283 case SkBitmap::kARGB_4444_Config: | |
| 284 case SkBitmap::kARGB_8888_Config: | |
| 285 if (kIgnore_SkAlphaType == alphaType) { | |
| 286 return false; | |
| 287 } | |
| 288 break; | |
| 289 case SkBitmap::kRGB_565_Config: | |
| 290 alphaType = kOpaque_SkAlphaType; | |
| 291 break; | |
| 292 } | |
| 293 if (canonical) { | |
| 294 *canonical = alphaType; | |
| 295 } | |
| 296 return true; | |
| 297 } | |
| 271 | 298 |
| 299 bool SkBitmap::setConfig(Config config, int width, int height, size_t rowBytes, | |
| 300 SkAlphaType alphaType) { | |
| 272 if ((width | height) < 0) { | 301 if ((width | height) < 0) { |
| 273 goto err; | 302 goto ERROR; |
| 274 } | 303 } |
| 275 | |
| 276 if (rowBytes == 0) { | 304 if (rowBytes == 0) { |
| 277 rowBytes = SkBitmap::ComputeRowBytes(c, width); | 305 rowBytes = SkBitmap::ComputeRowBytes(config, width); |
| 278 if (0 == rowBytes && kNo_Config != c) { | 306 if (0 == rowBytes && kNo_Config != config) { |
| 279 goto err; | 307 goto ERROR; |
| 280 } | 308 } |
| 281 } | 309 } |
| 282 | 310 |
| 283 fConfig = SkToU8(c); | 311 if (!validate_alphaType(config, alphaType, &alphaType)) { |
| 312 goto ERROR; | |
| 313 } | |
| 314 | |
| 315 this->freePixels(); | |
| 316 | |
| 317 fConfig = SkToU8(config); | |
| 318 fAlphaType = SkToU8(alphaType); | |
| 284 fWidth = width; | 319 fWidth = width; |
| 285 fHeight = height; | 320 fHeight = height; |
| 286 fRowBytes = SkToU32(rowBytes); | 321 fRowBytes = SkToU32(rowBytes); |
| 287 | 322 |
| 288 fBytesPerPixel = (uint8_t)ComputeBytesPerPixel(c); | 323 fBytesPerPixel = (uint8_t)ComputeBytesPerPixel(config); |
| 289 | 324 |
| 290 SkDEBUGCODE(this->validate();) | 325 SkDEBUGCODE(this->validate();) |
| 291 return; | 326 return true; |
| 292 | 327 |
| 293 // if we got here, we had an error, so we reset the bitmap to empty | 328 // if we got here, we had an error, so we reset the bitmap to empty |
| 294 err: | 329 ERROR: |
| 295 this->reset(); | 330 this->reset(); |
| 331 return false; | |
| 332 } | |
| 333 | |
| 334 bool SkBitmap::setAlphaType(SkAlphaType alphaType) { | |
| 335 if (!validate_alphaType(this->config(), alphaType, &alphaType)) { | |
| 336 return false; | |
| 337 } | |
| 338 fAlphaType = SkToU8(alphaType); | |
| 339 return true; | |
| 296 } | 340 } |
| 297 | 341 |
| 298 void SkBitmap::updatePixelsFromRef() const { | 342 void SkBitmap::updatePixelsFromRef() const { |
| 299 if (NULL != fPixelRef) { | 343 if (NULL != fPixelRef) { |
| 300 if (fPixelLockCount > 0) { | 344 if (fPixelLockCount > 0) { |
| 301 SkASSERT(fPixelRef->isLocked()); | 345 SkASSERT(fPixelRef->isLocked()); |
| 302 | 346 |
| 303 void* p = fPixelRef->pixels(); | 347 void* p = fPixelRef->pixels(); |
| 304 if (NULL != p) { | 348 if (NULL != p) { |
| 305 p = (char*)p + fPixelRefOffset; | 349 p = (char*)p + fPixelRefOffset; |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 517 } | 561 } |
| 518 | 562 |
| 519 void SkBitmap::setImmutable() { | 563 void SkBitmap::setImmutable() { |
| 520 if (fPixelRef) { | 564 if (fPixelRef) { |
| 521 fPixelRef->setImmutable(); | 565 fPixelRef->setImmutable(); |
| 522 } else { | 566 } else { |
| 523 fFlags |= kImageIsImmutable_Flag; | 567 fFlags |= kImageIsImmutable_Flag; |
| 524 } | 568 } |
| 525 } | 569 } |
| 526 | 570 |
| 527 bool SkBitmap::isOpaque() const { | |
| 528 switch (fConfig) { | |
| 529 case kNo_Config: | |
| 530 return true; | |
| 531 | |
| 532 case kA1_Config: | |
| 533 case kA8_Config: | |
| 534 case kARGB_4444_Config: | |
| 535 case kARGB_8888_Config: | |
| 536 return (fFlags & kImageIsOpaque_Flag) != 0; | |
| 537 | |
| 538 case kIndex8_Config: { | |
| 539 bool isOpaque; | |
| 540 | |
| 541 this->lockPixels(); | |
| 542 isOpaque = fColorTable && fColorTable->isOpaque(); | |
| 543 this->unlockPixels(); | |
| 544 return isOpaque; | |
| 545 } | |
| 546 | |
| 547 case kRGB_565_Config: | |
| 548 return true; | |
| 549 | |
| 550 default: | |
| 551 SkDEBUGFAIL("unknown bitmap config pased to isOpaque"); | |
| 552 return false; | |
| 553 } | |
| 554 } | |
| 555 | |
| 556 void SkBitmap::setIsOpaque(bool isOpaque) { | |
| 557 /* we record this regardless of fConfig, though it is ignored in | |
| 558 isOpaque() for configs that can't support per-pixel alpha. | |
| 559 */ | |
| 560 if (isOpaque) { | |
| 561 fFlags |= kImageIsOpaque_Flag; | |
| 562 } else { | |
| 563 fFlags &= ~kImageIsOpaque_Flag; | |
| 564 } | |
| 565 } | |
| 566 | |
| 567 bool SkBitmap::isVolatile() const { | 571 bool SkBitmap::isVolatile() const { |
| 568 return (fFlags & kImageIsVolatile_Flag) != 0; | 572 return (fFlags & kImageIsVolatile_Flag) != 0; |
| 569 } | 573 } |
| 570 | 574 |
| 571 void SkBitmap::setIsVolatile(bool isVolatile) { | 575 void SkBitmap::setIsVolatile(bool isVolatile) { |
| 572 if (isVolatile) { | 576 if (isVolatile) { |
| 573 fFlags |= kImageIsVolatile_Flag; | 577 fFlags |= kImageIsVolatile_Flag; |
| 574 } else { | 578 } else { |
| 575 fFlags &= ~kImageIsVolatile_Flag; | 579 fFlags &= ~kImageIsVolatile_Flag; |
| 576 } | 580 } |
| (...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 951 srcRect.set(0, 0, this->width(), this->height()); | 955 srcRect.set(0, 0, this->width(), this->height()); |
| 952 if (!r.intersect(srcRect, subset)) { | 956 if (!r.intersect(srcRect, subset)) { |
| 953 return false; // r is empty (i.e. no intersection) | 957 return false; // r is empty (i.e. no intersection) |
| 954 } | 958 } |
| 955 | 959 |
| 956 if (fPixelRef->getTexture() != NULL) { | 960 if (fPixelRef->getTexture() != NULL) { |
| 957 // Do a deep copy | 961 // Do a deep copy |
| 958 SkPixelRef* pixelRef = fPixelRef->deepCopy(this->config(), &subset); | 962 SkPixelRef* pixelRef = fPixelRef->deepCopy(this->config(), &subset); |
| 959 if (pixelRef != NULL) { | 963 if (pixelRef != NULL) { |
| 960 SkBitmap dst; | 964 SkBitmap dst; |
| 961 dst.setConfig(this->config(), subset.width(), subset.height()); | 965 dst.setConfig(this->config(), subset.width(), subset.height(), 0, |
| 966 this->alphaType()); | |
| 962 dst.setIsVolatile(this->isVolatile()); | 967 dst.setIsVolatile(this->isVolatile()); |
| 963 dst.setIsOpaque(this->isOpaque()); | |
| 964 dst.setPixelRef(pixelRef)->unref(); | 968 dst.setPixelRef(pixelRef)->unref(); |
| 965 SkDEBUGCODE(dst.validate()); | 969 SkDEBUGCODE(dst.validate()); |
| 966 result->swap(dst); | 970 result->swap(dst); |
| 967 return true; | 971 return true; |
| 968 } | 972 } |
| 969 } | 973 } |
| 970 | 974 |
| 971 // If the upper left of the rectangle was outside the bounds of this SkBitma p, we should have | 975 // If the upper left of the rectangle was outside the bounds of this SkBitma p, we should have |
| 972 // exited above. | 976 // exited above. |
| 973 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width( ))); | 977 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width( ))); |
| 974 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height( ))); | 978 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height( ))); |
| 975 | 979 |
| 976 size_t offset = get_sub_offset(*this, r.fLeft, r.fTop); | 980 size_t offset = get_sub_offset(*this, r.fLeft, r.fTop); |
| 977 if (SUB_OFFSET_FAILURE == offset) { | 981 if (SUB_OFFSET_FAILURE == offset) { |
| 978 return false; // config not supported | 982 return false; // config not supported |
| 979 } | 983 } |
| 980 | 984 |
| 981 SkBitmap dst; | 985 SkBitmap dst; |
| 982 dst.setConfig(this->config(), r.width(), r.height(), this->rowBytes()); | 986 dst.setConfig(this->config(), r.width(), r.height(), this->rowBytes(), |
| 987 this->alphaType()); | |
| 983 dst.setIsVolatile(this->isVolatile()); | 988 dst.setIsVolatile(this->isVolatile()); |
| 984 dst.setIsOpaque(this->isOpaque()); | |
| 985 | 989 |
| 986 if (fPixelRef) { | 990 if (fPixelRef) { |
| 987 // share the pixelref with a custom offset | 991 // share the pixelref with a custom offset |
| 988 dst.setPixelRef(fPixelRef, fPixelRefOffset + offset); | 992 dst.setPixelRef(fPixelRef, fPixelRefOffset + offset); |
| 989 } | 993 } |
| 990 SkDEBUGCODE(dst.validate();) | 994 SkDEBUGCODE(dst.validate();) |
| 991 | 995 |
| 992 // we know we're good, so commit to result | 996 // we know we're good, so commit to result |
| 993 result->swap(dst); | 997 result->swap(dst); |
| 994 return true; | 998 return true; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1063 } | 1067 } |
| 1064 } | 1068 } |
| 1065 | 1069 |
| 1066 // we lock this now, since we may need its colortable | 1070 // we lock this now, since we may need its colortable |
| 1067 SkAutoLockPixels srclock(*src); | 1071 SkAutoLockPixels srclock(*src); |
| 1068 if (!src->readyToDraw()) { | 1072 if (!src->readyToDraw()) { |
| 1069 return false; | 1073 return false; |
| 1070 } | 1074 } |
| 1071 | 1075 |
| 1072 SkBitmap tmpDst; | 1076 SkBitmap tmpDst; |
| 1073 tmpDst.setConfig(dstConfig, src->width(), src->height()); | 1077 tmpDst.setConfig(dstConfig, src->width(), src->height(), 0, |
| 1078 src->alphaType()); | |
| 1074 | 1079 |
| 1075 // allocate colortable if srcConfig == kIndex8_Config | 1080 // allocate colortable if srcConfig == kIndex8_Config |
| 1076 SkColorTable* ctable = (dstConfig == kIndex8_Config) ? | 1081 SkColorTable* ctable = (dstConfig == kIndex8_Config) ? |
| 1077 new SkColorTable(*src->getColorTable()) : NULL; | 1082 new SkColorTable(*src->getColorTable()) : NULL; |
| 1078 SkAutoUnref au(ctable); | 1083 SkAutoUnref au(ctable); |
| 1079 if (!tmpDst.allocPixels(alloc, ctable)) { | 1084 if (!tmpDst.allocPixels(alloc, ctable)) { |
| 1080 return false; | 1085 return false; |
| 1081 } | 1086 } |
| 1082 | 1087 |
| 1083 if (!tmpDst.readyToDraw()) { | 1088 if (!tmpDst.readyToDraw()) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1123 // TODO: switch the allocation of tmpDst to call sk_calloc_throw | 1128 // TODO: switch the allocation of tmpDst to call sk_calloc_throw |
| 1124 tmpDst.eraseColor(SK_ColorTRANSPARENT); | 1129 tmpDst.eraseColor(SK_ColorTRANSPARENT); |
| 1125 | 1130 |
| 1126 SkCanvas canvas(tmpDst); | 1131 SkCanvas canvas(tmpDst); |
| 1127 SkPaint paint; | 1132 SkPaint paint; |
| 1128 | 1133 |
| 1129 paint.setDither(true); | 1134 paint.setDither(true); |
| 1130 canvas.drawBitmap(*src, 0, 0, &paint); | 1135 canvas.drawBitmap(*src, 0, 0, &paint); |
| 1131 } | 1136 } |
| 1132 | 1137 |
| 1133 tmpDst.setIsOpaque(src->isOpaque()); | |
| 1134 | |
| 1135 dst->swap(tmpDst); | 1138 dst->swap(tmpDst); |
| 1136 return true; | 1139 return true; |
| 1137 } | 1140 } |
| 1138 | 1141 |
| 1139 bool SkBitmap::deepCopyTo(SkBitmap* dst, Config dstConfig) const { | 1142 bool SkBitmap::deepCopyTo(SkBitmap* dst, Config dstConfig) const { |
| 1140 if (!this->canCopyTo(dstConfig)) { | 1143 if (!this->canCopyTo(dstConfig)) { |
| 1141 return false; | 1144 return false; |
| 1142 } | 1145 } |
| 1143 | 1146 |
| 1144 // If we have a PixelRef, and it supports deep copy, use it. | 1147 // If we have a PixelRef, and it supports deep copy, use it. |
| (...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1572 enum { | 1575 enum { |
| 1573 SERIALIZE_PIXELTYPE_NONE, | 1576 SERIALIZE_PIXELTYPE_NONE, |
| 1574 SERIALIZE_PIXELTYPE_REF_DATA | 1577 SERIALIZE_PIXELTYPE_REF_DATA |
| 1575 }; | 1578 }; |
| 1576 | 1579 |
| 1577 void SkBitmap::flatten(SkFlattenableWriteBuffer& buffer) const { | 1580 void SkBitmap::flatten(SkFlattenableWriteBuffer& buffer) const { |
| 1578 buffer.writeInt(fWidth); | 1581 buffer.writeInt(fWidth); |
| 1579 buffer.writeInt(fHeight); | 1582 buffer.writeInt(fHeight); |
| 1580 buffer.writeInt(fRowBytes); | 1583 buffer.writeInt(fRowBytes); |
| 1581 buffer.writeInt(fConfig); | 1584 buffer.writeInt(fConfig); |
| 1582 buffer.writeBool(this->isOpaque()); | 1585 buffer.writeInt(fAlphaType); |
| 1583 | 1586 |
| 1584 if (fPixelRef) { | 1587 if (fPixelRef) { |
| 1585 if (fPixelRef->getFactory()) { | 1588 if (fPixelRef->getFactory()) { |
| 1586 buffer.writeInt(SERIALIZE_PIXELTYPE_REF_DATA); | 1589 buffer.writeInt(SERIALIZE_PIXELTYPE_REF_DATA); |
| 1587 buffer.writeUInt(SkToU32(fPixelRefOffset)); | 1590 buffer.writeUInt(SkToU32(fPixelRefOffset)); |
| 1588 buffer.writeFlattenable(fPixelRef); | 1591 buffer.writeFlattenable(fPixelRef); |
| 1589 return; | 1592 return; |
| 1590 } | 1593 } |
| 1591 // if we get here, we can't record the pixels | 1594 // if we get here, we can't record the pixels |
| 1592 buffer.writeInt(SERIALIZE_PIXELTYPE_NONE); | 1595 buffer.writeInt(SERIALIZE_PIXELTYPE_NONE); |
| 1593 } else { | 1596 } else { |
| 1594 buffer.writeInt(SERIALIZE_PIXELTYPE_NONE); | 1597 buffer.writeInt(SERIALIZE_PIXELTYPE_NONE); |
| 1595 } | 1598 } |
| 1596 } | 1599 } |
| 1597 | 1600 |
| 1598 void SkBitmap::unflatten(SkFlattenableReadBuffer& buffer) { | 1601 void SkBitmap::unflatten(SkFlattenableReadBuffer& buffer) { |
| 1599 this->reset(); | 1602 this->reset(); |
| 1600 | 1603 |
| 1601 int width = buffer.readInt(); | 1604 int width = buffer.readInt(); |
| 1602 int height = buffer.readInt(); | 1605 int height = buffer.readInt(); |
| 1603 int rowBytes = buffer.readInt(); | 1606 int rowBytes = buffer.readInt(); |
| 1604 int config = buffer.readInt(); | 1607 int config = buffer.readInt(); |
| 1608 int alphaType = buffer.readInt(); | |
| 1605 | 1609 |
| 1606 this->setConfig((Config)config, width, height, rowBytes); | 1610 this->setConfig((Config)config, width, height, rowBytes, (SkAlphaType)alphaT ype); |
| 1607 this->setIsOpaque(buffer.readBool()); | |
| 1608 | 1611 |
| 1609 int reftype = buffer.readInt(); | 1612 int reftype = buffer.readInt(); |
| 1610 switch (reftype) { | 1613 switch (reftype) { |
| 1611 case SERIALIZE_PIXELTYPE_REF_DATA: { | 1614 case SERIALIZE_PIXELTYPE_REF_DATA: { |
| 1612 size_t offset = buffer.readUInt(); | 1615 size_t offset = buffer.readUInt(); |
| 1613 SkPixelRef* pr = buffer.readPixelRef(); | 1616 SkPixelRef* pr = buffer.readPixelRef(); |
| 1614 SkSafeUnref(this->setPixelRef(pr, offset)); | 1617 SkSafeUnref(this->setPixelRef(pr, offset)); |
| 1615 break; | 1618 break; |
| 1616 } | 1619 } |
| 1617 case SERIALIZE_PIXELTYPE_NONE: | 1620 case SERIALIZE_PIXELTYPE_NONE: |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1693 if (NULL != uri) { | 1696 if (NULL != uri) { |
| 1694 str->appendf(" uri:\"%s\"", uri); | 1697 str->appendf(" uri:\"%s\"", uri); |
| 1695 } else { | 1698 } else { |
| 1696 str->appendf(" pixelref:%p", pr); | 1699 str->appendf(" pixelref:%p", pr); |
| 1697 } | 1700 } |
| 1698 } | 1701 } |
| 1699 | 1702 |
| 1700 str->append(")"); | 1703 str->append(")"); |
| 1701 } | 1704 } |
| 1702 #endif | 1705 #endif |
| OLD | NEW |