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