LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkPictureShader.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 144 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 22 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2014 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 "SkPictureShader.h"
       9             : 
      10             : #include "SkArenaAlloc.h"
      11             : #include "SkBitmap.h"
      12             : #include "SkBitmapProcShader.h"
      13             : #include "SkCanvas.h"
      14             : #include "SkImage.h"
      15             : #include "SkImageShader.h"
      16             : #include "SkMatrixUtils.h"
      17             : #include "SkPicture.h"
      18             : #include "SkPictureImageGenerator.h"
      19             : #include "SkReadBuffer.h"
      20             : #include "SkResourceCache.h"
      21             : 
      22             : #if SK_SUPPORT_GPU
      23             : #include "GrContext.h"
      24             : #include "GrCaps.h"
      25             : #include "GrFragmentProcessor.h"
      26             : #endif
      27             : 
      28             : namespace {
      29             : static unsigned gBitmapSkaderKeyNamespaceLabel;
      30             : 
      31             : struct BitmapShaderKey : public SkResourceCache::Key {
      32             : public:
      33           0 :     BitmapShaderKey(uint32_t pictureID,
      34             :                     const SkRect& tile,
      35             :                     SkShader::TileMode tmx,
      36             :                     SkShader::TileMode tmy,
      37             :                     const SkSize& scale,
      38             :                     const SkMatrix& localMatrix)
      39           0 :         : fPictureID(pictureID)
      40             :         , fTile(tile)
      41             :         , fTmx(tmx)
      42             :         , fTmy(tmy)
      43           0 :         , fScale(scale) {
      44             : 
      45           0 :         for (int i = 0; i < 9; ++i) {
      46           0 :             fLocalMatrixStorage[i] = localMatrix[i];
      47             :         }
      48             : 
      49             :         static const size_t keySize = sizeof(fPictureID) +
      50             :                                       sizeof(fTile) +
      51             :                                       sizeof(fTmx) + sizeof(fTmy) +
      52             :                                       sizeof(fScale) +
      53             :                                       sizeof(fLocalMatrixStorage);
      54             :         // This better be packed.
      55             :         SkASSERT(sizeof(uint32_t) * (&fEndOfStruct - &fPictureID) == keySize);
      56           0 :         this->init(&gBitmapSkaderKeyNamespaceLabel, 0, keySize);
      57           0 :     }
      58             : 
      59             : private:
      60             :     uint32_t           fPictureID;
      61             :     SkRect             fTile;
      62             :     SkShader::TileMode fTmx, fTmy;
      63             :     SkSize             fScale;
      64             :     SkScalar           fLocalMatrixStorage[9];
      65             : 
      66             :     SkDEBUGCODE(uint32_t fEndOfStruct;)
      67             : };
      68             : 
      69           0 : struct BitmapShaderRec : public SkResourceCache::Rec {
      70           0 :     BitmapShaderRec(const BitmapShaderKey& key, SkShader* tileShader)
      71           0 :         : fKey(key)
      72           0 :         , fShader(SkRef(tileShader)) {}
      73             : 
      74             :     BitmapShaderKey fKey;
      75             :     sk_sp<SkShader> fShader;
      76             :     size_t          fBitmapBytes;
      77             : 
      78           0 :     const Key& getKey() const override { return fKey; }
      79           0 :     size_t bytesUsed() const override {
      80             :         // Just the record overhead -- the actual pixels are accounted by SkImageCacherator.
      81           0 :         return sizeof(fKey) + sizeof(SkImageShader);
      82             :     }
      83           0 :     const char* getCategory() const override { return "bitmap-shader"; }
      84           0 :     SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return nullptr; }
      85             : 
      86           0 :     static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextShader) {
      87           0 :         const BitmapShaderRec& rec = static_cast<const BitmapShaderRec&>(baseRec);
      88           0 :         sk_sp<SkShader>* result = reinterpret_cast<sk_sp<SkShader>*>(contextShader);
      89             : 
      90           0 :         *result = rec.fShader;
      91             : 
      92             :         // The bitmap shader is backed by an image generator, thus it can always re-generate its
      93             :         // pixels if discarded.
      94           0 :         return true;
      95             :     }
      96             : };
      97             : 
      98             : } // namespace
      99             : 
     100           0 : SkPictureShader::SkPictureShader(sk_sp<SkPicture> picture, TileMode tmx, TileMode tmy,
     101           0 :                                  const SkMatrix* localMatrix, const SkRect* tile)
     102             :     : INHERITED(localMatrix)
     103           0 :     , fPicture(std::move(picture))
     104           0 :     , fTile(tile ? *tile : fPicture->cullRect())
     105             :     , fTmx(tmx)
     106           0 :     , fTmy(tmy) {
     107           0 : }
     108             : 
     109           0 : sk_sp<SkShader> SkPictureShader::Make(sk_sp<SkPicture> picture, TileMode tmx, TileMode tmy,
     110             :                                       const SkMatrix* localMatrix, const SkRect* tile) {
     111           0 :     if (!picture || picture->cullRect().isEmpty() || (tile && tile->isEmpty())) {
     112           0 :         return SkShader::MakeEmptyShader();
     113             :     }
     114           0 :     return sk_sp<SkShader>(new SkPictureShader(std::move(picture), tmx, tmy, localMatrix, tile));
     115             : }
     116             : 
     117           0 : sk_sp<SkFlattenable> SkPictureShader::CreateProc(SkReadBuffer& buffer) {
     118             :     SkMatrix lm;
     119           0 :     buffer.readMatrix(&lm);
     120           0 :     TileMode mx = (TileMode)buffer.read32();
     121           0 :     TileMode my = (TileMode)buffer.read32();
     122             :     SkRect tile;
     123           0 :     buffer.readRect(&tile);
     124             : 
     125           0 :     sk_sp<SkPicture> picture;
     126             : 
     127           0 :     if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
     128           0 :         if (buffer.isVersionLT(SkReadBuffer::kPictureShaderHasPictureBool_Version)) {
     129             :             // Older code blindly serialized pictures.  We don't trust them.
     130           0 :             buffer.validate(false);
     131           0 :             return nullptr;
     132             :         }
     133             :         // Newer code won't serialize pictures in disallow-cross-process-picture mode.
     134             :         // Assert that they didn't serialize anything except a false here.
     135           0 :         buffer.validate(!buffer.readBool());
     136             :     } else {
     137             :         // Old code always serialized the picture.  New code writes a 'true' first if it did.
     138           0 :         if (buffer.isVersionLT(SkReadBuffer::kPictureShaderHasPictureBool_Version) ||
     139           0 :             buffer.readBool()) {
     140           0 :             picture = SkPicture::MakeFromBuffer(buffer);
     141             :         }
     142             :     }
     143           0 :     return SkPictureShader::Make(picture, mx, my, &lm, &tile);
     144             : }
     145             : 
     146           0 : void SkPictureShader::flatten(SkWriteBuffer& buffer) const {
     147           0 :     buffer.writeMatrix(this->getLocalMatrix());
     148           0 :     buffer.write32(fTmx);
     149           0 :     buffer.write32(fTmy);
     150           0 :     buffer.writeRect(fTile);
     151             : 
     152             :     // The deserialization code won't trust that our serialized picture is safe to deserialize.
     153             :     // So write a 'false' telling it that we're not serializing a picture.
     154           0 :     if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
     155           0 :         buffer.writeBool(false);
     156             :     } else {
     157           0 :         buffer.writeBool(true);
     158           0 :         fPicture->flatten(buffer);
     159             :     }
     160           0 : }
     161             : 
     162           0 : sk_sp<SkShader> SkPictureShader::refBitmapShader(const SkMatrix& viewMatrix, const SkMatrix* localM,
     163             :                                                  SkColorSpace* dstColorSpace,
     164             :                                                  const int maxTextureSize) const {
     165           0 :     SkASSERT(fPicture && !fPicture->cullRect().isEmpty());
     166             : 
     167             :     SkMatrix m;
     168           0 :     m.setConcat(viewMatrix, this->getLocalMatrix());
     169           0 :     if (localM) {
     170           0 :         m.preConcat(*localM);
     171             :     }
     172             : 
     173             :     // Use a rotation-invariant scale
     174             :     SkPoint scale;
     175             :     //
     176             :     // TODO: replace this with decomposeScale() -- but beware LayoutTest rebaselines!
     177             :     //
     178           0 :     if (!SkDecomposeUpper2x2(m, nullptr, &scale, nullptr)) {
     179             :         // Decomposition failed, use an approximation.
     180           0 :         scale.set(SkScalarSqrt(m.getScaleX() * m.getScaleX() + m.getSkewX() * m.getSkewX()),
     181           0 :                   SkScalarSqrt(m.getScaleY() * m.getScaleY() + m.getSkewY() * m.getSkewY()));
     182             :     }
     183           0 :     SkSize scaledSize = SkSize::Make(SkScalarAbs(scale.x() * fTile.width()),
     184           0 :                                      SkScalarAbs(scale.y() * fTile.height()));
     185             : 
     186             :     // Clamp the tile size to about 4M pixels
     187             :     static const SkScalar kMaxTileArea = 2048 * 2048;
     188           0 :     SkScalar tileArea = scaledSize.width() * scaledSize.height();
     189           0 :     if (tileArea > kMaxTileArea) {
     190           0 :         SkScalar clampScale = SkScalarSqrt(kMaxTileArea / tileArea);
     191           0 :         scaledSize.set(scaledSize.width() * clampScale,
     192           0 :                        scaledSize.height() * clampScale);
     193             :     }
     194             : #if SK_SUPPORT_GPU
     195             :     // Scale down the tile size if larger than maxTextureSize for GPU Path or it should fail on create texture
     196           0 :     if (maxTextureSize) {
     197           0 :         if (scaledSize.width() > maxTextureSize || scaledSize.height() > maxTextureSize) {
     198           0 :             SkScalar downScale = maxTextureSize / SkMaxScalar(scaledSize.width(), scaledSize.height());
     199           0 :             scaledSize.set(SkScalarFloorToScalar(scaledSize.width() * downScale),
     200           0 :                            SkScalarFloorToScalar(scaledSize.height() * downScale));
     201             :         }
     202             :     }
     203             : #endif
     204             : 
     205             : #ifdef SK_SUPPORT_LEGACY_PICTURESHADER_ROUNDING
     206             :     const SkISize tileSize = scaledSize.toRound();
     207             : #else
     208           0 :     const SkISize tileSize = scaledSize.toCeil();
     209             : #endif
     210           0 :     if (tileSize.isEmpty()) {
     211           0 :         return SkShader::MakeEmptyShader();
     212             :     }
     213             : 
     214             :     // The actual scale, compensating for rounding & clamping.
     215           0 :     const SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fTile.width(),
     216           0 :                                           SkIntToScalar(tileSize.height()) / fTile.height());
     217             : 
     218           0 :     sk_sp<SkShader> tileShader;
     219             :     BitmapShaderKey key(fPicture->uniqueID(),
     220             :                         fTile,
     221           0 :                         fTmx,
     222           0 :                         fTmy,
     223             :                         tileScale,
     224           0 :                         this->getLocalMatrix());
     225             : 
     226           0 :     if (!SkResourceCache::Find(key, BitmapShaderRec::Visitor, &tileShader)) {
     227             :         SkMatrix tileMatrix;
     228           0 :         tileMatrix.setRectToRect(fTile, SkRect::MakeIWH(tileSize.width(), tileSize.height()),
     229           0 :                                  SkMatrix::kFill_ScaleToFit);
     230             : 
     231             :         sk_sp<SkImage> tileImage = SkImage::MakeFromGenerator(
     232           0 :                 SkPictureImageGenerator::Make(tileSize, fPicture, &tileMatrix, nullptr,
     233           0 :                                               SkImage::BitDepth::kU8, sk_ref_sp(dstColorSpace)));
     234           0 :         if (!tileImage) {
     235           0 :             return nullptr;
     236             :         }
     237             : 
     238           0 :         SkMatrix shaderMatrix = this->getLocalMatrix();
     239           0 :         shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height());
     240           0 :         tileShader = tileImage->makeShader(fTmx, fTmy, &shaderMatrix);
     241             : 
     242           0 :         SkResourceCache::Add(new BitmapShaderRec(key, tileShader.get()));
     243             :     }
     244             : 
     245           0 :     return tileShader;
     246             : }
     247             : 
     248           0 : bool SkPictureShader::onAppendStages(SkRasterPipeline* p, SkColorSpace* cs, SkArenaAlloc* alloc,
     249             :                                      const SkMatrix& ctm, const SkPaint& paint,
     250             :                                      const SkMatrix* localMatrix) const {
     251             :     // Keep bitmapShader alive by using alloc instead of stack memory
     252           0 :     auto& bitmapShader = *alloc->make<sk_sp<SkShader>>();
     253           0 :     bitmapShader = this->refBitmapShader(ctm, localMatrix, cs);
     254           0 :     return bitmapShader && bitmapShader->appendStages(p, cs, alloc, ctm, paint);
     255             : }
     256             : 
     257             : /////////////////////////////////////////////////////////////////////////////////////////
     258           0 : SkShader::Context* SkPictureShader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc)
     259             : const {
     260           0 :     sk_sp<SkShader> bitmapShader(this->refBitmapShader(*rec.fMatrix, rec.fLocalMatrix,
     261           0 :                                                        rec.fDstColorSpace));
     262           0 :     if (!bitmapShader) {
     263           0 :         return nullptr;
     264             :     }
     265             : 
     266             :     PictureShaderContext* ctx =
     267           0 :         alloc->make<PictureShaderContext>(*this, rec, std::move(bitmapShader), alloc);
     268           0 :     if (nullptr == ctx->fBitmapShaderContext) {
     269           0 :         ctx = nullptr;
     270             :     }
     271           0 :     return ctx;
     272             : }
     273             : 
     274             : /////////////////////////////////////////////////////////////////////////////////////////
     275             : 
     276           0 : SkPictureShader::PictureShaderContext::PictureShaderContext(
     277             :         const SkPictureShader& shader, const ContextRec& rec, sk_sp<SkShader> bitmapShader,
     278           0 :         SkArenaAlloc* alloc)
     279             :     : INHERITED(shader, rec)
     280           0 :     , fBitmapShader(std::move(bitmapShader))
     281             : {
     282           0 :     fBitmapShaderContext = fBitmapShader->makeContext(rec, alloc);
     283             :     //if fBitmapShaderContext is null, we are invalid
     284           0 : }
     285             : 
     286           0 : uint32_t SkPictureShader::PictureShaderContext::getFlags() const {
     287           0 :     SkASSERT(fBitmapShaderContext);
     288           0 :     return fBitmapShaderContext->getFlags();
     289             : }
     290             : 
     291           0 : SkShader::Context::ShadeProc SkPictureShader::PictureShaderContext::asAShadeProc(void** ctx) {
     292           0 :     SkASSERT(fBitmapShaderContext);
     293           0 :     return fBitmapShaderContext->asAShadeProc(ctx);
     294             : }
     295             : 
     296           0 : void SkPictureShader::PictureShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
     297           0 :     SkASSERT(fBitmapShaderContext);
     298           0 :     fBitmapShaderContext->shadeSpan(x, y, dstC, count);
     299           0 : }
     300             : 
     301             : #ifndef SK_IGNORE_TO_STRING
     302           0 : void SkPictureShader::toString(SkString* str) const {
     303             :     static const char* gTileModeName[SkShader::kTileModeCount] = {
     304             :         "clamp", "repeat", "mirror"
     305             :     };
     306             : 
     307           0 :     str->appendf("PictureShader: [%f:%f:%f:%f] ",
     308           0 :                  fPicture->cullRect().fLeft,
     309           0 :                  fPicture->cullRect().fTop,
     310           0 :                  fPicture->cullRect().fRight,
     311           0 :                  fPicture->cullRect().fBottom);
     312             : 
     313           0 :     str->appendf("(%s, %s)", gTileModeName[fTmx], gTileModeName[fTmy]);
     314             : 
     315           0 :     this->INHERITED::toString(str);
     316           0 : }
     317             : #endif
     318             : 
     319             : #if SK_SUPPORT_GPU
     320           0 : sk_sp<GrFragmentProcessor> SkPictureShader::asFragmentProcessor(const AsFPArgs& args) const {
     321           0 :     int maxTextureSize = 0;
     322           0 :     if (args.fContext) {
     323           0 :         maxTextureSize = args.fContext->caps()->maxTextureSize();
     324             :     }
     325           0 :     sk_sp<SkShader> bitmapShader(this->refBitmapShader(*args.fViewMatrix, args.fLocalMatrix,
     326           0 :                                                        args.fDstColorSpace, maxTextureSize));
     327           0 :     if (!bitmapShader) {
     328           0 :         return nullptr;
     329             :     }
     330           0 :     return bitmapShader->asFragmentProcessor(SkShader::AsFPArgs(
     331           0 :         args.fContext, args.fViewMatrix, nullptr, args.fFilterQuality, args.fDstColorSpace));
     332             : }
     333             : #endif

Generated by: LCOV version 1.13