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

          Line data    Source code
       1             : /*
       2             :  * Copyright 2016 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 "Sk4fLinearGradient.h"
       9             : #include "Sk4x4f.h"
      10             : 
      11             : #include <cmath>
      12             : 
      13             : namespace {
      14             : 
      15             : template<DstType dstType, ApplyPremul premul>
      16           0 : void ramp(const Sk4f& c, const Sk4f& dc, typename DstTraits<dstType, premul>::Type dst[], int n) {
      17           0 :     SkASSERT(n > 0);
      18             : 
      19           0 :     const Sk4f dc2 = dc + dc;
      20           0 :     const Sk4f dc4 = dc2 + dc2;
      21             : 
      22           0 :     Sk4f c0 = c ;
      23           0 :     Sk4f c1 = c + dc;
      24           0 :     Sk4f c2 = c0 + dc2;
      25           0 :     Sk4f c3 = c1 + dc2;
      26             : 
      27           0 :     while (n >= 4) {
      28           0 :         DstTraits<dstType, premul>::store4x(c0, c1, c2, c3, dst);
      29           0 :         dst += 4;
      30             : 
      31           0 :         c0 = c0 + dc4;
      32           0 :         c1 = c1 + dc4;
      33           0 :         c2 = c2 + dc4;
      34           0 :         c3 = c3 + dc4;
      35           0 :         n -= 4;
      36             :     }
      37           0 :     if (n & 2) {
      38           0 :         DstTraits<dstType, premul>::store(c0, dst++);
      39           0 :         DstTraits<dstType, premul>::store(c1, dst++);
      40           0 :         c0 = c0 + dc2;
      41             :     }
      42           0 :     if (n & 1) {
      43           0 :         DstTraits<dstType, premul>::store(c0, dst);
      44             :     }
      45           0 : }
      46             : 
      47             : // Planar version of ramp (S32 no-premul only).
      48             : template<>
      49           0 : void ramp<DstType::S32, ApplyPremul::False>(const Sk4f& c, const Sk4f& dc, SkPMColor dst[], int n) {
      50           0 :     SkASSERT(n > 0);
      51             : 
      52           0 :     const Sk4f    dc4 = dc * 4;
      53           0 :     const Sk4x4f dc4x = { Sk4f(dc4[0]), Sk4f(dc4[1]), Sk4f(dc4[2]), Sk4f(dc4[3]) };
      54           0 :     Sk4x4f        c4x = Sk4x4f::Transpose(c, c + dc, c + dc * 2, c + dc * 3);
      55             : 
      56           0 :     while (n >= 4) {
      57           0 :         ( sk_linear_to_srgb(c4x.r) <<  0
      58           0 :         | sk_linear_to_srgb(c4x.g) <<  8
      59           0 :         | sk_linear_to_srgb(c4x.b) << 16
      60           0 :         | Sk4f_round(255.0f*c4x.a) << 24).store(dst);
      61             : 
      62             :         c4x.r += dc4x.r;
      63             :         c4x.g += dc4x.g;
      64             :         c4x.b += dc4x.b;
      65             :         c4x.a += dc4x.a;
      66             : 
      67           0 :         dst += 4;
      68           0 :         n   -= 4;
      69             :     }
      70             : 
      71           0 :     if (n & 2) {
      72             :         DstTraits<DstType::S32, ApplyPremul::False>
      73           0 :             ::store(Sk4f(c4x.r[0], c4x.g[0], c4x.b[0], c4x.a[0]), dst++);
      74             :         DstTraits<DstType::S32, ApplyPremul::False>
      75           0 :             ::store(Sk4f(c4x.r[1], c4x.g[1], c4x.b[1], c4x.a[1]), dst++);
      76             :     }
      77             : 
      78           0 :     if (n & 1) {
      79             :         DstTraits<DstType::S32, ApplyPremul::False>
      80           0 :             ::store(Sk4f(c4x.r[n & 2], c4x.g[n & 2], c4x.b[n & 2], c4x.a[n & 2]), dst);
      81             :     }
      82           0 : }
      83             : 
      84             : template<SkShader::TileMode>
      85             : SkScalar pinFx(SkScalar);
      86             : 
      87             : template<>
      88           0 : SkScalar pinFx<SkShader::kClamp_TileMode>(SkScalar fx) {
      89           0 :     return fx;
      90             : }
      91             : 
      92             : template<>
      93           0 : SkScalar pinFx<SkShader::kRepeat_TileMode>(SkScalar fx) {
      94           0 :     SkScalar f = SkScalarFraction(fx);
      95           0 :     if (f < 0) {
      96           0 :         f = SkTMin(f + 1, nextafterf(1, 0));
      97             :     }
      98           0 :     SkASSERT(f >= 0);
      99           0 :     SkASSERT(f < 1.0f);
     100           0 :     return f;
     101             : }
     102             : 
     103             : template<>
     104           0 : SkScalar pinFx<SkShader::kMirror_TileMode>(SkScalar fx) {
     105           0 :     SkScalar f = SkScalarMod(fx, 2.0f);
     106           0 :     if (f < 0) {
     107           0 :         f = SkTMin(f + 2, nextafterf(2, 0));
     108             :     }
     109           0 :     SkASSERT(f >= 0);
     110           0 :     SkASSERT(f < 2.0f);
     111           0 :     return f;
     112             : }
     113             : 
     114             : // true when x is in [k1,k2], or [k2, k1] when the interval is reversed.
     115             : // TODO(fmalita): hoist the reversed interval check out of this helper.
     116           0 : bool in_range(SkScalar x, SkScalar k1, SkScalar k2) {
     117           0 :     SkASSERT(k1 != k2);
     118             :     return (k1 < k2)
     119           0 :         ? (x >= k1 && x <= k2)
     120           0 :         : (x >= k2 && x <= k1);
     121             : }
     122             : 
     123             : } // anonymous namespace
     124             : 
     125           0 : SkLinearGradient::
     126             : LinearGradient4fContext::LinearGradient4fContext(const SkLinearGradient& shader,
     127           0 :                                                  const ContextRec& rec)
     128           0 :     : INHERITED(shader, rec) {
     129             : 
     130             :     // Our fast path expects interval points to be monotonically increasing in x.
     131           0 :     const bool reverseIntervals = this->isFast() && std::signbit(fDstToPos.getScaleX());
     132           0 :     fIntervals.init(shader.fOrigColors, shader.fOrigPos, shader.fColorCount, shader.fTileMode,
     133           0 :                     fColorsArePremul, rec.fPaint->getAlpha() * (1.0f / 255), reverseIntervals);
     134             : 
     135           0 :     SkASSERT(fIntervals->count() > 0);
     136           0 :     fCachedInterval = fIntervals->begin();
     137           0 : }
     138             : 
     139             : const Sk4fGradientInterval*
     140           0 : SkLinearGradient::LinearGradient4fContext::findInterval(SkScalar fx) const {
     141           0 :     SkASSERT(in_range(fx, fIntervals->front().fT0, fIntervals->back().fT1));
     142             : 
     143             :     if (1) {
     144             :         // Linear search, using the last scanline interval as a starting point.
     145           0 :         SkASSERT(fCachedInterval >= fIntervals->begin());
     146           0 :         SkASSERT(fCachedInterval < fIntervals->end());
     147           0 :         const int search_dir = fDstToPos.getScaleX() >= 0 ? 1 : -1;
     148           0 :         while (!in_range(fx, fCachedInterval->fT0, fCachedInterval->fT1)) {
     149           0 :             fCachedInterval += search_dir;
     150           0 :             if (fCachedInterval >= fIntervals->end()) {
     151           0 :                 fCachedInterval = fIntervals->begin();
     152           0 :             } else if (fCachedInterval < fIntervals->begin()) {
     153           0 :                 fCachedInterval = fIntervals->end() - 1;
     154             :             }
     155             :         }
     156           0 :         return fCachedInterval;
     157             :     } else {
     158             :         // Binary search.  Seems less effective than linear + caching.
     159             :         const auto* i0 = fIntervals->begin();
     160             :         const auto* i1 = fIntervals->end() - 1;
     161             : 
     162             :         while (i0 != i1) {
     163             :             SkASSERT(i0 < i1);
     164             :             SkASSERT(in_range(fx, i0->fT0, i1->fT1));
     165             : 
     166             :             const auto* i = i0 + ((i1 - i0) >> 1);
     167             : 
     168             :             if (in_range(fx, i0->fT0, i->fT1)) {
     169             :                 i1 = i;
     170             :             } else {
     171             :                 SkASSERT(in_range(fx, i->fT1, i1->fT1));
     172             :                 i0 = i + 1;
     173             :             }
     174             :         }
     175             : 
     176             :         SkASSERT(in_range(fx, i0->fT0, i0->fT1));
     177             :         return i0;
     178             :     }
     179             : }
     180             : 
     181           0 : void SkLinearGradient::
     182             : LinearGradient4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) {
     183           0 :     if (!this->isFast()) {
     184           0 :         this->INHERITED::shadeSpan(x, y, dst, count);
     185           0 :         return;
     186             :     }
     187             : 
     188             :     // TODO: plumb dithering
     189           0 :     SkASSERT(count > 0);
     190           0 :     if (fColorsArePremul) {
     191             :         this->shadePremulSpan<DstType::L32,
     192           0 :                               ApplyPremul::False>(x, y, dst, count);
     193             :     } else {
     194             :         this->shadePremulSpan<DstType::L32,
     195           0 :                               ApplyPremul::True>(x, y, dst, count);
     196             :     }
     197             : }
     198             : 
     199           0 : void SkLinearGradient::
     200             : LinearGradient4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) {
     201           0 :     if (!this->isFast()) {
     202           0 :         this->INHERITED::shadeSpan4f(x, y, dst, count);
     203           0 :         return;
     204             :     }
     205             : 
     206             :     // TONOTDO: plumb dithering
     207           0 :     SkASSERT(count > 0);
     208           0 :     if (fColorsArePremul) {
     209             :         this->shadePremulSpan<DstType::F32,
     210           0 :                               ApplyPremul::False>(x, y, dst, count);
     211             :     } else {
     212             :         this->shadePremulSpan<DstType::F32,
     213           0 :                               ApplyPremul::True>(x, y, dst, count);
     214             :     }
     215             : }
     216             : 
     217             : template<DstType dstType, ApplyPremul premul>
     218           0 : void SkLinearGradient::
     219             : LinearGradient4fContext::shadePremulSpan(int x, int y,
     220             :                                          typename DstTraits<dstType, premul>::Type dst[],
     221             :                                          int count) const {
     222             :     const SkLinearGradient& shader =
     223           0 :         static_cast<const SkLinearGradient&>(fShader);
     224           0 :     switch (shader.fTileMode) {
     225             :     case kClamp_TileMode:
     226           0 :         this->shadeSpanInternal<dstType,
     227             :                                 premul,
     228             :                                 kClamp_TileMode>(x, y, dst, count);
     229           0 :         break;
     230             :     case kRepeat_TileMode:
     231           0 :         this->shadeSpanInternal<dstType,
     232             :                                 premul,
     233             :                                 kRepeat_TileMode>(x, y, dst, count);
     234           0 :         break;
     235             :     case kMirror_TileMode:
     236           0 :         this->shadeSpanInternal<dstType,
     237             :                                 premul,
     238             :                                 kMirror_TileMode>(x, y, dst, count);
     239           0 :         break;
     240             :     }
     241           0 : }
     242             : 
     243             : template<DstType dstType, ApplyPremul premul, SkShader::TileMode tileMode>
     244           0 : void SkLinearGradient::
     245             : LinearGradient4fContext::shadeSpanInternal(int x, int y,
     246             :                                            typename DstTraits<dstType, premul>::Type dst[],
     247             :                                            int count) const {
     248             :     SkPoint pt;
     249           0 :     fDstToPosProc(fDstToPos,
     250             :                   x + SK_ScalarHalf,
     251             :                   y + SK_ScalarHalf,
     252             :                   &pt);
     253           0 :     const SkScalar fx = pinFx<tileMode>(pt.x());
     254           0 :     const SkScalar dx = fDstToPos.getScaleX();
     255           0 :     LinearIntervalProcessor<dstType, premul, tileMode> proc(fIntervals->begin(),
     256           0 :                                                             fIntervals->end() - 1,
     257             :                                                             this->findInterval(fx),
     258             :                                                             fx,
     259             :                                                             dx,
     260           0 :                                                             SkScalarNearlyZero(dx * count));
     261           0 :     while (count > 0) {
     262             :         // What we really want here is SkTPin(advance, 1, count)
     263             :         // but that's a significant perf hit for >> stops; investigate.
     264           0 :         const int n = SkScalarTruncToInt(
     265             :             SkTMin<SkScalar>(proc.currentAdvance() + 1, SkIntToScalar(count)));
     266             : 
     267             :         // The current interval advance can be +inf (e.g. when reaching
     268             :         // the clamp mode end intervals) - when that happens, we expect to
     269             :         //   a) consume all remaining count in one swoop
     270             :         //   b) return a zero color gradient
     271           0 :         SkASSERT(SkScalarIsFinite(proc.currentAdvance())
     272             :             || (n == count && proc.currentRampIsZero()));
     273             : 
     274           0 :         if (proc.currentRampIsZero()) {
     275           0 :             DstTraits<dstType, premul>::store(proc.currentColor(),
     276             :                                               dst, n);
     277             :         } else {
     278           0 :             ramp<dstType, premul>(proc.currentColor(),
     279             :                                   proc.currentColorGrad(),
     280             :                                   dst, n);
     281             :         }
     282             : 
     283           0 :         proc.advance(SkIntToScalar(n));
     284           0 :         count -= n;
     285           0 :         dst   += n;
     286             :     }
     287           0 : }
     288             : 
     289             : template<DstType dstType, ApplyPremul premul, SkShader::TileMode tileMode>
     290             : class SkLinearGradient::
     291             : LinearGradient4fContext::LinearIntervalProcessor {
     292             : public:
     293           0 :     LinearIntervalProcessor(const Sk4fGradientInterval* firstInterval,
     294             :                             const Sk4fGradientInterval* lastInterval,
     295             :                             const Sk4fGradientInterval* i,
     296             :                             SkScalar fx,
     297             :                             SkScalar dx,
     298             :                             bool is_vertical)
     299           0 :         : fAdvX(is_vertical ? SK_ScalarInfinity : (i->fT1 - fx) / dx)
     300             :         , fFirstInterval(firstInterval)
     301             :         , fLastInterval(lastInterval)
     302             :         , fInterval(i)
     303             :         , fDx(dx)
     304           0 :         , fIsVertical(is_vertical)
     305             :     {
     306           0 :         SkASSERT(fAdvX >= 0);
     307           0 :         SkASSERT(firstInterval <= lastInterval);
     308             : 
     309           0 :         if (tileMode != kClamp_TileMode && !is_vertical) {
     310           0 :             const auto spanX = (lastInterval->fT1 - firstInterval->fT0) / dx;
     311           0 :             SkASSERT(spanX >= 0);
     312             : 
     313             :             // If we're in a repeating tile mode and the whole gradient is compressed into a
     314             :             // fraction of a pixel, we just use the average color in zero-ramp mode.
     315             :             // This also avoids cases where we make no progress due to interval advances being
     316             :             // close to zero.
     317             :             static constexpr SkScalar kMinSpanX = .25f;
     318           0 :             if (spanX < kMinSpanX) {
     319           0 :                 this->init_average_props();
     320           0 :                 return;
     321             :             }
     322             :         }
     323             : 
     324           0 :         this->compute_interval_props(fx);
     325             :     }
     326             : 
     327           0 :     SkScalar currentAdvance() const {
     328           0 :         SkASSERT(fAdvX >= 0);
     329           0 :         SkASSERT(fAdvX <= (fInterval->fT1 - fInterval->fT0) / fDx || !std::isfinite(fAdvX));
     330           0 :         return fAdvX;
     331             :     }
     332             : 
     333           0 :     bool currentRampIsZero() const { return fZeroRamp; }
     334           0 :     const Sk4f& currentColor() const { return fCc; }
     335           0 :     const Sk4f& currentColorGrad() const { return fDcDx; }
     336             : 
     337           0 :     void advance(SkScalar advX) {
     338           0 :         SkASSERT(advX > 0);
     339           0 :         SkASSERT(fAdvX >= 0);
     340             : 
     341           0 :         if (advX >= fAdvX) {
     342           0 :             advX = this->advance_interval(advX);
     343             :         }
     344           0 :         SkASSERT(advX < fAdvX);
     345             : 
     346           0 :         fCc = fCc + fDcDx * Sk4f(advX);
     347           0 :         fAdvX -= advX;
     348           0 :     }
     349             : 
     350             : private:
     351           0 :     void compute_interval_props(SkScalar t) {
     352           0 :         SkASSERT(in_range(t, fInterval->fT0, fInterval->fT1));
     353             : 
     354           0 :         fZeroRamp     = fIsVertical || fInterval->fZeroRamp;
     355           0 :         fCc           = DstTraits<dstType, premul>::load(fInterval->fCb);
     356             : 
     357           0 :         if (fInterval->fZeroRamp) {
     358           0 :             fDcDx = 0;
     359             :         } else {
     360           0 :             const Sk4f dC = DstTraits<dstType, premul>::load(fInterval->fCg);
     361           0 :             fCc           = fCc + dC * Sk4f(t);
     362           0 :             fDcDx         = dC * fDx;
     363             :         }
     364           0 :     }
     365             : 
     366           0 :     void init_average_props() {
     367           0 :         fAdvX     = SK_ScalarInfinity;
     368           0 :         fZeroRamp = true;
     369           0 :         fDcDx     = 0;
     370           0 :         fCc       = Sk4f(0);
     371             : 
     372             :         // TODO: precompute the average at interval setup time?
     373           0 :         for (const auto* i = fFirstInterval; i <= fLastInterval; ++i) {
     374             :             // Each interval contributes its average color to the total/weighted average:
     375             :             //
     376             :             //   C = (c0 + c1) / 2 = (Cb + Cg * t0 + Cb + Cg * t1) / 2 = Cb + Cg *(t0 + t1) / 2
     377             :             //
     378             :             //   Avg += C * (t1 - t0)
     379             :             //
     380           0 :             auto c = DstTraits<dstType, premul>::load(i->fCb);
     381           0 :             if (!i->fZeroRamp) {
     382           0 :                 c = c + DstTraits<dstType, premul>::load(i->fCg) * (i->fT0 + i->fT1) * 0.5f;
     383             :             }
     384           0 :             fCc = fCc + c * (i->fT1 - i->fT0);
     385             :         }
     386           0 :     }
     387             : 
     388           0 :     const Sk4fGradientInterval* next_interval(const Sk4fGradientInterval* i) const {
     389           0 :         SkASSERT(i >= fFirstInterval);
     390           0 :         SkASSERT(i <= fLastInterval);
     391           0 :         i++;
     392             : 
     393             :         if (tileMode == kClamp_TileMode) {
     394           0 :             SkASSERT(i <= fLastInterval);
     395           0 :             return i;
     396             :         }
     397             : 
     398           0 :         return (i <= fLastInterval) ? i : fFirstInterval;
     399             :     }
     400             : 
     401           0 :     SkScalar advance_interval(SkScalar advX) {
     402           0 :         SkASSERT(advX >= fAdvX);
     403             : 
     404           0 :         do {
     405           0 :             advX -= fAdvX;
     406           0 :             fInterval = this->next_interval(fInterval);
     407           0 :             fAdvX = (fInterval->fT1 - fInterval->fT0) / fDx;
     408           0 :             SkASSERT(fAdvX > 0);
     409           0 :         } while (advX >= fAdvX);
     410             : 
     411           0 :         compute_interval_props(fInterval->fT0);
     412             : 
     413           0 :         SkASSERT(advX >= 0);
     414           0 :         return advX;
     415             :     }
     416             : 
     417             :     // Current interval properties.
     418             :     Sk4f            fDcDx;      // dst color gradient (dc/dx)
     419             :     Sk4f            fCc;        // current color, interpolated in dst
     420             :     SkScalar        fAdvX;      // remaining interval advance in dst
     421             :     bool            fZeroRamp;  // current interval color grad is 0
     422             : 
     423             :     const Sk4fGradientInterval* fFirstInterval;
     424             :     const Sk4fGradientInterval* fLastInterval;
     425             :     const Sk4fGradientInterval* fInterval;  // current interval
     426             :     const SkScalar              fDx;        // 'dx' for consistency with other impls; actually dt/dx
     427             :     const bool                  fIsVertical;
     428             : };
     429             : 
     430           0 : void SkLinearGradient::
     431             : LinearGradient4fContext::mapTs(int x, int y, SkScalar ts[], int count) const {
     432           0 :     SkASSERT(count > 0);
     433           0 :     SkASSERT(fDstToPosClass != kLinear_MatrixClass);
     434             : 
     435           0 :     SkScalar sx = x + SK_ScalarHalf;
     436           0 :     const SkScalar sy = y + SK_ScalarHalf;
     437             :     SkPoint pt;
     438             : 
     439           0 :     if (fDstToPosClass != kPerspective_MatrixClass) {
     440             :         // kLinear_MatrixClass, kFixedStepInX_MatrixClass => fixed dt per scanline
     441           0 :         const SkScalar dtdx = fDstToPos.fixedStepInX(sy).x();
     442           0 :         fDstToPosProc(fDstToPos, sx, sy, &pt);
     443             : 
     444           0 :         const Sk4f dtdx4 = Sk4f(4 * dtdx);
     445           0 :         Sk4f t4 = Sk4f(pt.x() + 0 * dtdx,
     446           0 :                        pt.x() + 1 * dtdx,
     447           0 :                        pt.x() + 2 * dtdx,
     448           0 :                        pt.x() + 3 * dtdx);
     449             : 
     450           0 :         while (count >= 4) {
     451             :             t4.store(ts);
     452           0 :             t4 = t4 + dtdx4;
     453           0 :             ts += 4;
     454           0 :             count -= 4;
     455             :         }
     456             : 
     457           0 :         if (count & 2) {
     458           0 :             *ts++ = t4[0];
     459           0 :             *ts++ = t4[1];
     460           0 :             t4 = SkNx_shuffle<2, 0, 1, 3>(t4);
     461             :         }
     462             : 
     463           0 :         if (count & 1) {
     464           0 :             *ts++ = t4[0];
     465             :         }
     466             :     } else {
     467           0 :         for (int i = 0; i < count; ++i) {
     468           0 :             fDstToPosProc(fDstToPos, sx, sy, &pt);
     469             :             // Perspective may yield NaN values.
     470             :             // Short of a better idea, drop to 0.
     471           0 :             ts[i] = SkScalarIsNaN(pt.x()) ? 0 : pt.x();
     472           0 :             sx += SK_Scalar1;
     473             :         }
     474             :     }
     475           0 : }
     476             : 
     477           0 : bool SkLinearGradient::LinearGradient4fContext::onChooseBlitProcs(const SkImageInfo& info,
     478             :                                                                   BlitState* state) {
     479           0 :     if (state->fMode != SkBlendMode::kSrc &&
     480           0 :         !(state->fMode == SkBlendMode::kSrcOver && (fFlags & kOpaqueAlpha_Flag))) {
     481           0 :         return false;
     482             :     }
     483             : 
     484           0 :     switch (info.colorType()) {
     485             :         case kN32_SkColorType:
     486           0 :             state->fBlitBW = D32_BlitBW;
     487           0 :             return true;
     488             :         case kRGBA_F16_SkColorType:
     489           0 :             state->fBlitBW = D64_BlitBW;
     490           0 :             return true;
     491             :         default:
     492           0 :             return false;
     493             :     }
     494             : }
     495             : 
     496           0 : void SkLinearGradient::
     497             : LinearGradient4fContext::D32_BlitBW(BlitState* state, int x, int y, const SkPixmap& dst,
     498             :                                     int count) {
     499             :     // FIXME: ignoring coverage for now
     500             :     const LinearGradient4fContext* ctx =
     501           0 :         static_cast<const LinearGradient4fContext*>(state->fCtx);
     502             : 
     503           0 :     if (!dst.info().gammaCloseToSRGB()) {
     504           0 :         if (ctx->fColorsArePremul) {
     505           0 :             ctx->shadePremulSpan<DstType::L32, ApplyPremul::False>(
     506           0 :                 x, y, dst.writable_addr32(x, y), count);
     507             :         } else {
     508           0 :             ctx->shadePremulSpan<DstType::L32, ApplyPremul::True>(
     509           0 :                 x, y, dst.writable_addr32(x, y), count);
     510             :         }
     511             :     } else {
     512           0 :         if (ctx->fColorsArePremul) {
     513           0 :             ctx->shadePremulSpan<DstType::S32, ApplyPremul::False>(
     514           0 :                 x, y, dst.writable_addr32(x, y), count);
     515             :         } else {
     516           0 :             ctx->shadePremulSpan<DstType::S32, ApplyPremul::True>(
     517           0 :                 x, y, dst.writable_addr32(x, y), count);
     518             :         }
     519             :     }
     520           0 : }
     521             : 
     522           0 : void SkLinearGradient::
     523             : LinearGradient4fContext::D64_BlitBW(BlitState* state, int x, int y, const SkPixmap& dst,
     524             :                                     int count) {
     525             :     // FIXME: ignoring coverage for now
     526             :     const LinearGradient4fContext* ctx =
     527           0 :         static_cast<const LinearGradient4fContext*>(state->fCtx);
     528             : 
     529           0 :     if (ctx->fColorsArePremul) {
     530           0 :         ctx->shadePremulSpan<DstType::F16, ApplyPremul::False>(
     531           0 :             x, y, dst.writable_addr64(x, y), count);
     532             :     } else {
     533           0 :         ctx->shadePremulSpan<DstType::F16, ApplyPremul::True>(
     534           0 :             x, y, dst.writable_addr64(x, y), count);
     535             :     }
     536           0 : }

Generated by: LCOV version 1.13