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

          Line data    Source code
       1             : /*
       2             :  * Copyright 2012 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 "SkTwoPointConicalGradient.h"
       9             : 
      10             : struct TwoPtRadialContext {
      11             :     const TwoPtRadial&  fRec;
      12             :     float               fRelX, fRelY;
      13             :     const float         fIncX, fIncY;
      14             :     float               fB;
      15             :     const float         fDB;
      16             : 
      17             :     TwoPtRadialContext(const TwoPtRadial& rec, SkScalar fx, SkScalar fy,
      18             :                        SkScalar dfx, SkScalar dfy);
      19             :     SkFixed nextT();
      20             : };
      21             : 
      22           0 : static int valid_divide(float numer, float denom, float* ratio) {
      23           0 :     SkASSERT(ratio);
      24           0 :     if (0 == denom) {
      25           0 :         return 0;
      26             :     }
      27           0 :     *ratio = numer / denom;
      28           0 :     return 1;
      29             : }
      30             : 
      31             : // Return the number of distinct real roots, and write them into roots[] in
      32             : // ascending order
      33           0 : static int find_quad_roots(float A, float B, float C, float roots[2], bool descendingOrder = false) {
      34           0 :     SkASSERT(roots);
      35             : 
      36           0 :     if (A == 0) {
      37           0 :         return valid_divide(-C, B, roots);
      38             :     }
      39             : 
      40           0 :     float R = B*B - 4*A*C;
      41           0 :     if (R < 0) {
      42           0 :         return 0;
      43             :     }
      44           0 :     R = sk_float_sqrt(R);
      45             : 
      46             : #if 1
      47           0 :     float Q = B;
      48           0 :     if (Q < 0) {
      49           0 :         Q -= R;
      50             :     } else {
      51           0 :         Q += R;
      52             :     }
      53             : #else
      54             :     // on 10.6 this was much slower than the above branch :(
      55             :     float Q = B + copysignf(R, B);
      56             : #endif
      57           0 :     Q *= -0.5f;
      58           0 :     if (0 == Q) {
      59           0 :         roots[0] = 0;
      60           0 :         return 1;
      61             :     }
      62             : 
      63           0 :     float r0 = Q / A;
      64           0 :     float r1 = C / Q;
      65           0 :     roots[0] = r0 < r1 ? r0 : r1;
      66           0 :     roots[1] = r0 > r1 ? r0 : r1;
      67           0 :     if (descendingOrder) {
      68           0 :         SkTSwap(roots[0], roots[1]);
      69             :     }
      70           0 :     return 2;
      71             : }
      72             : 
      73           0 : static float lerp(float x, float dx, float t) {
      74           0 :     return x + t * dx;
      75             : }
      76             : 
      77           0 : static float sqr(float x) { return x * x; }
      78             : 
      79           0 : void TwoPtRadial::init(const SkPoint& center0, SkScalar rad0,
      80             :                        const SkPoint& center1, SkScalar rad1,
      81             :                        bool flipped) {
      82           0 :     fCenterX = SkScalarToFloat(center0.fX);
      83           0 :     fCenterY = SkScalarToFloat(center0.fY);
      84           0 :     fDCenterX = SkScalarToFloat(center1.fX) - fCenterX;
      85           0 :     fDCenterY = SkScalarToFloat(center1.fY) - fCenterY;
      86           0 :     fRadius = SkScalarToFloat(rad0);
      87           0 :     fDRadius = SkScalarToFloat(rad1) - fRadius;
      88             : 
      89           0 :     fA = sqr(fDCenterX) + sqr(fDCenterY) - sqr(fDRadius);
      90           0 :     fRadius2 = sqr(fRadius);
      91           0 :     fRDR = fRadius * fDRadius;
      92             : 
      93           0 :     fFlipped = flipped;
      94           0 : }
      95             : 
      96           0 : TwoPtRadialContext::TwoPtRadialContext(const TwoPtRadial& rec, SkScalar fx, SkScalar fy,
      97           0 :                                        SkScalar dfx, SkScalar dfy)
      98             :     : fRec(rec)
      99           0 :     , fRelX(SkScalarToFloat(fx) - rec.fCenterX)
     100           0 :     , fRelY(SkScalarToFloat(fy) - rec.fCenterY)
     101             :     , fIncX(SkScalarToFloat(dfx))
     102             :     , fIncY(SkScalarToFloat(dfy))
     103           0 :     , fB(-2 * (rec.fDCenterX * fRelX + rec.fDCenterY * fRelY + rec.fRDR))
     104           0 :     , fDB(-2 * (rec.fDCenterX * fIncX + rec.fDCenterY * fIncY)) {}
     105             : 
     106           0 : SkFixed TwoPtRadialContext::nextT() {
     107             :     float roots[2];
     108             : 
     109           0 :     float C = sqr(fRelX) + sqr(fRelY) - fRec.fRadius2;
     110           0 :     int countRoots = find_quad_roots(fRec.fA, fB, C, roots, fRec.fFlipped);
     111             : 
     112           0 :     fRelX += fIncX;
     113           0 :     fRelY += fIncY;
     114           0 :     fB += fDB;
     115             : 
     116           0 :     if (0 == countRoots) {
     117           0 :         return TwoPtRadial::kDontDrawT;
     118             :     }
     119             : 
     120             :     // Prefer the bigger t value if both give a radius(t) > 0
     121             :     // find_quad_roots returns the values sorted, so we start with the last
     122           0 :     float t = roots[countRoots - 1];
     123           0 :     float r = lerp(fRec.fRadius, fRec.fDRadius, t);
     124           0 :     if (r < 0) {
     125           0 :         t = roots[0];   // might be the same as roots[countRoots-1]
     126           0 :         r = lerp(fRec.fRadius, fRec.fDRadius, t);
     127           0 :         if (r < 0) {
     128           0 :             return TwoPtRadial::kDontDrawT;
     129             :         }
     130             :     }
     131           0 :     return SkFloatToFixed(t);
     132             : }
     133             : 
     134             : typedef void (*TwoPointConicalProc)(TwoPtRadialContext* rec, SkPMColor* dstC,
     135             :                                     const SkPMColor* cache, int toggle, int count);
     136             : 
     137           0 : static void twopoint_clamp(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC,
     138             :                            const SkPMColor* SK_RESTRICT cache, int toggle,
     139             :                            int count) {
     140           0 :     for (; count > 0; --count) {
     141           0 :         SkFixed t = rec->nextT();
     142           0 :         if (TwoPtRadial::DontDrawT(t)) {
     143           0 :             *dstC++ = 0;
     144             :         } else {
     145           0 :             SkFixed index = SkClampMax(t, 0xFFFF);
     146           0 :             SkASSERT(index <= 0xFFFF);
     147           0 :             *dstC++ = cache[toggle +
     148           0 :                             (index >> SkGradientShaderBase::kCache32Shift)];
     149             :         }
     150           0 :         toggle = next_dither_toggle(toggle);
     151             :     }
     152           0 : }
     153             : 
     154           0 : static void twopoint_repeat(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC,
     155             :                             const SkPMColor* SK_RESTRICT cache, int toggle,
     156             :                             int count) {
     157           0 :     for (; count > 0; --count) {
     158           0 :         SkFixed t = rec->nextT();
     159           0 :         if (TwoPtRadial::DontDrawT(t)) {
     160           0 :             *dstC++ = 0;
     161             :         } else {
     162           0 :             SkFixed index = repeat_tileproc(t);
     163           0 :             SkASSERT(index <= 0xFFFF);
     164           0 :             *dstC++ = cache[toggle +
     165           0 :                             (index >> SkGradientShaderBase::kCache32Shift)];
     166             :         }
     167           0 :         toggle = next_dither_toggle(toggle);
     168             :     }
     169           0 : }
     170             : 
     171           0 : static void twopoint_mirror(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC,
     172             :                             const SkPMColor* SK_RESTRICT cache, int toggle,
     173             :                             int count) {
     174           0 :     for (; count > 0; --count) {
     175           0 :         SkFixed t = rec->nextT();
     176           0 :         if (TwoPtRadial::DontDrawT(t)) {
     177           0 :             *dstC++ = 0;
     178             :         } else {
     179           0 :             SkFixed index = mirror_tileproc(t);
     180           0 :             SkASSERT(index <= 0xFFFF);
     181           0 :             *dstC++ = cache[toggle +
     182           0 :                             (index >> SkGradientShaderBase::kCache32Shift)];
     183             :         }
     184           0 :         toggle = next_dither_toggle(toggle);
     185             :     }
     186           0 : }
     187             : 
     188             : /////////////////////////////////////////////////////////////////////
     189             : 
     190           0 : SkTwoPointConicalGradient::SkTwoPointConicalGradient(
     191             :         const SkPoint& start, SkScalar startRadius,
     192             :         const SkPoint& end, SkScalar endRadius,
     193           0 :         bool flippedGrad, const Descriptor& desc)
     194             :     : SkGradientShaderBase(desc, SkMatrix::I())
     195             :     , fCenter1(start)
     196             :     , fCenter2(end)
     197             :     , fRadius1(startRadius)
     198             :     , fRadius2(endRadius)
     199           0 :     , fFlippedGrad(flippedGrad)
     200             : {
     201             :     // this is degenerate, and should be caught by our caller
     202           0 :     SkASSERT(fCenter1 != fCenter2 || fRadius1 != fRadius2);
     203           0 :     fRec.init(fCenter1, fRadius1, fCenter2, fRadius2, fFlippedGrad);
     204           0 : }
     205             : 
     206           0 : bool SkTwoPointConicalGradient::isOpaque() const {
     207             :     // Because areas outside the cone are left untouched, we cannot treat the
     208             :     // shader as opaque even if the gradient itself is opaque.
     209             :     // TODO(junov): Compute whether the cone fills the plane crbug.com/222380
     210           0 :     return false;
     211             : }
     212             : 
     213           0 : SkShader::Context* SkTwoPointConicalGradient::onMakeContext(
     214             :     const ContextRec& rec, SkArenaAlloc* alloc) const {
     215           0 :     return CheckedMakeContext<TwoPointConicalGradientContext>(alloc, *this, rec);
     216             : }
     217             : 
     218           0 : SkTwoPointConicalGradient::TwoPointConicalGradientContext::TwoPointConicalGradientContext(
     219           0 :         const SkTwoPointConicalGradient& shader, const ContextRec& rec)
     220           0 :     : INHERITED(shader, rec)
     221             : {
     222             :     // in general, we might discard based on computed-radius, so clear
     223             :     // this flag (todo: sometimes we can detect that we never discard...)
     224           0 :     fFlags &= ~kOpaqueAlpha_Flag;
     225           0 : }
     226             : 
     227           0 : void SkTwoPointConicalGradient::TwoPointConicalGradientContext::shadeSpan(
     228             :         int x, int y, SkPMColor* dstCParam, int count) {
     229             :     const SkTwoPointConicalGradient& twoPointConicalGradient =
     230           0 :             static_cast<const SkTwoPointConicalGradient&>(fShader);
     231             : 
     232           0 :     int toggle = init_dither_toggle(x, y);
     233             : 
     234           0 :     SkASSERT(count > 0);
     235             : 
     236           0 :     SkPMColor* SK_RESTRICT dstC = dstCParam;
     237             : 
     238           0 :     SkMatrix::MapXYProc dstProc = fDstToIndexProc;
     239             : 
     240           0 :     const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
     241             : 
     242           0 :     TwoPointConicalProc shadeProc = twopoint_repeat;
     243           0 :     if (SkShader::kClamp_TileMode == twoPointConicalGradient.fTileMode) {
     244           0 :         shadeProc = twopoint_clamp;
     245           0 :     } else if (SkShader::kMirror_TileMode == twoPointConicalGradient.fTileMode) {
     246           0 :         shadeProc = twopoint_mirror;
     247             :     } else {
     248           0 :         SkASSERT(SkShader::kRepeat_TileMode == twoPointConicalGradient.fTileMode);
     249             :     }
     250             : 
     251           0 :     if (fDstToIndexClass != kPerspective_MatrixClass) {
     252             :         SkPoint srcPt;
     253           0 :         dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
     254           0 :                 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
     255           0 :         SkScalar dx, fx = srcPt.fX;
     256           0 :         SkScalar dy, fy = srcPt.fY;
     257             : 
     258           0 :         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
     259           0 :             const auto step = fDstToIndex.fixedStepInX(SkIntToScalar(y));
     260           0 :             dx = step.fX;
     261           0 :             dy = step.fY;
     262             :         } else {
     263           0 :             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
     264           0 :             dx = fDstToIndex.getScaleX();
     265           0 :             dy = fDstToIndex.getSkewY();
     266             :         }
     267             : 
     268           0 :         TwoPtRadialContext rec(twoPointConicalGradient.fRec, fx, fy, dx, dy);
     269           0 :         (*shadeProc)(&rec, dstC, cache, toggle, count);
     270             :     } else {    // perspective case
     271           0 :         SkScalar dstX = SkIntToScalar(x) + SK_ScalarHalf;
     272           0 :         SkScalar dstY = SkIntToScalar(y) + SK_ScalarHalf;
     273           0 :         for (; count > 0; --count) {
     274             :             SkPoint srcPt;
     275           0 :             dstProc(fDstToIndex, dstX, dstY, &srcPt);
     276           0 :             TwoPtRadialContext rec(twoPointConicalGradient.fRec, srcPt.fX, srcPt.fY, 0, 0);
     277           0 :             (*shadeProc)(&rec, dstC, cache, toggle, 1);
     278             : 
     279           0 :             dstX += SK_Scalar1;
     280           0 :             toggle = next_dither_toggle(toggle);
     281           0 :             dstC += 1;
     282             :         }
     283             :     }
     284           0 : }
     285             : 
     286             : // Returns the original non-sorted version of the gradient
     287           0 : SkShader::GradientType SkTwoPointConicalGradient::asAGradient(
     288             :     GradientInfo* info) const {
     289           0 :     if (info) {
     290           0 :         commonAsAGradient(info, fFlippedGrad);
     291           0 :         info->fPoint[0] = fCenter1;
     292           0 :         info->fPoint[1] = fCenter2;
     293           0 :         info->fRadius[0] = fRadius1;
     294           0 :         info->fRadius[1] = fRadius2;
     295           0 :         if (fFlippedGrad) {
     296           0 :             SkTSwap(info->fPoint[0], info->fPoint[1]);
     297           0 :             SkTSwap(info->fRadius[0], info->fRadius[1]);
     298             :         }
     299             :     }
     300           0 :     return kConical_GradientType;
     301             : }
     302             : 
     303           0 : sk_sp<SkFlattenable> SkTwoPointConicalGradient::CreateProc(SkReadBuffer& buffer) {
     304           0 :     DescriptorScope desc;
     305           0 :     if (!desc.unflatten(buffer)) {
     306           0 :         return nullptr;
     307             :     }
     308           0 :     SkPoint c1 = buffer.readPoint();
     309           0 :     SkPoint c2 = buffer.readPoint();
     310           0 :     SkScalar r1 = buffer.readScalar();
     311           0 :     SkScalar r2 = buffer.readScalar();
     312             : 
     313           0 :     if (buffer.readBool()) {    // flipped
     314           0 :         SkTSwap(c1, c2);
     315           0 :         SkTSwap(r1, r2);
     316             : 
     317           0 :         SkColor4f* colors = desc.mutableColors();
     318           0 :         SkScalar* pos = desc.mutablePos();
     319           0 :         const int last = desc.fCount - 1;
     320           0 :         const int half = desc.fCount >> 1;
     321           0 :         for (int i = 0; i < half; ++i) {
     322           0 :             SkTSwap(colors[i], colors[last - i]);
     323           0 :             if (pos) {
     324           0 :                 SkScalar tmp = pos[i];
     325           0 :                 pos[i] = SK_Scalar1 - pos[last - i];
     326           0 :                 pos[last - i] = SK_Scalar1 - tmp;
     327             :             }
     328             :         }
     329           0 :         if (pos) {
     330           0 :             if (desc.fCount & 1) {
     331           0 :                 pos[half] = SK_Scalar1 - pos[half];
     332             :             }
     333             :         }
     334             :     }
     335             : 
     336           0 :     return SkGradientShader::MakeTwoPointConical(c1, r1, c2, r2, desc.fColors,
     337           0 :                                                  std::move(desc.fColorSpace), desc.fPos,
     338             :                                                  desc.fCount, desc.fTileMode, desc.fGradFlags,
     339           0 :                                                  desc.fLocalMatrix);
     340             : }
     341             : 
     342           0 : void SkTwoPointConicalGradient::flatten(SkWriteBuffer& buffer) const {
     343           0 :     this->INHERITED::flatten(buffer);
     344           0 :     buffer.writePoint(fCenter1);
     345           0 :     buffer.writePoint(fCenter2);
     346           0 :     buffer.writeScalar(fRadius1);
     347           0 :     buffer.writeScalar(fRadius2);
     348           0 :     buffer.writeBool(fFlippedGrad);
     349           0 : }
     350             : 
     351             : #if SK_SUPPORT_GPU
     352             : 
     353             : #include "SkGr.h"
     354             : #include "SkTwoPointConicalGradient_gpu.h"
     355             : 
     356           0 : sk_sp<GrFragmentProcessor> SkTwoPointConicalGradient::asFragmentProcessor(
     357             :         const AsFPArgs& args) const {
     358           0 :     SkASSERT(args.fContext);
     359           0 :     SkASSERT(fPtsToUnit.isIdentity());
     360           0 :     sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(),
     361           0 :                                                                        args.fDstColorSpace);
     362             :     sk_sp<GrFragmentProcessor> inner(Gr2PtConicalGradientEffect::Make(
     363           0 :         GrGradientEffect::CreateArgs(args.fContext, this, args.fLocalMatrix, fTileMode,
     364           0 :                                      std::move(colorSpaceXform), SkToBool(args.fDstColorSpace))));
     365           0 :     return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
     366             : }
     367             : 
     368             : #endif
     369             : 
     370             : #ifndef SK_IGNORE_TO_STRING
     371           0 : void SkTwoPointConicalGradient::toString(SkString* str) const {
     372           0 :     str->append("SkTwoPointConicalGradient: (");
     373             : 
     374           0 :     str->append("center1: (");
     375           0 :     str->appendScalar(fCenter1.fX);
     376           0 :     str->append(", ");
     377           0 :     str->appendScalar(fCenter1.fY);
     378           0 :     str->append(") radius1: ");
     379           0 :     str->appendScalar(fRadius1);
     380           0 :     str->append(" ");
     381             : 
     382           0 :     str->append("center2: (");
     383           0 :     str->appendScalar(fCenter2.fX);
     384           0 :     str->append(", ");
     385           0 :     str->appendScalar(fCenter2.fY);
     386           0 :     str->append(") radius2: ");
     387           0 :     str->appendScalar(fRadius2);
     388           0 :     str->append(" ");
     389             : 
     390           0 :     this->INHERITED::toString(str);
     391             : 
     392           0 :     str->append(")");
     393           0 : }
     394             : #endif

Generated by: LCOV version 1.13