1bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita/* 2bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita * Copyright 2016 Google Inc. 3bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita * 4bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita * Use of this source code is governed by a BSD-style license that can be 5bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita * found in the LICENSE file. 6bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita */ 7bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita 8bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita#include "Sk4fGradientBase.h" 97e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 107e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita#include <functional> 11bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita 12bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitanamespace { 13bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita 14b931336f3b7913e64602562d7d6d9187086bbd5afmalitaSk4f pack_color(SkColor c, bool premul, const Sk4f& component_scale) { 15b931336f3b7913e64602562d7d6d9187086bbd5afmalita const SkColor4f c4f = SkColor4f::FromColor(c); 16b931336f3b7913e64602562d7d6d9187086bbd5afmalita const Sk4f pm4f = premul 17b931336f3b7913e64602562d7d6d9187086bbd5afmalita ? c4f.premul().to4f() 18b931336f3b7913e64602562d7d6d9187086bbd5afmalita : Sk4f{c4f.fR, c4f.fG, c4f.fB, c4f.fA}; 19b931336f3b7913e64602562d7d6d9187086bbd5afmalita 20b931336f3b7913e64602562d7d6d9187086bbd5afmalita return pm4f * component_scale; 217e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita} 227e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 237e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalitaclass IntervalIterator { 247e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalitapublic: 257e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita IntervalIterator(const SkColor* colors, const SkScalar* pos, int count, bool reverse) 267e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita : fColors(colors) 277e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita , fPos(pos) 287e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita , fCount(count) 297e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita , fFirstPos(reverse ? SK_Scalar1 : 0) 307e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita , fBegin(reverse ? count - 1 : 0) 317e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita , fAdvance(reverse ? -1 : 1) { 327e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita SkASSERT(colors); 337e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita SkASSERT(count > 0); 347e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } 357e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 367e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita void iterate(std::function<void(SkColor, SkColor, SkScalar, SkScalar)> func) const { 377e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita if (!fPos) { 387e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita this->iterateImplicitPos(func); 397e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita return; 407e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } 417e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 427e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita const int end = fBegin + fAdvance * (fCount - 1); 437e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita const SkScalar lastPos = 1 - fFirstPos; 447e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita int prev = fBegin; 457e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita SkScalar prevPos = fFirstPos; 467e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 477e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita do { 487e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita const int curr = prev + fAdvance; 497e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita SkASSERT(curr >= 0 && curr < fCount); 507e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 517e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // TODO: this sanitization should be done in SkGradientShaderBase 527e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita const SkScalar currPos = (fAdvance > 0) 537e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita ? SkTPin(fPos[curr], prevPos, lastPos) 547e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita : SkTPin(fPos[curr], lastPos, prevPos); 557e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 567e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita if (currPos != prevPos) { 577e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita SkASSERT((currPos - prevPos > 0) == (fAdvance > 0)); 587e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita func(fColors[prev], fColors[curr], prevPos, currPos); 597e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } 607e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 617e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita prev = curr; 627e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita prevPos = currPos; 637e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } while (prev != end); 647e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } 657e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 667e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalitaprivate: 677e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita void iterateImplicitPos(std::function<void(SkColor, SkColor, SkScalar, SkScalar)> func) const { 687e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // When clients don't provide explicit color stop positions (fPos == nullptr), 697e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // the color stops are distributed evenly across the unit interval 707e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // (implicit positioning). 717e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita const SkScalar dt = fAdvance * SK_Scalar1 / (fCount - 1); 727e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita const int end = fBegin + fAdvance * (fCount - 2); 737e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita int prev = fBegin; 747e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita SkScalar prevPos = fFirstPos; 757e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 767e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita while (prev != end) { 777e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita const int curr = prev + fAdvance; 787e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita SkASSERT(curr >= 0 && curr < fCount); 797e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 807e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita const SkScalar currPos = prevPos + dt; 817e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita func(fColors[prev], fColors[curr], prevPos, currPos); 827e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita prev = curr; 837e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita prevPos = currPos; 847e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } 857e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 867e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // emit the last interval with a pinned end position, to avoid precision issues 877e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita func(fColors[prev], fColors[prev + fAdvance], prevPos, 1 - fFirstPos); 887e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } 897e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 907e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita const SkColor* fColors; 917e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita const SkScalar* fPos; 927e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita const int fCount; 937e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita const SkScalar fFirstPos; 947e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita const int fBegin; 957e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita const int fAdvance; 967e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita}; 977e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 98da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malitavoid addMirrorIntervals(const SkColor colors[], 99da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const SkScalar pos[], int count, 100da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const Sk4f& componentScale, 101da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita bool premulColors, bool reverse, 102da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita Sk4fGradientIntervalBuffer::BufferType* buffer) { 103da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const IntervalIterator iter(colors, pos, count, reverse); 104da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita iter.iterate([&] (SkColor c0, SkColor c1, SkScalar p0, SkScalar p1) { 105da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita SkASSERT(buffer->empty() || buffer->back().fP1 == 2 - p0); 106da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita 107da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const auto mirror_p0 = 2 - p0; 108da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const auto mirror_p1 = 2 - p1; 109da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita // mirror_p1 & mirror_p1 may collapse for very small values - recheck to avoid 110da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita // triggering Interval asserts. 111da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita if (mirror_p0 != mirror_p1) { 112da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita buffer->emplace_back(pack_color(c0, premulColors, componentScale), mirror_p0, 113da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita pack_color(c1, premulColors, componentScale), mirror_p1); 114da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita } 115da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita }); 116da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita} 117da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita 118bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita} // anonymous namespace 119bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita 120da4545bfc58f8ec19df79f6ae75b7231477973d8Florin MalitaSk4fGradientInterval::Sk4fGradientInterval(const Sk4f& c0, SkScalar p0, 121da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const Sk4f& c1, SkScalar p1) 122bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita : fP0(p0) 123bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita , fP1(p1) 124b931336f3b7913e64602562d7d6d9187086bbd5afmalita , fZeroRamp((c0 == c1).allTrue()) { 125b931336f3b7913e64602562d7d6d9187086bbd5afmalita SkASSERT(p0 != p1); 1268f457591e6a21c240fd2fca56a97281b556ce796fmalita // Either p0 or p1 can be (-)inf for synthetic clamp edge intervals. 1278f457591e6a21c240fd2fca56a97281b556ce796fmalita SkASSERT(SkScalarIsFinite(p0) || SkScalarIsFinite(p1)); 1288f457591e6a21c240fd2fca56a97281b556ce796fmalita 1298f457591e6a21c240fd2fca56a97281b556ce796fmalita const auto dp = p1 - p0; 1308f457591e6a21c240fd2fca56a97281b556ce796fmalita 1318f457591e6a21c240fd2fca56a97281b556ce796fmalita // Clamp edge intervals are always zero-ramp. 1328f457591e6a21c240fd2fca56a97281b556ce796fmalita SkASSERT(SkScalarIsFinite(dp) || fZeroRamp); 1338f457591e6a21c240fd2fca56a97281b556ce796fmalita const Sk4f dc = SkScalarIsFinite(dp) ? (c1 - c0) / dp : 0; 134bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita 135b931336f3b7913e64602562d7d6d9187086bbd5afmalita c0.store(&fC0.fVec); 136b931336f3b7913e64602562d7d6d9187086bbd5afmalita dc.store(&fDc.fVec); 137bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita} 138bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita 139da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malitavoid Sk4fGradientIntervalBuffer::init(const SkColor colors[], const SkScalar pos[], int count, 140da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita SkShader::TileMode tileMode, bool premulColors, 141da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita SkScalar alpha, bool reverse) { 1427e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // The main job here is to build a specialized interval list: a different 1437e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // representation of the color stops data, optimized for efficient scan line 1447e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // access during shading. 1457e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // 1467e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // [{P0,C0} , {P1,C1}) [{P1,C2} , {P2,c3}) ... [{Pn,C2n} , {Pn+1,C2n+1}) 1477e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // 1487e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // The list may be inverted when requested (such that e.g. points are sorted 1497e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // in increasing x order when dx < 0). 1507e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // 1517e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // Note: the current representation duplicates pos data; we could refactor to 1527e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // avoid this if interval storage size becomes a concern. 1537e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // 1547e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // Aside from reordering, we also perform two more pre-processing steps at 1557e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // this stage: 1567e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // 1577e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // 1) scale the color components depending on paint alpha and the requested 1587e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // interpolation space (note: the interval color storage is SkPM4f, but 1597e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // that doesn't necessarily mean the colors are premultiplied; that 1607e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // property is tracked in fColorsArePremul) 1617e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // 1627e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // 2) inject synthetic intervals to support tiling. 1637e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // 1647e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // * for kRepeat, no extra intervals are needed - the iterator just 1657e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // wraps around at the end: 1667e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // 1677e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // ->[P0,P1)->..[Pn-1,Pn)-> 1687e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // 1697e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // * for kClamp, we add two "infinite" intervals before/after: 1707e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // 1717e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // [-/+inf , P0)->[P0 , P1)->..[Pn-1 , Pn)->[Pn , +/-inf) 1727e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // 1737e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // (the iterator should never run off the end in this mode) 1747e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // 1757e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // * for kMirror, we extend the range to [0..2] and add a flipped 1767e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // interval series - then the iterator operates just as in the 1777e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // kRepeat case: 1787e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // 1797e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // ->[P0,P1)->..[Pn-1,Pn)->[2 - Pn,2 - Pn-1)->..[2 - P1,2 - P0)-> 1807e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // 1817e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // TODO: investigate collapsing intervals << 1px. 1827e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 183da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita SkASSERT(count > 0); 184da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita SkASSERT(colors); 1857e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 186da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita fIntervals.reset(); 187da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita 188da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const Sk4f componentScale = premulColors 189da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita ? Sk4f(alpha) 190da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita : Sk4f(1.0f, 1.0f, 1.0f, alpha); 191da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const int first_index = reverse ? count - 1 : 0; 192da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const int last_index = count - 1 - first_index; 1937e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita const SkScalar first_pos = reverse ? SK_Scalar1 : 0; 1947e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita const SkScalar last_pos = SK_Scalar1 - first_pos; 1957e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 196da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita if (tileMode == SkShader::kClamp_TileMode) { 1977e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // synthetic edge interval: -/+inf .. P0 198da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const Sk4f clamp_color = pack_color(colors[first_index], 199da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita premulColors, componentScale); 2008f457591e6a21c240fd2fca56a97281b556ce796fmalita const SkScalar clamp_pos = reverse ? SK_ScalarInfinity : SK_ScalarNegativeInfinity; 2017e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita fIntervals.emplace_back(clamp_color, clamp_pos, 202b931336f3b7913e64602562d7d6d9187086bbd5afmalita clamp_color, first_pos); 203da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita } else if (tileMode == SkShader::kMirror_TileMode && reverse) { 2047e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // synthetic mirror intervals injected before main intervals: (2 .. 1] 205da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita addMirrorIntervals(colors, pos, count, componentScale, premulColors, false, &fIntervals); 2067e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } 2077e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 208da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const IntervalIterator iter(colors, pos, count, reverse); 209da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita iter.iterate([&] (SkColor c0, SkColor c1, SkScalar p0, SkScalar p1) { 2107e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita SkASSERT(fIntervals.empty() || fIntervals.back().fP1 == p0); 2117e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 212da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita fIntervals.emplace_back(pack_color(c0, premulColors, componentScale), p0, 213da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita pack_color(c1, premulColors, componentScale), p1); 2147e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita }); 2157e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 216da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita if (tileMode == SkShader::kClamp_TileMode) { 2177e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // synthetic edge interval: Pn .. +/-inf 218da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const Sk4f clamp_color = pack_color(colors[last_index], premulColors, componentScale); 2198f457591e6a21c240fd2fca56a97281b556ce796fmalita const SkScalar clamp_pos = reverse ? SK_ScalarNegativeInfinity : SK_ScalarInfinity; 2207e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita fIntervals.emplace_back(clamp_color, last_pos, 221b931336f3b7913e64602562d7d6d9187086bbd5afmalita clamp_color, clamp_pos); 222da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita } else if (tileMode == SkShader::kMirror_TileMode && !reverse) { 2237e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // synthetic mirror intervals injected after main intervals: [1 .. 2) 224da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita addMirrorIntervals(colors, pos, count, componentScale, premulColors, true, &fIntervals); 2257e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } 2267e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita} 2277e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 228da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malitaconst Sk4fGradientInterval* Sk4fGradientIntervalBuffer::find(SkScalar t) const { 229da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita // Binary search. 230da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const auto* i0 = fIntervals.begin(); 231da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const auto* i1 = fIntervals.end() - 1; 2327e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 233da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita while (i0 != i1) { 234da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita SkASSERT(i0 < i1); 235da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita SkASSERT(t >= i0->fP0 && t <= i1->fP1); 236da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita 237da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const auto* i = i0 + ((i1 - i0) >> 1); 238da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita 239da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita if (t > i->fP1) { 240da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita i0 = i + 1; 241da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita } else { 242da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita i1 = i; 243cc34176c040c9703e351af7268dfc3a8b3cbf71dfmalita } 244da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita } 245da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita 246da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita SkASSERT(i0->contains(t)); 247da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita return i0; 248da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita} 249da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita 250da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malitaconst Sk4fGradientInterval* Sk4fGradientIntervalBuffer::findNext( 251da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita SkScalar t, const Sk4fGradientInterval* prev, bool increasing) const { 252da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita 253da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita SkASSERT(!prev->contains(t)); 254da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita SkASSERT(prev >= fIntervals.begin() && prev < fIntervals.end()); 255da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita SkASSERT(t >= fIntervals.front().fP0 && t <= fIntervals.back().fP1); 256da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita 257da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const auto* i = prev; 258da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita 259da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita // Use the |increasing| signal to figure which direction we should search for 260da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita // the next interval, then perform a linear search. 261da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita if (increasing) { 262da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita do { 263da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita i += 1; 264da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita if (i >= fIntervals.end()) { 265da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita i = fIntervals.begin(); 266da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita } 267da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita } while (!i->contains(t)); 268da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita } else { 269da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita do { 270da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita i -= 1; 271da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita if (i < fIntervals.begin()) { 272da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita i = fIntervals.end() - 1; 273da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita } 274da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita } while (!i->contains(t)); 275da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita } 276da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita 277da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita return i; 278da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita} 279da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita 280da4545bfc58f8ec19df79f6ae75b7231477973d8Florin MalitaSkGradientShaderBase:: 281da4545bfc58f8ec19df79f6ae75b7231477973d8Florin MalitaGradientShaderBase4fContext::GradientShaderBase4fContext(const SkGradientShaderBase& shader, 282da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const ContextRec& rec) 283da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita : INHERITED(shader, rec) 284da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita , fFlags(this->INHERITED::getFlags()) 285da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita#ifdef SK_SUPPORT_LEGACY_GRADIENT_DITHERING 286da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita , fDither(true) 287da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita#else 288da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita , fDither(rec.fPaint->isDither()) 289da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita#endif 290da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita{ 291da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const SkMatrix& inverse = this->getTotalInverse(); 292da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita fDstToPos.setConcat(shader.fPtsToUnit, inverse); 293da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita fDstToPosProc = fDstToPos.getMapXYProc(); 294da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita fDstToPosClass = static_cast<uint8_t>(INHERITED::ComputeMatrixClass(fDstToPos)); 295da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita 296da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita if (shader.fColorsAreOpaque && this->getPaintAlpha() == SK_AlphaOPAQUE) { 297da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita fFlags |= kOpaqueAlpha_Flag; 298da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita } 299da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita 300da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita fColorsArePremul = 301da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita (shader.fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag) 302da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita || shader.fColorsAreOpaque; 303da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita} 304da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita 305da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malitabool SkGradientShaderBase:: 306da4545bfc58f8ec19df79f6ae75b7231477973d8Florin MalitaGradientShaderBase4fContext::isValid() const { 307da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita return fDstToPos.isFinite(); 3087e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita} 3097e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 3107e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalitavoid SkGradientShaderBase:: 3117e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalitaGradientShaderBase4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) { 3127e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita if (fColorsArePremul) { 313dc6c9bf91c158e89cd9d5ef19dfbf1da98c598a6fmalita this->shadePremulSpan<DstType::L32, ApplyPremul::False>(x, y, dst, count); 3147e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } else { 315dc6c9bf91c158e89cd9d5ef19dfbf1da98c598a6fmalita this->shadePremulSpan<DstType::L32, ApplyPremul::True>(x, y, dst, count); 3167e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } 3177e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita} 3187e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 3197e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalitavoid SkGradientShaderBase:: 3207e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalitaGradientShaderBase4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) { 3217e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita if (fColorsArePremul) { 322dc6c9bf91c158e89cd9d5ef19dfbf1da98c598a6fmalita this->shadePremulSpan<DstType::F32, ApplyPremul::False>(x, y, dst, count); 3237e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } else { 324dc6c9bf91c158e89cd9d5ef19dfbf1da98c598a6fmalita this->shadePremulSpan<DstType::F32, ApplyPremul::True>(x, y, dst, count); 3257e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } 3267e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita} 3277e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 328dc6c9bf91c158e89cd9d5ef19dfbf1da98c598a6fmalitatemplate<DstType dstType, ApplyPremul premul> 3297e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalitavoid SkGradientShaderBase:: 3307e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalitaGradientShaderBase4fContext::shadePremulSpan(int x, int y, 331dc6c9bf91c158e89cd9d5ef19dfbf1da98c598a6fmalita typename DstTraits<dstType, premul>::Type dst[], 3327e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita int count) const { 3337e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita const SkGradientShaderBase& shader = 3347e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita static_cast<const SkGradientShaderBase&>(fShader); 3357e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 3367e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita switch (shader.fTileMode) { 3377e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita case kClamp_TileMode: 338dc6c9bf91c158e89cd9d5ef19dfbf1da98c598a6fmalita this->shadeSpanInternal<dstType, 339a928b288b3001eb34cc3c9caedbaac9a403b05edfmalita premul, 3407e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita kClamp_TileMode>(x, y, dst, count); 3417e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita break; 3427e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita case kRepeat_TileMode: 343dc6c9bf91c158e89cd9d5ef19dfbf1da98c598a6fmalita this->shadeSpanInternal<dstType, 344a928b288b3001eb34cc3c9caedbaac9a403b05edfmalita premul, 3457e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita kRepeat_TileMode>(x, y, dst, count); 3467e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita break; 3477e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita case kMirror_TileMode: 348dc6c9bf91c158e89cd9d5ef19dfbf1da98c598a6fmalita this->shadeSpanInternal<dstType, 349a928b288b3001eb34cc3c9caedbaac9a403b05edfmalita premul, 3507e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita kMirror_TileMode>(x, y, dst, count); 3517e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita break; 3527e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } 3537e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita} 3547e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 355dc6c9bf91c158e89cd9d5ef19dfbf1da98c598a6fmalitatemplate<DstType dstType, ApplyPremul premul, SkShader::TileMode tileMode> 3567e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalitavoid SkGradientShaderBase:: 3577e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalitaGradientShaderBase4fContext::shadeSpanInternal(int x, int y, 358dc6c9bf91c158e89cd9d5ef19dfbf1da98c598a6fmalita typename DstTraits<dstType, premul>::Type dst[], 3597e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita int count) const { 3607e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita static const int kBufSize = 128; 3617e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita SkScalar ts[kBufSize]; 3623a2e45a6ed50c07cb1a710d3f7b74be796e61251fmalita TSampler<dstType, premul, tileMode> sampler(*this); 3637e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 3647e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita SkASSERT(count > 0); 3657e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita do { 3667e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita const int n = SkTMin(kBufSize, count); 3677e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita this->mapTs(x, y, ts, n); 3687e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita for (int i = 0; i < n; ++i) { 3697e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita const Sk4f c = sampler.sample(ts[i]); 370dc6c9bf91c158e89cd9d5ef19dfbf1da98c598a6fmalita DstTraits<dstType, premul>::store(c, dst++); 3717e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } 3727e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita x += n; 3737e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita count -= n; 3747e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } while (count > 0); 3757e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita} 3767e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 3773a2e45a6ed50c07cb1a710d3f7b74be796e61251fmalitatemplate<DstType dstType, ApplyPremul premul, SkShader::TileMode tileMode> 3787e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalitaclass SkGradientShaderBase::GradientShaderBase4fContext::TSampler { 3797e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalitapublic: 3807e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita TSampler(const GradientShaderBase4fContext& ctx) 381da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita : fCtx(ctx) 3825b1a7c21006175d313aad09ef40f9453a21480e2Florin Malita , fInterval(nullptr) { 3835b1a7c21006175d313aad09ef40f9453a21480e2Florin Malita switch (tileMode) { 3845b1a7c21006175d313aad09ef40f9453a21480e2Florin Malita case kClamp_TileMode: 3855b1a7c21006175d313aad09ef40f9453a21480e2Florin Malita fLargestIntervalValue = SK_ScalarInfinity; 3865b1a7c21006175d313aad09ef40f9453a21480e2Florin Malita break; 3875b1a7c21006175d313aad09ef40f9453a21480e2Florin Malita case kRepeat_TileMode: 3885b1a7c21006175d313aad09ef40f9453a21480e2Florin Malita fLargestIntervalValue = nextafterf(1, 0); 3895b1a7c21006175d313aad09ef40f9453a21480e2Florin Malita break; 3905b1a7c21006175d313aad09ef40f9453a21480e2Florin Malita case kMirror_TileMode: 3915b1a7c21006175d313aad09ef40f9453a21480e2Florin Malita fLargestIntervalValue = nextafterf(2.0f, 0); 3925b1a7c21006175d313aad09ef40f9453a21480e2Florin Malita break; 3935b1a7c21006175d313aad09ef40f9453a21480e2Florin Malita } 3947e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } 3957e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 3967e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita Sk4f sample(SkScalar t) { 3978ffb3e5d4c3731d02b3502a89c7a7eb18daf398cfmalita const auto tiled_t = tileProc(t); 3987e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 3997e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita if (!fInterval) { 4007e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // Very first sample => locate the initial interval. 4017e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita // TODO: maybe do this in ctor to remove a branch? 402da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita fInterval = fCtx.fIntervals.find(tiled_t); 4037e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita this->loadIntervalData(fInterval); 4043d1a6bc5f3124dd5cd237ccc39ead26fe4b3355fFlorin Malita } else if (!fInterval->contains(tiled_t)) { 405da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita fInterval = fCtx.fIntervals.findNext(tiled_t, fInterval, t >= fPrevT); 4067e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita this->loadIntervalData(fInterval); 4077e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } 4087e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 4097e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita fPrevT = t; 4107e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita return lerp(tiled_t); 4117e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } 4127e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 4137e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalitaprivate: 4148ffb3e5d4c3731d02b3502a89c7a7eb18daf398cfmalita SkScalar tileProc(SkScalar t) const { 4158ffb3e5d4c3731d02b3502a89c7a7eb18daf398cfmalita switch (tileMode) { 4168ffb3e5d4c3731d02b3502a89c7a7eb18daf398cfmalita case kClamp_TileMode: 4178ffb3e5d4c3731d02b3502a89c7a7eb18daf398cfmalita // synthetic clamp-mode edge intervals allow for a free-floating t: 4188ffb3e5d4c3731d02b3502a89c7a7eb18daf398cfmalita // [-inf..0)[0..1)[1..+inf) 4198ffb3e5d4c3731d02b3502a89c7a7eb18daf398cfmalita return t; 4208ffb3e5d4c3731d02b3502a89c7a7eb18daf398cfmalita case kRepeat_TileMode: 4218ffb3e5d4c3731d02b3502a89c7a7eb18daf398cfmalita // t % 1 (intervals range: [0..1)) 4225b1a7c21006175d313aad09ef40f9453a21480e2Florin Malita // Due to the extra arithmetic, we must clamp to ensure the value remains less than 1. 4235b1a7c21006175d313aad09ef40f9453a21480e2Florin Malita return SkTMin(t - SkScalarFloorToScalar(t), fLargestIntervalValue); 4248ffb3e5d4c3731d02b3502a89c7a7eb18daf398cfmalita case kMirror_TileMode: 4258ffb3e5d4c3731d02b3502a89c7a7eb18daf398cfmalita // t % 2 (synthetic mirror intervals expand the range to [0..2) 4268ffb3e5d4c3731d02b3502a89c7a7eb18daf398cfmalita // Due to the extra arithmetic, we must clamp to ensure the value remains less than 2. 4275b1a7c21006175d313aad09ef40f9453a21480e2Florin Malita return SkTMin(t - SkScalarFloorToScalar(t / 2) * 2, fLargestIntervalValue); 4288ffb3e5d4c3731d02b3502a89c7a7eb18daf398cfmalita } 4298ffb3e5d4c3731d02b3502a89c7a7eb18daf398cfmalita 4308ffb3e5d4c3731d02b3502a89c7a7eb18daf398cfmalita SK_ABORT("Unhandled tile mode."); 4318ffb3e5d4c3731d02b3502a89c7a7eb18daf398cfmalita return 0; 4328ffb3e5d4c3731d02b3502a89c7a7eb18daf398cfmalita } 4338ffb3e5d4c3731d02b3502a89c7a7eb18daf398cfmalita 4347e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita Sk4f lerp(SkScalar t) { 4353d1a6bc5f3124dd5cd237ccc39ead26fe4b3355fFlorin Malita SkASSERT(fInterval->contains(t)); 4367e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita return fCc + fDc * (t - fInterval->fP0); 4377e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } 4387e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 439da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita void loadIntervalData(const Sk4fGradientInterval* i) { 4403a2e45a6ed50c07cb1a710d3f7b74be796e61251fmalita fCc = DstTraits<dstType, premul>::load(i->fC0); 4413a2e45a6ed50c07cb1a710d3f7b74be796e61251fmalita fDc = DstTraits<dstType, premul>::load(i->fDc); 4427e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita } 4437e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita 444da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const GradientShaderBase4fContext& fCtx; 445da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita const Sk4fGradientInterval* fInterval; 446da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita SkScalar fPrevT; 447da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita SkScalar fLargestIntervalValue; 448da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita Sk4f fCc; 449da4545bfc58f8ec19df79f6ae75b7231477973d8Florin Malita Sk4f fDc; 4507e6fcf890a1a63249136b8e6d9f4d5a606ef7508fmalita}; 451