SkBitmapController.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /*
  2. * Copyright 2015 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "include/core/SkBitmap.h"
  8. #include "include/core/SkMatrix.h"
  9. #include "include/private/SkTemplates.h"
  10. #include "src/core/SkArenaAlloc.h"
  11. #include "src/core/SkBitmapCache.h"
  12. #include "src/core/SkBitmapController.h"
  13. #include "src/core/SkBitmapProvider.h"
  14. #include "src/core/SkMipMap.h"
  15. ///////////////////////////////////////////////////////////////////////////////////////////////////
  16. SkBitmapController::State* SkBitmapController::RequestBitmap(const SkBitmapProvider& provider,
  17. const SkMatrix& inv,
  18. SkFilterQuality quality,
  19. SkArenaAlloc* alloc) {
  20. auto* state = alloc->make<SkBitmapController::State>(provider, inv, quality);
  21. return state->pixmap().addr() ? state : nullptr;
  22. }
  23. bool SkBitmapController::State::processHighRequest(const SkBitmapProvider& provider) {
  24. if (fQuality != kHigh_SkFilterQuality) {
  25. return false;
  26. }
  27. fQuality = kMedium_SkFilterQuality;
  28. SkScalar invScaleX = fInvMatrix.getScaleX();
  29. SkScalar invScaleY = fInvMatrix.getScaleY();
  30. if (fInvMatrix.getType() & SkMatrix::kAffine_Mask) {
  31. SkSize scale;
  32. if (!fInvMatrix.decomposeScale(&scale)) {
  33. return false;
  34. }
  35. invScaleX = scale.width();
  36. invScaleY = scale.height();
  37. }
  38. invScaleX = SkScalarAbs(invScaleX);
  39. invScaleY = SkScalarAbs(invScaleY);
  40. if (invScaleX >= 1 - SK_ScalarNearlyZero || invScaleY >= 1 - SK_ScalarNearlyZero) {
  41. // we're down-scaling so abort HQ
  42. return false;
  43. }
  44. // Confirmed that we can use HQ (w/ rasterpipeline)
  45. fQuality = kHigh_SkFilterQuality;
  46. (void)provider.asBitmap(&fResultBitmap);
  47. return true;
  48. }
  49. /*
  50. * Modulo internal errors, this should always succeed *if* the matrix is downscaling
  51. * (in this case, we have the inverse, so it succeeds if fInvMatrix is upscaling)
  52. */
  53. bool SkBitmapController::State::processMediumRequest(const SkBitmapProvider& provider) {
  54. SkASSERT(fQuality <= kMedium_SkFilterQuality);
  55. if (fQuality != kMedium_SkFilterQuality) {
  56. return false;
  57. }
  58. // Our default return state is to downgrade the request to Low, w/ or w/o setting fBitmap
  59. // to a valid bitmap.
  60. fQuality = kLow_SkFilterQuality;
  61. SkSize invScaleSize;
  62. if (!fInvMatrix.decomposeScale(&invScaleSize, nullptr)) {
  63. return false;
  64. }
  65. if (invScaleSize.width() > SK_Scalar1 || invScaleSize.height() > SK_Scalar1) {
  66. fCurrMip.reset(SkMipMapCache::FindAndRef(provider.makeCacheDesc()));
  67. if (nullptr == fCurrMip.get()) {
  68. fCurrMip.reset(SkMipMapCache::AddAndRef(provider));
  69. if (nullptr == fCurrMip.get()) {
  70. return false;
  71. }
  72. }
  73. // diagnostic for a crasher...
  74. SkASSERT_RELEASE(fCurrMip->data());
  75. const SkSize scale = SkSize::Make(SkScalarInvert(invScaleSize.width()),
  76. SkScalarInvert(invScaleSize.height()));
  77. SkMipMap::Level level;
  78. if (fCurrMip->extractLevel(scale, &level)) {
  79. const SkSize& invScaleFixup = level.fScale;
  80. fInvMatrix.postScale(invScaleFixup.width(), invScaleFixup.height());
  81. // todo: if we could wrap the fCurrMip in a pixelref, then we could just install
  82. // that here, and not need to explicitly track it ourselves.
  83. return fResultBitmap.installPixels(level.fPixmap);
  84. } else {
  85. // failed to extract, so release the mipmap
  86. fCurrMip.reset(nullptr);
  87. }
  88. }
  89. return false;
  90. }
  91. SkBitmapController::State::State(const SkBitmapProvider& provider,
  92. const SkMatrix& inv,
  93. SkFilterQuality qual) {
  94. fInvMatrix = inv;
  95. fQuality = qual;
  96. if (this->processHighRequest(provider) || this->processMediumRequest(provider)) {
  97. SkASSERT(fResultBitmap.getPixels());
  98. } else {
  99. (void)provider.asBitmap(&fResultBitmap);
  100. }
  101. // fResultBitmap.getPixels() may be null, but our caller knows to check fPixmap.addr()
  102. // and will destroy us if it is nullptr.
  103. fPixmap.reset(fResultBitmap.info(), fResultBitmap.getPixels(), fResultBitmap.rowBytes());
  104. }