diff options
author | Florin Malita <fmalita@chromium.org> | 2017-06-29 11:03:45 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-06-29 15:34:47 +0000 |
commit | 9026fe13a751582e58e98f9bf735c18b4719d7fe (patch) | |
tree | 6c3f03fb9be33f18d1d686a10839e096ab030393 /src/shaders/gradients | |
parent | 762466e9fe0478bcf11fba532998e81e33b3069e (diff) |
2pt conical stage for focal-point-outside case
A couple of annoyances here:
1) the prev vector_scale stage is not usable for masking, as NaN values can propagate through
=> switch to actual masking
2) for the outside case, we must select the min root when the gradient is flipped
=> split into two templated stages (_min, _max)
(I'm not convinced that we need to flip the gradient for RP at all; we can investigate later)
Change-Id: I0283812d613a53124f2987d1aea1f26e4533655e
Reviewed-on: https://skia-review.googlesource.com/21162
Reviewed-by: Mike Klein <mtklein@chromium.org>
Commit-Queue: Florin Malita <fmalita@chromium.org>
Diffstat (limited to 'src/shaders/gradients')
-rw-r--r-- | src/shaders/gradients/SkTwoPointConicalGradient.cpp | 36 |
1 files changed, 27 insertions, 9 deletions
diff --git a/src/shaders/gradients/SkTwoPointConicalGradient.cpp b/src/shaders/gradients/SkTwoPointConicalGradient.cpp index 0f48cc20e3..07934ed613 100644 --- a/src/shaders/gradients/SkTwoPointConicalGradient.cpp +++ b/src/shaders/gradients/SkTwoPointConicalGradient.cpp @@ -453,11 +453,6 @@ bool SkTwoPointConicalGradient::adjustMatrixAndAppendStages(SkArenaAlloc* alloc, return true; } - if (dCenter + fRadius1 > fRadius2) { - // We only handle well behaved cases for now. - return false; - } - // To simplify the stage math, we transform the universe (translate/scale/rotate) // such that fCenter1 -> (0, 0) and fCenter2 -> (1, 0). SkMatrix map_to_unit_vector; @@ -475,14 +470,37 @@ bool SkTwoPointConicalGradient::adjustMatrixAndAppendStages(SkArenaAlloc* alloc, ctx->fR0 = fRadius1 / dCenter; ctx->fDR = dRadius / dCenter; + // Is the solver guaranteed to not produce degenerates? + bool isWellBehaved = true; + if (SkScalarNearlyZero(coeffA)) { // The focal point is on the edge of the end circle. p->append(SkRasterPipeline::xy_to_2pt_conical_linear, ctx); - // To handle degenerate values (NaN, r < 0), the t stage sets up a scale/mask - // context, which we post-apply to force transparent black. - postPipeline->append(SkRasterPipeline::vector_scale, &ctx->fMask); + isWellBehaved = false; } else { - p->append(SkRasterPipeline::xy_to_2pt_conical_quadratic, ctx); + if (dCenter + fRadius1 > fRadius2) { + // The focal point is outside the end circle. + + // We want the larger root, per spec: + // "For all values of ω where r(ω) > 0, starting with the value of ω nearest + // to positive infinity and ending with the value of ω nearest to negative + // infinity, draw the circumference of the circle with radius r(ω) at position + // (x(ω), y(ω)), with the color at ω, but only painting on the parts of the + // bitmap that have not yet been painted on by earlier circles in this step for + // this rendering of the gradient." + // (https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-createradialgradient) + p->append(fFlippedGrad ? SkRasterPipeline::xy_to_2pt_conical_quadratic_min + : SkRasterPipeline::xy_to_2pt_conical_quadratic_max, ctx); + isWellBehaved = false; + } else { + // The focal point is inside (well-behaved case). + p->append(SkRasterPipeline::xy_to_2pt_conical_quadratic_max, ctx); + } + } + + if (!isWellBehaved) { + p->append(SkRasterPipeline::mask_2pt_conical_degenerates, ctx); + postPipeline->append(SkRasterPipeline::apply_vector_mask, &ctx->fMask); } return true; |