gfx/skia/patches/archive/0016-Bug-718849-Radial-gradients.patch

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 # HG changeset patch
     2 # User Matt Woodrow <mwoodrow@mozilla.com>
     3 # Date 1339988782 -43200
     4 # Node ID 1e9dae659ee6c992f719fd4136efbcc5410ded37
     5 # Parent 946750f6d95febd199fb7b748e9d2c48fd01c8a6
     6 [mq]: skia-windows-gradients
     8 diff --git a/gfx/skia/src/effects/SkGradientShader.cpp b/gfx/skia/src/effects/SkGradientShader.cpp
     9 --- a/gfx/skia/src/effects/SkGradientShader.cpp
    10 +++ b/gfx/skia/src/effects/SkGradientShader.cpp
    11 @@ -847,16 +847,19 @@ bool Linear_Gradient::setContext(const S
    12          fFlags |= SkShader::kConstInY32_Flag;
    13          if ((fFlags & SkShader::kHasSpan16_Flag) && !paint.isDither()) {
    14              // only claim this if we do have a 16bit mode (i.e. none of our
    15              // colors have alpha), and if we are not dithering (which obviously
    16              // is not const in Y).
    17              fFlags |= SkShader::kConstInY16_Flag;
    18          }
    19      }
    20 +    if (fStart == fEnd) {
    21 +        fFlags &= ~kOpaqueAlpha_Flag;
    22 +    }
    23      return true;
    24  }
    26  #define NO_CHECK_ITER               \
    27      do {                            \
    28      unsigned fi = fx >> Gradient_Shader::kCache32Shift; \
    29      SkASSERT(fi <= 0xFF);           \
    30      fx += dx;                       \
    31 @@ -976,16 +979,21 @@ void Linear_Gradient::shadeSpan(int x, i
    32      TileProc            proc = fTileProc;
    33      const SkPMColor* SK_RESTRICT cache = this->getCache32();
    34  #ifdef USE_DITHER_32BIT_GRADIENT
    35      int                 toggle = ((x ^ y) & 1) * kDitherStride32;
    36  #else
    37      int toggle = 0;
    38  #endif
    40 +    if (fStart == fEnd) {
    41 +        sk_bzero(dstC, count * sizeof(*dstC));
    42 +        return;
    43 +    }
    44 +
    45      if (fDstToIndexClass != kPerspective_MatrixClass) {
    46          dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
    47                               SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
    48          SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
    50          if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
    51              SkFixed dxStorage[1];
    52              (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
    53 @@ -1169,16 +1177,21 @@ void Linear_Gradient::shadeSpan16(int x,
    54      SkASSERT(count > 0);
    56      SkPoint             srcPt;
    57      SkMatrix::MapXYProc dstProc = fDstToIndexProc;
    58      TileProc            proc = fTileProc;
    59      const uint16_t* SK_RESTRICT cache = this->getCache16();
    60      int                 toggle = ((x ^ y) & 1) * kDitherStride16;
    62 +    if (fStart == fEnd) {
    63 +        sk_bzero(dstC, count * sizeof(*dstC));
    64 +        return;
    65 +    }
    66 +
    67      if (fDstToIndexClass != kPerspective_MatrixClass) {
    68          dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
    69                               SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
    70          SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
    72          if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
    73              SkFixed dxStorage[1];
    74              (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
    75 @@ -1739,21 +1752,25 @@ void Radial_Gradient::shadeSpan(int x, i
    76     possible circles on which the point may fall.  Solving for t yields
    77     the gradient value to use.
    79     If a<0, the start circle is entirely contained in the
    80     end circle, and one of the roots will be <0 or >1 (off the line
    81     segment).  If a>0, the start circle falls at least partially
    82     outside the end circle (or vice versa), and the gradient
    83     defines a "tube" where a point may be on one circle (on the
    84 -   inside of the tube) or the other (outside of the tube).  We choose
    85 -   one arbitrarily.
    86 +   inside of the tube) or the other (outside of the tube). We choose
    87 +   the one with the highest t value, as long as the radius that it 
    88 +   corresponds to is >=0. In the case where neither root has a positive
    89 +   radius, we don't draw anything.
    91 +   XXXmattwoodrow: I've removed this for now since it breaks
    92 +   down when Dr == 0. Is there something else we can do instead?
    93     In order to keep the math to within the limits of fixed point,
    94 -   we divide the entire quadratic by Dr^2, and replace
    95 +   we divide the entire quadratic by Dr, and replace
    96     (x - Sx)/Dr with x' and (y - Sy)/Dr with y', giving
    98     [Dx^2 / Dr^2 + Dy^2 / Dr^2 - 1)] * t^2
    99     + 2 * [x' * Dx / Dr + y' * Dy / Dr - Sr / Dr] * t
   100     + [x'^2 + y'^2 - Sr^2/Dr^2] = 0
   102     (x' and y' are computed by appending the subtract and scale to the
   103     fDstToIndex matrix in the constructor).
   104 @@ -1763,99 +1780,122 @@ void Radial_Gradient::shadeSpan(int x, i
   105     x' and y', if x and y are linear in the span, 'B' can be computed
   106     incrementally with a simple delta (db below).  If it is not (e.g.,
   107     a perspective projection), it must be computed in the loop.
   109  */
   111  namespace {
   113 -inline SkFixed two_point_radial(SkScalar b, SkScalar fx, SkScalar fy,
   114 -                                SkScalar sr2d2, SkScalar foura,
   115 -                                SkScalar oneOverTwoA, bool posRoot) {
   116 +inline bool two_point_radial(SkScalar b, SkScalar fx, SkScalar fy,
   117 +                             SkScalar sr2d2, SkScalar foura,
   118 +                             SkScalar oneOverTwoA, SkScalar diffRadius, 
   119 +                             SkScalar startRadius, SkFixed& t) {
   120      SkScalar c = SkScalarSquare(fx) + SkScalarSquare(fy) - sr2d2;
   121      if (0 == foura) {
   122 -        return SkScalarToFixed(SkScalarDiv(-c, b));
   123 +        SkScalar result = SkScalarDiv(-c, b);
   124 +        if (result * diffRadius + startRadius >= 0) {
   125 +            t = SkScalarToFixed(result);
   126 +            return true;
   127 +        }
   128 +        return false;
   129      }
   131      SkScalar discrim = SkScalarSquare(b) - SkScalarMul(foura, c);
   132      if (discrim < 0) {
   133 -        discrim = -discrim;
   134 +        return false;
   135      }
   136      SkScalar rootDiscrim = SkScalarSqrt(discrim);
   137 -    SkScalar result;
   138 -    if (posRoot) {
   139 -        result = SkScalarMul(-b + rootDiscrim, oneOverTwoA);
   140 -    } else {
   141 -        result = SkScalarMul(-b - rootDiscrim, oneOverTwoA);
   142 +
   143 +    // Make sure the results corresponds to a positive radius.
   144 +    SkScalar result = SkScalarMul(-b + rootDiscrim, oneOverTwoA);
   145 +    if (result * diffRadius + startRadius >= 0) {
   146 +        t = SkScalarToFixed(result);
   147 +        return true;
   148      }
   149 -    return SkScalarToFixed(result);
   150 +    result = SkScalarMul(-b - rootDiscrim, oneOverTwoA);
   151 +    if (result * diffRadius + startRadius >= 0) {
   152 +        t = SkScalarToFixed(result);
   153 +        return true;
   154 +    }
   155 +
   156 +    return false;
   157  }
   159  typedef void (* TwoPointRadialShadeProc)(SkScalar fx, SkScalar dx,
   160          SkScalar fy, SkScalar dy,
   161          SkScalar b, SkScalar db,
   162 -        SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
   163 +        SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA,
   164 +        SkScalar fDiffRadius, SkScalar fRadius1,
   165          SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
   166          int count);
   168  void shadeSpan_twopoint_clamp(SkScalar fx, SkScalar dx,
   169          SkScalar fy, SkScalar dy,
   170          SkScalar b, SkScalar db,
   171 -        SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
   172 +        SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA,
   173 +        SkScalar fDiffRadius, SkScalar fRadius1,
   174          SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
   175          int count) {
   176      for (; count > 0; --count) {
   177 -        SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
   178 -                                     fOneOverTwoA, posRoot);
   179 -
   180 -        if (t < 0) {
   181 +        SkFixed t;
   182 +        if (!two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1, t)) {
   183 +          *(dstC++) = 0;
   184 +        } else if (t < 0) {
   185              *dstC++ = cache[-1];
   186          } else if (t > 0xFFFF) {
   187              *dstC++ = cache[Gradient_Shader::kCache32Count * 2];
   188          } else {
   189              SkASSERT(t <= 0xFFFF);
   190              *dstC++ = cache[t >> Gradient_Shader::kCache32Shift];
   191          }
   193          fx += dx;
   194          fy += dy;
   195          b += db;
   196      }
   197  }
   198  void shadeSpan_twopoint_mirror(SkScalar fx, SkScalar dx,
   199          SkScalar fy, SkScalar dy,
   200          SkScalar b, SkScalar db,
   201 -        SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
   202 +        SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA,
   203 +        SkScalar fDiffRadius, SkScalar fRadius1,
   204          SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
   205          int count) {
   206      for (; count > 0; --count) {
   207 -        SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
   208 -                                     fOneOverTwoA, posRoot);
   209 -        SkFixed index = mirror_tileproc(t);
   210 -        SkASSERT(index <= 0xFFFF);
   211 -        *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
   212 +        SkFixed t;
   213 +        if (!two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1, t)) {
   214 +          *(dstC++) = 0;
   215 +        } else {
   216 +          SkFixed index = mirror_tileproc(t);
   217 +          SkASSERT(index <= 0xFFFF);
   218 +          *dstC++ = cache[index >> (16 - Gradient_Shader::kCache32Shift)];
   219 +        }
   220          fx += dx;
   221          fy += dy;
   222          b += db;
   223      }
   224  }
   226  void shadeSpan_twopoint_repeat(SkScalar fx, SkScalar dx,
   227          SkScalar fy, SkScalar dy,
   228          SkScalar b, SkScalar db,
   229 -        SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
   230 +        SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, 
   231 +        SkScalar fDiffRadius, SkScalar fRadius1,
   232          SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
   233          int count) {
   234      for (; count > 0; --count) {
   235 -        SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
   236 -                                     fOneOverTwoA, posRoot);
   237 -        SkFixed index = repeat_tileproc(t);
   238 -        SkASSERT(index <= 0xFFFF);
   239 -        *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
   240 +        SkFixed t;
   241 +        if (!two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1, t)) {
   242 +          *(dstC++) = 0;
   243 +        } else {
   244 +          SkFixed index = repeat_tileproc(t);
   245 +          SkASSERT(index <= 0xFFFF);
   246 +          *dstC++ = cache[index >> (16 - Gradient_Shader::kCache32Shift)];
   247 +        }
   248          fx += dx;
   249          fy += dy;
   250          b += db;
   251      }
   252  }
   256 @@ -1935,17 +1975,16 @@ public:
   257            sk_bzero(dstC, count * sizeof(*dstC));
   258            return;
   259          }
   260          SkMatrix::MapXYProc dstProc = fDstToIndexProc;
   261          TileProc            proc = fTileProc;
   262          const SkPMColor* SK_RESTRICT cache = this->getCache32();
   264          SkScalar foura = fA * 4;
   265 -        bool posRoot = fDiffRadius < 0;
   266          if (fDstToIndexClass != kPerspective_MatrixClass) {
   267              SkPoint srcPt;
   268              dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
   269                                   SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
   270              SkScalar dx, fx = srcPt.fX;
   271              SkScalar dy, fy = srcPt.fY;
   273              if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
   274 @@ -1954,60 +1993,69 @@ public:
   275                  dx = SkFixedToScalar(fixedX);
   276                  dy = SkFixedToScalar(fixedY);
   277              } else {
   278                  SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
   279                  dx = fDstToIndex.getScaleX();
   280                  dy = fDstToIndex.getSkewY();
   281              }
   282              SkScalar b = (SkScalarMul(fDiff.fX, fx) +
   283 -                         SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
   284 +                          SkScalarMul(fDiff.fY, fy) - fStartRadius * fDiffRadius) * 2;
   285              SkScalar db = (SkScalarMul(fDiff.fX, dx) +
   286                            SkScalarMul(fDiff.fY, dy)) * 2;
   288              TwoPointRadialShadeProc shadeProc = shadeSpan_twopoint_repeat;
   289              if (proc == clamp_tileproc) {
   290                  shadeProc = shadeSpan_twopoint_clamp;
   291              } else if (proc == mirror_tileproc) {
   292                  shadeProc = shadeSpan_twopoint_mirror;
   293              } else {
   294                  SkASSERT(proc == repeat_tileproc);
   295              }
   296              (*shadeProc)(fx, dx, fy, dy, b, db,
   297 -                         fSr2D2, foura, fOneOverTwoA, posRoot,
   298 +                         fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1,
   299                           dstC, cache, count);
   300          } else {    // perspective case
   301              SkScalar dstX = SkIntToScalar(x);
   302              SkScalar dstY = SkIntToScalar(y);
   303              for (; count > 0; --count) {
   304                  SkPoint             srcPt;
   305                  dstProc(fDstToIndex, dstX, dstY, &srcPt);
   306                  SkScalar fx = srcPt.fX;
   307                  SkScalar fy = srcPt.fY;
   308                  SkScalar b = (SkScalarMul(fDiff.fX, fx) +
   309                               SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
   310 -                SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
   311 -                                             fOneOverTwoA, posRoot);
   312 -                SkFixed index = proc(t);
   313 -                SkASSERT(index <= 0xFFFF);
   314 -                *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
   315 +                SkFixed t;
   316 +                if (!two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, fDiffRadius, fRadius1, t)) {
   317 +                  *(dstC++) = 0;
   318 +                } else {
   319 +                  SkFixed index = proc(t);
   320 +                  SkASSERT(index <= 0xFFFF);
   321 +                  *dstC++ = cache[index >> (16 - kCache32Bits)];
   322 +                }
   323                  dstX += SK_Scalar1;
   324              }
   325          }
   326      }
   328      virtual bool setContext(const SkBitmap& device,
   329                              const SkPaint& paint,
   330                              const SkMatrix& matrix) SK_OVERRIDE {
   331          if (!this->INHERITED::setContext(device, paint, matrix)) {
   332              return false;
   333          }
   335          // we don't have a span16 proc
   336          fFlags &= ~kHasSpan16_Flag;
   337 +
   338 +        // If we might end up wanting to draw nothing as part of the gradient
   339 +        // then we should mark ourselves as not being opaque.
   340 +        if (fA >= 0 || (fDiffRadius == 0 && fCenter1 == fCenter2)) {
   341 +            fFlags &= ~kOpaqueAlpha_Flag;
   342 +        }
   343          return true;
   344      }
   346      SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(Two_Point_Radial_Gradient)
   348  protected:
   349      Two_Point_Radial_Gradient(SkFlattenableReadBuffer& buffer)
   350              : INHERITED(buffer),
   351 @@ -2033,26 +2081,22 @@ private:
   352      const SkScalar fRadius1;
   353      const SkScalar fRadius2;
   354      SkPoint fDiff;
   355      SkScalar fStartRadius, fDiffRadius, fSr2D2, fA, fOneOverTwoA;
   357      void init() {
   358          fDiff = fCenter1 - fCenter2;
   359          fDiffRadius = fRadius2 - fRadius1;
   360 -        SkScalar inv = SkScalarInvert(fDiffRadius);
   361 -        fDiff.fX = SkScalarMul(fDiff.fX, inv);
   362 -        fDiff.fY = SkScalarMul(fDiff.fY, inv);
   363 -        fStartRadius = SkScalarMul(fRadius1, inv);
   364 +        fStartRadius = fRadius1;
   365          fSr2D2 = SkScalarSquare(fStartRadius);
   366 -        fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
   367 +        fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SkScalarSquare(fDiffRadius);
   368          fOneOverTwoA = fA ? SkScalarInvert(fA * 2) : 0;
   370          fPtsToUnit.setTranslate(-fCenter1.fX, -fCenter1.fY);
   371 -        fPtsToUnit.postScale(inv, inv);
   372      }
   373  };
   375  ///////////////////////////////////////////////////////////////////////////////
   377  class Sweep_Gradient : public Gradient_Shader {
   378  public:
   379      Sweep_Gradient(SkScalar cx, SkScalar cy, const SkColor colors[],
   380 @@ -2488,16 +2532,20 @@ SkShader* SkGradientShader::CreateTwoPoi
   381                                                   int colorCount,
   382                                                   SkShader::TileMode mode,
   383                                                   SkUnitMapper* mapper) {
   384      if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) {
   385          return NULL;
   386      }
   387      EXPAND_1_COLOR(colorCount);
   389 +    if (start == end && startRadius == 0) {
   390 +        return CreateRadial(start, endRadius, colors, pos, colorCount, mode, mapper);
   391 +    }
   392 +
   393      return SkNEW_ARGS(Two_Point_Radial_Gradient,
   394                        (start, startRadius, end, endRadius, colors, pos,
   395                         colorCount, mode, mapper));
   396  }
   398  SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy,
   399                                          const SkColor colors[],
   400                                          const SkScalar pos[],

mercurial