tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

0016-Bug-718849-Radial-gradients.patch (16295B)


      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
      7 
      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 }
     25 
     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
     39 
     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);
     49 
     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);
     55 
     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;
     61 
     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);
     71 
     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.
     78 
     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.
     90 
     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
     97 
     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
    101 
    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.
    108 
    109 */
    110 
    111 namespace {
    112 
    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     }
    130 
    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 }
    158 
    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);
    167 
    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         }
    192 
    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 }
    225 
    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 }
    253 
    254 
    255 
    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();
    263 
    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;
    272 
    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;
    287 
    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     }
    327 
    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         }
    334 
    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     }
    345 
    346     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(Two_Point_Radial_Gradient)
    347 
    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;
    356 
    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;
    369 
    370         fPtsToUnit.setTranslate(-fCenter1.fX, -fCenter1.fY);
    371 -        fPtsToUnit.postScale(inv, inv);
    372     }
    373 };
    374 
    375 ///////////////////////////////////////////////////////////////////////////////
    376 
    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);
    388 
    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 }
    397 
    398 SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy,
    399                                         const SkColor colors[],
    400                                         const SkScalar pos[],