1589708bf7c706348b763e8277004cb160b202bdbrileya@google.com/* 2589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * Copyright 2012 Google Inc. 3589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * 4589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * Use of this source code is governed by a BSD-style license that can be 5589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * found in the LICENSE file. 6589708bf7c706348b763e8277004cb160b202bdbrileya@google.com */ 7589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 8bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita#include "Sk4fLinearGradient.h" 9589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#include "SkLinearGradient.h" 10589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 11bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita// define to test the 4f gradient path 1255430a620762e882c2b3018c57f9a7d51cf16071fmalita// #define FORCE_4F_CONTEXT 13bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita 14f3182ebc72db2bf2e24119d5cea05f270473a491reedstatic const float kInv255Float = 1.0f / 255; 15f3182ebc72db2bf2e24119d5cea05f270473a491reed 16589708bf7c706348b763e8277004cb160b202bdbrileya@google.comstatic inline int repeat_8bits(int x) { 17589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return x & 0xFF; 18589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 19589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 20589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly. 21589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// See http://code.google.com/p/skia/issues/detail?id=472 22589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#if defined(_MSC_VER) && (_MSC_VER >= 1600) 23589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#pragma optimize("", off) 24589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#endif 25589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 26589708bf7c706348b763e8277004cb160b202bdbrileya@google.comstatic inline int mirror_8bits(int x) { 27589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (x & 256) { 28589708bf7c706348b763e8277004cb160b202bdbrileya@google.com x = ~x; 29589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 30589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return x & 255; 31589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 32589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 33589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#if defined(_MSC_VER) && (_MSC_VER >= 1600) 34589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#pragma optimize("", on) 35589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#endif 36589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 37cc695fee81613dc92746c1c6bb27f45cfc6ce73emtkleinstatic SkMatrix pts_to_unit_matrix(const SkPoint pts[2]) { 38589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkVector vec = pts[1] - pts[0]; 39589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkScalar mag = vec.length(); 40589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkScalar inv = mag ? SkScalarInvert(mag) : 0; 41589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 42589708bf7c706348b763e8277004cb160b202bdbrileya@google.com vec.scale(inv); 43cc695fee81613dc92746c1c6bb27f45cfc6ce73emtklein SkMatrix matrix; 44cc695fee81613dc92746c1c6bb27f45cfc6ce73emtklein matrix.setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY); 45cc695fee81613dc92746c1c6bb27f45cfc6ce73emtklein matrix.postTranslate(-pts[0].fX, -pts[0].fY); 46cc695fee81613dc92746c1c6bb27f45cfc6ce73emtklein matrix.postScale(inv, inv); 47cc695fee81613dc92746c1c6bb27f45cfc6ce73emtklein return matrix; 48589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 49589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 5055430a620762e882c2b3018c57f9a7d51cf16071fmalitastatic bool use_4f_context(const SkShader::ContextRec& rec, uint32_t flags) { 5155430a620762e882c2b3018c57f9a7d51cf16071fmalita#ifdef FORCE_4F_CONTEXT 52bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita return true; 53bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita#else 5455430a620762e882c2b3018c57f9a7d51cf16071fmalita // Perspective not supported in 4f yet. 5555430a620762e882c2b3018c57f9a7d51cf16071fmalita if (rec.fMatrix->hasPerspective() 5655430a620762e882c2b3018c57f9a7d51cf16071fmalita || (rec.fLocalMatrix && rec.fLocalMatrix->hasPerspective())) { 5755430a620762e882c2b3018c57f9a7d51cf16071fmalita return false; 5855430a620762e882c2b3018c57f9a7d51cf16071fmalita } 5955430a620762e882c2b3018c57f9a7d51cf16071fmalita 6055430a620762e882c2b3018c57f9a7d51cf16071fmalita return rec.fPreferredDstType == SkShader::ContextRec::kPM4f_DstType 6155430a620762e882c2b3018c57f9a7d51cf16071fmalita || SkToBool(flags & SkLinearGradient::kForce4fContext_PrivateFlag); 62bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita#endif 63bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita} 64bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita 65589708bf7c706348b763e8277004cb160b202bdbrileya@google.com/////////////////////////////////////////////////////////////////////////////// 66589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 67addf2edf3da20f053daa3897cfe2c52d7369a7b1reedSkLinearGradient::SkLinearGradient(const SkPoint pts[2], const Descriptor& desc) 68cc695fee81613dc92746c1c6bb27f45cfc6ce73emtklein : SkGradientShaderBase(desc, pts_to_unit_matrix(pts)) 69589708bf7c706348b763e8277004cb160b202bdbrileya@google.com , fStart(pts[0]) 70cc695fee81613dc92746c1c6bb27f45cfc6ce73emtklein , fEnd(pts[1]) { 71589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 72589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 739fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFlattenable* SkLinearGradient::CreateProc(SkReadBuffer& buffer) { 749fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed DescriptorScope desc; 759fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed if (!desc.unflatten(buffer)) { 7696fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 779fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed } 789fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed SkPoint pts[2]; 799fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed pts[0] = buffer.readPoint(); 809fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed pts[1] = buffer.readPoint(); 819fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed return SkGradientShader::CreateLinear(pts, desc.fColors, desc.fPos, desc.fCount, 829fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed desc.fTileMode, desc.fGradFlags, desc.fLocalMatrix); 839fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed} 84589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 858b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkLinearGradient::flatten(SkWriteBuffer& buffer) const { 86589708bf7c706348b763e8277004cb160b202bdbrileya@google.com this->INHERITED::flatten(buffer); 87589708bf7c706348b763e8277004cb160b202bdbrileya@google.com buffer.writePoint(fStart); 88589708bf7c706348b763e8277004cb160b202bdbrileya@google.com buffer.writePoint(fEnd); 89589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 90589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 9155430a620762e882c2b3018c57f9a7d51cf16071fmalitasize_t SkLinearGradient::contextSize(const ContextRec& rec) const { 9255430a620762e882c2b3018c57f9a7d51cf16071fmalita return use_4f_context(rec, fGradFlags) 93bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita ? sizeof(LinearGradient4fContext) 94bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita : sizeof(LinearGradientContext); 9587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org} 9687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org 97ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.orgSkShader::Context* SkLinearGradient::onCreateContext(const ContextRec& rec, void* storage) const { 9855430a620762e882c2b3018c57f9a7d51cf16071fmalita return use_4f_context(rec, fGradFlags) 99bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita ? static_cast<SkShader::Context*>(new (storage) LinearGradient4fContext(*this, rec)) 100bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita : static_cast<SkShader::Context*>(new (storage) LinearGradientContext(*this, rec)); 10187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org} 10287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org 103f3182ebc72db2bf2e24119d5cea05f270473a491reed// This swizzles SkColor into the same component order as SkPMColor, but does not actually 104f3182ebc72db2bf2e24119d5cea05f270473a491reed// "pre" multiply the color components. 105f3182ebc72db2bf2e24119d5cea05f270473a491reed// 106f3182ebc72db2bf2e24119d5cea05f270473a491reed// This allows us to map directly to Sk4f, and eventually scale down to bytes to output a 107f3182ebc72db2bf2e24119d5cea05f270473a491reed// SkPMColor from the floats, without having to swizzle each time. 108f3182ebc72db2bf2e24119d5cea05f270473a491reed// 109f3182ebc72db2bf2e24119d5cea05f270473a491reedstatic uint32_t SkSwizzle_Color_to_PMColor(SkColor c) { 110f3182ebc72db2bf2e24119d5cea05f270473a491reed return SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), SkColorGetG(c), SkColorGetB(c)); 111f3182ebc72db2bf2e24119d5cea05f270473a491reed} 112f3182ebc72db2bf2e24119d5cea05f270473a491reed 11387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkLinearGradient::LinearGradientContext::LinearGradientContext( 114f3182ebc72db2bf2e24119d5cea05f270473a491reed const SkLinearGradient& shader, const ContextRec& ctx) 115f3182ebc72db2bf2e24119d5cea05f270473a491reed : INHERITED(shader, ctx) 11687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org{ 117f3182ebc72db2bf2e24119d5cea05f270473a491reed // setup for Sk4f 118f3182ebc72db2bf2e24119d5cea05f270473a491reed int count = shader.fColorCount; 119f3182ebc72db2bf2e24119d5cea05f270473a491reed fRecs.setCount(count); 120f3182ebc72db2bf2e24119d5cea05f270473a491reed Rec* rec = fRecs.begin(); 121f3182ebc72db2bf2e24119d5cea05f270473a491reed if (shader.fOrigPos) { 122f3182ebc72db2bf2e24119d5cea05f270473a491reed rec[0].fPos = 0; 123f3182ebc72db2bf2e24119d5cea05f270473a491reed SkDEBUGCODE(rec[0].fPosScale = SK_FloatNaN;) // should never get used 124f3182ebc72db2bf2e24119d5cea05f270473a491reed for (int i = 1; i < count; ++i) { 125f3182ebc72db2bf2e24119d5cea05f270473a491reed rec[i].fPos = SkTPin(shader.fOrigPos[i], rec[i - 1].fPos, 1.0f); 126f2b8662b5c73e03648ed1a154b717e354753a0e1lsalzman float diff = rec[i].fPos - rec[i - 1].fPos; 127f2b8662b5c73e03648ed1a154b717e354753a0e1lsalzman if (diff > 0) { 128f2b8662b5c73e03648ed1a154b717e354753a0e1lsalzman rec[i].fPosScale = 1.0f / diff; 129f2b8662b5c73e03648ed1a154b717e354753a0e1lsalzman } else { 130f2b8662b5c73e03648ed1a154b717e354753a0e1lsalzman rec[i].fPosScale = 0; 131f2b8662b5c73e03648ed1a154b717e354753a0e1lsalzman } 132f3182ebc72db2bf2e24119d5cea05f270473a491reed } 133f3182ebc72db2bf2e24119d5cea05f270473a491reed rec[count - 1].fPos = 1; // overwrite the last value just to be sure we end at 1.0 134f3182ebc72db2bf2e24119d5cea05f270473a491reed } else { 135f3182ebc72db2bf2e24119d5cea05f270473a491reed // no pos specified, so we compute evenly spaced values 136f3182ebc72db2bf2e24119d5cea05f270473a491reed const float scale = float(count - 1); 137f3182ebc72db2bf2e24119d5cea05f270473a491reed float invScale = 1.0f / scale; 138f3182ebc72db2bf2e24119d5cea05f270473a491reed for (int i = 0; i < count; ++i) { 139f3182ebc72db2bf2e24119d5cea05f270473a491reed rec[i].fPos = i * invScale; 140f3182ebc72db2bf2e24119d5cea05f270473a491reed rec[i].fPosScale = scale; 141f3182ebc72db2bf2e24119d5cea05f270473a491reed } 142f3182ebc72db2bf2e24119d5cea05f270473a491reed } 143f3182ebc72db2bf2e24119d5cea05f270473a491reed 144f3182ebc72db2bf2e24119d5cea05f270473a491reed fApplyAlphaAfterInterp = true; 145f3182ebc72db2bf2e24119d5cea05f270473a491reed if ((shader.getGradFlags() & SkGradientShader::kInterpolateColorsInPremul_Flag) || 146f3182ebc72db2bf2e24119d5cea05f270473a491reed shader.colorsAreOpaque()) 147f3182ebc72db2bf2e24119d5cea05f270473a491reed { 148f3182ebc72db2bf2e24119d5cea05f270473a491reed fApplyAlphaAfterInterp = false; 149f3182ebc72db2bf2e24119d5cea05f270473a491reed } 150f3182ebc72db2bf2e24119d5cea05f270473a491reed 151f3182ebc72db2bf2e24119d5cea05f270473a491reed if (fApplyAlphaAfterInterp) { 152f3182ebc72db2bf2e24119d5cea05f270473a491reed // Our fColor values are in PMColor order, but are still unpremultiplied, allowing us to 153f3182ebc72db2bf2e24119d5cea05f270473a491reed // interpolate in unpremultiplied space first, and then scale by alpha right before we 154f3182ebc72db2bf2e24119d5cea05f270473a491reed // convert to SkPMColor bytes. 155f3182ebc72db2bf2e24119d5cea05f270473a491reed const float paintAlpha = ctx.fPaint->getAlpha() * kInv255Float; 156f3182ebc72db2bf2e24119d5cea05f270473a491reed const Sk4f scale(1, 1, 1, paintAlpha); 157f3182ebc72db2bf2e24119d5cea05f270473a491reed for (int i = 0; i < count; ++i) { 158f3182ebc72db2bf2e24119d5cea05f270473a491reed uint32_t c = SkSwizzle_Color_to_PMColor(shader.fOrigColors[i]); 159507ef6d68115ae9e6d884bb36436a1463523d893mtklein rec[i].fColor = SkNx_cast<float>(Sk4b::Load(&c)) * scale; 160f3182ebc72db2bf2e24119d5cea05f270473a491reed if (i > 0) { 161f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(rec[i - 1].fPos <= rec[i].fPos); 162f3182ebc72db2bf2e24119d5cea05f270473a491reed } 163f3182ebc72db2bf2e24119d5cea05f270473a491reed } 164f3182ebc72db2bf2e24119d5cea05f270473a491reed } else { 165f3182ebc72db2bf2e24119d5cea05f270473a491reed // Our fColor values are premultiplied, so converting to SkPMColor is just a matter 166f3182ebc72db2bf2e24119d5cea05f270473a491reed // of converting the floats down to bytes. 167f3182ebc72db2bf2e24119d5cea05f270473a491reed unsigned alphaScale = ctx.fPaint->getAlpha() + (ctx.fPaint->getAlpha() >> 7); 168f3182ebc72db2bf2e24119d5cea05f270473a491reed for (int i = 0; i < count; ++i) { 169f3182ebc72db2bf2e24119d5cea05f270473a491reed SkPMColor pmc = SkPreMultiplyColor(shader.fOrigColors[i]); 170f3182ebc72db2bf2e24119d5cea05f270473a491reed pmc = SkAlphaMulQ(pmc, alphaScale); 171507ef6d68115ae9e6d884bb36436a1463523d893mtklein rec[i].fColor = SkNx_cast<float>(Sk4b::Load(&pmc)); 172f3182ebc72db2bf2e24119d5cea05f270473a491reed if (i > 0) { 173f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(rec[i - 1].fPos <= rec[i].fPos); 174f3182ebc72db2bf2e24119d5cea05f270473a491reed } 175f3182ebc72db2bf2e24119d5cea05f270473a491reed } 176f3182ebc72db2bf2e24119d5cea05f270473a491reed } 177589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 178589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 179589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#define NO_CHECK_ITER \ 180589708bf7c706348b763e8277004cb160b202bdbrileya@google.com do { \ 181caf7e9313b52f78b53ff7d478f9cc41a1f6a85ffreed unsigned fi = SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache32Shift; \ 182589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(fi <= 0xFF); \ 183589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fx += dx; \ 184589708bf7c706348b763e8277004cb160b202bdbrileya@google.com *dstC++ = cache[toggle + fi]; \ 18555853db3cce9539746fe202519a534c85ecdf62creed@google.com toggle = next_dither_toggle(toggle); \ 186589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } while (0) 187589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 188589708bf7c706348b763e8277004cb160b202bdbrileya@google.comnamespace { 189589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 190caf7e9313b52f78b53ff7d478f9cc41a1f6a85ffreedtypedef void (*LinearShadeProc)(TileProc proc, SkGradFixed dx, SkGradFixed fx, 191589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkPMColor* dstC, const SkPMColor* cache, 192589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int toggle, int count); 193589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 194589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// Linear interpolation (lerp) is unnecessary if there are no sharp 195589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// discontinuities in the gradient - which must be true if there are 196589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// only 2 colors - but it's cheap. 197caf7e9313b52f78b53ff7d478f9cc41a1f6a85ffreedvoid shadeSpan_linear_vertical_lerp(TileProc proc, SkGradFixed dx, SkGradFixed fx, 198589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkPMColor* SK_RESTRICT dstC, 199589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const SkPMColor* SK_RESTRICT cache, 200589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int toggle, int count) { 201589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // We're a vertical gradient, so no change in a span. 202589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // If colors change sharply across the gradient, dithering is 203589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // insufficient (it subsamples the color space) and we need to lerp. 204caf7e9313b52f78b53ff7d478f9cc41a1f6a85ffreed unsigned fullIndex = proc(SkGradFixedToFixed(fx)); 2053c2102c2d2cdad328a0d87329e1a973f12775836reed@google.com unsigned fi = fullIndex >> SkGradientShaderBase::kCache32Shift; 2063c2102c2d2cdad328a0d87329e1a973f12775836reed@google.com unsigned remainder = fullIndex & ((1 << SkGradientShaderBase::kCache32Shift) - 1); 2079dde018753c4d16cdc60c008c32bb0b573a82944skia.committer@gmail.com 2083c2102c2d2cdad328a0d87329e1a973f12775836reed@google.com int index0 = fi + toggle; 2093c2102c2d2cdad328a0d87329e1a973f12775836reed@google.com int index1 = index0; 2103c2102c2d2cdad328a0d87329e1a973f12775836reed@google.com if (fi < SkGradientShaderBase::kCache32Count - 1) { 2113c2102c2d2cdad328a0d87329e1a973f12775836reed@google.com index1 += 1; 2123c2102c2d2cdad328a0d87329e1a973f12775836reed@google.com } 2133c2102c2d2cdad328a0d87329e1a973f12775836reed@google.com SkPMColor lerp = SkFastFourByteInterp(cache[index1], cache[index0], remainder); 2143c2102c2d2cdad328a0d87329e1a973f12775836reed@google.com index0 ^= SkGradientShaderBase::kDitherStride32; 2153c2102c2d2cdad328a0d87329e1a973f12775836reed@google.com index1 ^= SkGradientShaderBase::kDitherStride32; 2163c2102c2d2cdad328a0d87329e1a973f12775836reed@google.com SkPMColor dlerp = SkFastFourByteInterp(cache[index1], cache[index0], remainder); 217589708bf7c706348b763e8277004cb160b202bdbrileya@google.com sk_memset32_dither(dstC, lerp, dlerp, count); 218589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 219589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 220caf7e9313b52f78b53ff7d478f9cc41a1f6a85ffreedvoid shadeSpan_linear_clamp(TileProc proc, SkGradFixed dx, SkGradFixed fx, 221589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkPMColor* SK_RESTRICT dstC, 222589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const SkPMColor* SK_RESTRICT cache, 223589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int toggle, int count) { 224589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkClampRange range; 2253c2102c2d2cdad328a0d87329e1a973f12775836reed@google.com range.init(fx, dx, count, 0, SkGradientShaderBase::kCache32Count - 1); 2269d91eb313623dca16bc988bad2e8b01712e4c578reed range.validate(count); 227589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 228589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if ((count = range.fCount0) > 0) { 229589708bf7c706348b763e8277004cb160b202bdbrileya@google.com sk_memset32_dither(dstC, 230589708bf7c706348b763e8277004cb160b202bdbrileya@google.com cache[toggle + range.fV0], 23155853db3cce9539746fe202519a534c85ecdf62creed@google.com cache[next_dither_toggle(toggle) + range.fV0], 232589708bf7c706348b763e8277004cb160b202bdbrileya@google.com count); 233589708bf7c706348b763e8277004cb160b202bdbrileya@google.com dstC += count; 234589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 235589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if ((count = range.fCount1) > 0) { 236589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int unroll = count >> 3; 237589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fx = range.fFx1; 238589708bf7c706348b763e8277004cb160b202bdbrileya@google.com for (int i = 0; i < unroll; i++) { 239589708bf7c706348b763e8277004cb160b202bdbrileya@google.com NO_CHECK_ITER; NO_CHECK_ITER; 240589708bf7c706348b763e8277004cb160b202bdbrileya@google.com NO_CHECK_ITER; NO_CHECK_ITER; 241589708bf7c706348b763e8277004cb160b202bdbrileya@google.com NO_CHECK_ITER; NO_CHECK_ITER; 242589708bf7c706348b763e8277004cb160b202bdbrileya@google.com NO_CHECK_ITER; NO_CHECK_ITER; 243589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 244589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if ((count &= 7) > 0) { 245589708bf7c706348b763e8277004cb160b202bdbrileya@google.com do { 246589708bf7c706348b763e8277004cb160b202bdbrileya@google.com NO_CHECK_ITER; 247589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } while (--count != 0); 248589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 249589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 250589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if ((count = range.fCount2) > 0) { 251589708bf7c706348b763e8277004cb160b202bdbrileya@google.com sk_memset32_dither(dstC, 252589708bf7c706348b763e8277004cb160b202bdbrileya@google.com cache[toggle + range.fV1], 25355853db3cce9539746fe202519a534c85ecdf62creed@google.com cache[next_dither_toggle(toggle) + range.fV1], 254589708bf7c706348b763e8277004cb160b202bdbrileya@google.com count); 255589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 256589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 257589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 258caf7e9313b52f78b53ff7d478f9cc41a1f6a85ffreedvoid shadeSpan_linear_mirror(TileProc proc, SkGradFixed dx, SkGradFixed fx, 259589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkPMColor* SK_RESTRICT dstC, 260589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const SkPMColor* SK_RESTRICT cache, 261589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int toggle, int count) { 262589708bf7c706348b763e8277004cb160b202bdbrileya@google.com do { 263caf7e9313b52f78b53ff7d478f9cc41a1f6a85ffreed unsigned fi = mirror_8bits(SkGradFixedToFixed(fx) >> 8); 264589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(fi <= 0xFF); 265589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fx += dx; 266589708bf7c706348b763e8277004cb160b202bdbrileya@google.com *dstC++ = cache[toggle + fi]; 26755853db3cce9539746fe202519a534c85ecdf62creed@google.com toggle = next_dither_toggle(toggle); 268589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } while (--count != 0); 269589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 270589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 271caf7e9313b52f78b53ff7d478f9cc41a1f6a85ffreedvoid shadeSpan_linear_repeat(TileProc proc, SkGradFixed dx, SkGradFixed fx, 272589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkPMColor* SK_RESTRICT dstC, 273589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const SkPMColor* SK_RESTRICT cache, 274589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int toggle, int count) { 275589708bf7c706348b763e8277004cb160b202bdbrileya@google.com do { 276caf7e9313b52f78b53ff7d478f9cc41a1f6a85ffreed unsigned fi = repeat_8bits(SkGradFixedToFixed(fx) >> 8); 277589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(fi <= 0xFF); 278589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fx += dx; 279589708bf7c706348b763e8277004cb160b202bdbrileya@google.com *dstC++ = cache[toggle + fi]; 28055853db3cce9539746fe202519a534c85ecdf62creed@google.com toggle = next_dither_toggle(toggle); 281589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } while (--count != 0); 282589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 283589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 284589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 285589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 28687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgvoid SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, 28787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org int count) { 288589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(count > 0); 28987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org const SkLinearGradient& linearGradient = static_cast<const SkLinearGradient&>(fShader); 29087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org 291c2e0ac4fce5bfe5bac9f2cb1ebd3aea3a8900fb1fmalita// Only use the Sk4f impl when known to be fast. 292c2e0ac4fce5bfe5bac9f2cb1ebd3aea3a8900fb1fmalita#if defined(SKNX_IS_FAST) 293f3182ebc72db2bf2e24119d5cea05f270473a491reed if (SkShader::kClamp_TileMode == linearGradient.fTileMode && 294f3182ebc72db2bf2e24119d5cea05f270473a491reed kLinear_MatrixClass == fDstToIndexClass) 295f3182ebc72db2bf2e24119d5cea05f270473a491reed { 296f3182ebc72db2bf2e24119d5cea05f270473a491reed this->shade4_clamp(x, y, dstC, count); 297f3182ebc72db2bf2e24119d5cea05f270473a491reed return; 298f3182ebc72db2bf2e24119d5cea05f270473a491reed } 299f3182ebc72db2bf2e24119d5cea05f270473a491reed#endif 300f3182ebc72db2bf2e24119d5cea05f270473a491reed 301589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkPoint srcPt; 302589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkMatrix::MapXYProc dstProc = fDstToIndexProc; 30387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org TileProc proc = linearGradient.fTileProc; 30487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); 30555853db3cce9539746fe202519a534c85ecdf62creed@google.com int toggle = init_dither_toggle(x, y); 306589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 307589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fDstToIndexClass != kPerspective_MatrixClass) { 308589708bf7c706348b763e8277004cb160b202bdbrileya@google.com dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, 309589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 310caf7e9313b52f78b53ff7d478f9cc41a1f6a85ffreed SkGradFixed dx, fx = SkScalarToGradFixed(srcPt.fX); 311589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 312589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fDstToIndexClass == kFixedStepInX_MatrixClass) { 3138e17556349132a46c02fbabcaf74b63f521528e0benjaminwagner const auto step = fDstToIndex.fixedStepInX(SkIntToScalar(y)); 314caf7e9313b52f78b53ff7d478f9cc41a1f6a85ffreed // todo: do we need a real/high-precision value for dx here? 3158e17556349132a46c02fbabcaf74b63f521528e0benjaminwagner dx = SkScalarToGradFixed(step.fX); 316589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } else { 317589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(fDstToIndexClass == kLinear_MatrixClass); 318caf7e9313b52f78b53ff7d478f9cc41a1f6a85ffreed dx = SkScalarToGradFixed(fDstToIndex.getScaleX()); 319589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 320589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 321589708bf7c706348b763e8277004cb160b202bdbrileya@google.com LinearShadeProc shadeProc = shadeSpan_linear_repeat; 32253009ba7019cbe86a6ab2aa5b7ae5893e4efffbdreed@google.com if (0 == dx) { 323589708bf7c706348b763e8277004cb160b202bdbrileya@google.com shadeProc = shadeSpan_linear_vertical_lerp; 32487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org } else if (SkShader::kClamp_TileMode == linearGradient.fTileMode) { 325589708bf7c706348b763e8277004cb160b202bdbrileya@google.com shadeProc = shadeSpan_linear_clamp; 32687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org } else if (SkShader::kMirror_TileMode == linearGradient.fTileMode) { 327589708bf7c706348b763e8277004cb160b202bdbrileya@google.com shadeProc = shadeSpan_linear_mirror; 328589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } else { 32987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org SkASSERT(SkShader::kRepeat_TileMode == linearGradient.fTileMode); 330589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 331589708bf7c706348b763e8277004cb160b202bdbrileya@google.com (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count); 332589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } else { 333589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkScalar dstX = SkIntToScalar(x); 334589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkScalar dstY = SkIntToScalar(y); 335589708bf7c706348b763e8277004cb160b202bdbrileya@google.com do { 336589708bf7c706348b763e8277004cb160b202bdbrileya@google.com dstProc(fDstToIndex, dstX, dstY, &srcPt); 337589708bf7c706348b763e8277004cb160b202bdbrileya@google.com unsigned fi = proc(SkScalarToFixed(srcPt.fX)); 338589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(fi <= 0xFFFF); 339589708bf7c706348b763e8277004cb160b202bdbrileya@google.com *dstC++ = cache[toggle + (fi >> kCache32Shift)]; 34055853db3cce9539746fe202519a534c85ecdf62creed@google.com toggle = next_dither_toggle(toggle); 341589708bf7c706348b763e8277004cb160b202bdbrileya@google.com dstX += SK_Scalar1; 342589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } while (--count != 0); 343589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 344589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 345589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 346589708bf7c706348b763e8277004cb160b202bdbrileya@google.comSkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const { 347589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (info) { 348589708bf7c706348b763e8277004cb160b202bdbrileya@google.com commonAsAGradient(info); 349589708bf7c706348b763e8277004cb160b202bdbrileya@google.com info->fPoint[0] = fStart; 350589708bf7c706348b763e8277004cb160b202bdbrileya@google.com info->fPoint[1] = fEnd; 351589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 352589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return kLinear_GradientType; 353589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 354589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 355cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#if SK_SUPPORT_GPU 356cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com 3577ea439b2203855db97330b25945b87dd4b170b8begdaniel#include "glsl/GrGLSLCaps.h" 3587ea439b2203855db97330b25945b87dd4b170b8begdaniel#include "glsl/GrGLSLFragmentShaderBuilder.h" 3599de5b514d38c5b36066bcdc14fba2f7e5196d372dandov#include "SkGr.h" 3602eaaefd7e6a58339b3f93333f1e9cc92252cc303bsalomon@google.com 361d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com///////////////////////////////////////////////////////////////////// 362d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 3630707c29413a5a3cc1c2d14b8c65b3692af5c7411bsalomon@google.comclass GrGLLinearGradient : public GrGLGradientEffect { 364d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.compublic: 365d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 366eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt GrGLLinearGradient(const GrProcessor&) {} 367d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 368d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com virtual ~GrGLLinearGradient() { } 369d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 3707c157a988845fb00f9024d6db6dda142c3458033wangyix virtual void emitCode(EmitArgs&) override; 371f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com 372cfc18867d982119d9dc2888bf09f1093012daaddjvanverth static void GenKey(const GrProcessor& processor, const GrGLSLCaps&, GrProcessorKeyBuilder* b) { 373b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt b->add32(GenBaseGradientKey(processor)); 374d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com } 375d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 376d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.comprivate: 377d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 3780707c29413a5a3cc1c2d14b8c65b3692af5c7411bsalomon@google.com typedef GrGLGradientEffect INHERITED; 379d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com}; 380d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 38198e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com///////////////////////////////////////////////////////////////////// 38298e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com 38398e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.comclass GrLinearGradient : public GrGradientEffect { 38498e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.compublic: 38598e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com 386b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt static GrFragmentProcessor* Create(GrContext* ctx, 387b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt const SkLinearGradient& shader, 388b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt const SkMatrix& matrix, 389b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt SkShader::TileMode tm) { 3904a339529612a43871d021877e58698e067d6c4cdbsalomon return new GrLinearGradient(ctx, shader, matrix, tm); 3910ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com } 3920ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com 39398e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com virtual ~GrLinearGradient() { } 39498e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com 39536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein const char* name() const override { return "Linear Gradient"; } 396eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt 39798e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.comprivate: 3980ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com GrLinearGradient(GrContext* ctx, 3990ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com const SkLinearGradient& shader, 4000ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com const SkMatrix& matrix, 4010ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com SkShader::TileMode tm) 4024a339529612a43871d021877e58698e067d6c4cdbsalomon : INHERITED(ctx, shader, matrix, tm) { 403eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt this->initClassID<GrLinearGradient>(); 404eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt } 4054b3050b410254d0cb38df9a30ae2e209124fa1a2wangyix 40657d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { 407385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanary return new GrGLLinearGradient(*this); 408b1daa86732fe70aa4630c89d75ff0fd619d77c77wangyix } 409b1daa86732fe70aa4630c89d75ff0fd619d77c77wangyix 41057d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps, 41157d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel GrProcessorKeyBuilder* b) const override { 4124b3050b410254d0cb38df9a30ae2e209124fa1a2wangyix GrGLLinearGradient::GenKey(*this, caps, b); 4134b3050b410254d0cb38df9a30ae2e209124fa1a2wangyix } 4144b3050b410254d0cb38df9a30ae2e209124fa1a2wangyix 415b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt GR_DECLARE_FRAGMENT_PROCESSOR_TEST; 41698e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com 41798e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com typedef GrGradientEffect INHERITED; 41898e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com}; 41998e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com 42098e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com///////////////////////////////////////////////////////////////////// 42198e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com 422b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrLinearGradient); 423d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com 424c21b09eec91c9e263cb0b88467ea44e348ed4962bsalomonconst GrFragmentProcessor* GrLinearGradient::TestCreate(GrProcessorTestData* d) { 4250067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt SkPoint points[] = {{d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()}, 4260067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()}}; 427d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com 428d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com SkColor colors[kMaxRandomGradientColors]; 429d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com SkScalar stopsArray[kMaxRandomGradientColors]; 430d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com SkScalar* stops = stopsArray; 431d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com SkShader::TileMode tm; 4320067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm); 433d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com SkAutoTUnref<SkShader> shader(SkGradientShader::CreateLinear(points, 434d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com colors, stops, colorCount, 435d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com tm)); 436c21b09eec91c9e263cb0b88467ea44e348ed4962bsalomon const GrFragmentProcessor* fp = shader->asFragmentProcessor(d->fContext, 4374a339529612a43871d021877e58698e067d6c4cdbsalomon GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality); 438c21b09eec91c9e263cb0b88467ea44e348ed4962bsalomon GrAlwaysAssert(fp); 439b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt return fp; 440d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com} 441d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com 442d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com///////////////////////////////////////////////////////////////////// 443d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com 4447c157a988845fb00f9024d6db6dda142c3458033wangyixvoid GrGLLinearGradient::emitCode(EmitArgs& args) { 4457c157a988845fb00f9024d6db6dda142c3458033wangyix const GrLinearGradient& ge = args.fFp.cast<GrLinearGradient>(); 4467ea439b2203855db97330b25945b87dd4b170b8begdaniel this->emitUniforms(args.fUniformHandler, ge); 4474ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel SkString t = args.fFragBuilder->ensureFSCoords2D(args.fCoords, 0); 448d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com t.append(".x"); 4497ea439b2203855db97330b25945b87dd4b170b8begdaniel this->emitColor(args.fFragBuilder, 4507ea439b2203855db97330b25945b87dd4b170b8begdaniel args.fUniformHandler, 451a2e3e0f7f8ceed2ab152428d7ee2812ad8c842c3egdaniel args.fGLSLCaps, 4524ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel ge, t.c_str(), 4534ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel args.fOutputColor, 4544ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel args.fInputColor, 4557c157a988845fb00f9024d6db6dda142c3458033wangyix args.fSamplers); 456d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com} 457d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 458d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com///////////////////////////////////////////////////////////////////// 459d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 460c21b09eec91c9e263cb0b88467ea44e348ed4962bsalomonconst GrFragmentProcessor* SkLinearGradient::asFragmentProcessor( 461c21b09eec91c9e263cb0b88467ea44e348ed4962bsalomon GrContext* context, 462c21b09eec91c9e263cb0b88467ea44e348ed4962bsalomon const SkMatrix& viewm, 463c21b09eec91c9e263cb0b88467ea44e348ed4962bsalomon const SkMatrix* localMatrix, 4644a339529612a43871d021877e58698e067d6c4cdbsalomon SkFilterQuality) const { 46549f085dddff10473b6ebf832a974288300224e60bsalomon SkASSERT(context); 4663f3b3d003527861dc0bd89733857576408906431mtklein 467dfdb7e5240276493077b7c6e1f3cc8b8a0e195babsalomon@google.com SkMatrix matrix; 468f94b3a4cebd4adab09c40ebe23c02a615e10c394bsalomon@google.com if (!this->getLocalMatrix().invert(&matrix)) { 469c21b09eec91c9e263cb0b88467ea44e348ed4962bsalomon return nullptr; 470dfdb7e5240276493077b7c6e1f3cc8b8a0e195babsalomon@google.com } 47196fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org if (localMatrix) { 47296fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org SkMatrix inv; 47396fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org if (!localMatrix->invert(&inv)) { 474c21b09eec91c9e263cb0b88467ea44e348ed4962bsalomon return nullptr; 47596fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org } 47696fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org matrix.postConcat(inv); 47796fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org } 478f94b3a4cebd4adab09c40ebe23c02a615e10c394bsalomon@google.com matrix.postConcat(fPtsToUnit); 4793f3b3d003527861dc0bd89733857576408906431mtklein 480c21b09eec91c9e263cb0b88467ea44e348ed4962bsalomon SkAutoTUnref<const GrFragmentProcessor> inner( 4814a339529612a43871d021877e58698e067d6c4cdbsalomon GrLinearGradient::Create(context, *this, matrix, fTileMode)); 482f1b7a1d82860e106ed7d3e0e876419e65783fb84bsalomon return GrFragmentProcessor::MulOutputByInputAlpha(inner); 483d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com} 484d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 485cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com 486cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#endif 48776f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com 4880f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org#ifndef SK_IGNORE_TO_STRING 48976f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.comvoid SkLinearGradient::toString(SkString* str) const { 49076f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->append("SkLinearGradient ("); 49176f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com 49276f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->appendf("start: (%f, %f)", fStart.fX, fStart.fY); 49376f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->appendf(" end: (%f, %f) ", fEnd.fX, fEnd.fY); 49476f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com 49576f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com this->INHERITED::toString(str); 49676f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com 49776f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->append(")"); 49876f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com} 49976f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com#endif 500f3182ebc72db2bf2e24119d5cea05f270473a491reed 501f3182ebc72db2bf2e24119d5cea05f270473a491reed/////////////////////////////////////////////////////////////////////////////////////////////////// 502f3182ebc72db2bf2e24119d5cea05f270473a491reed 503f3182ebc72db2bf2e24119d5cea05f270473a491reed#include "SkNx.h" 504f3182ebc72db2bf2e24119d5cea05f270473a491reed 505f3182ebc72db2bf2e24119d5cea05f270473a491reedstatic const SkLinearGradient::LinearGradientContext::Rec* 506f3182ebc72db2bf2e24119d5cea05f270473a491reedfind_forward(const SkLinearGradient::LinearGradientContext::Rec rec[], float tiledX) { 507f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(tiledX >= 0 && tiledX <= 1); 508f3182ebc72db2bf2e24119d5cea05f270473a491reed 509f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(rec[0].fPos >= 0 && rec[0].fPos <= 1); 510f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(rec[1].fPos >= 0 && rec[1].fPos <= 1); 511f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(rec[0].fPos <= rec[1].fPos); 512f3182ebc72db2bf2e24119d5cea05f270473a491reed rec += 1; 513f2b8662b5c73e03648ed1a154b717e354753a0e1lsalzman while (rec->fPos < tiledX || rec->fPosScale == 0) { 514f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(rec[0].fPos >= 0 && rec[0].fPos <= 1); 515f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(rec[1].fPos >= 0 && rec[1].fPos <= 1); 516f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(rec[0].fPos <= rec[1].fPos); 517f3182ebc72db2bf2e24119d5cea05f270473a491reed rec += 1; 518f3182ebc72db2bf2e24119d5cea05f270473a491reed } 519f3182ebc72db2bf2e24119d5cea05f270473a491reed return rec - 1; 520f3182ebc72db2bf2e24119d5cea05f270473a491reed} 521f3182ebc72db2bf2e24119d5cea05f270473a491reed 522f3182ebc72db2bf2e24119d5cea05f270473a491reedstatic const SkLinearGradient::LinearGradientContext::Rec* 523f3182ebc72db2bf2e24119d5cea05f270473a491reedfind_backward(const SkLinearGradient::LinearGradientContext::Rec rec[], float tiledX) { 524f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(tiledX >= 0 && tiledX <= 1); 525f3182ebc72db2bf2e24119d5cea05f270473a491reed 526f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(rec[0].fPos >= 0 && rec[0].fPos <= 1); 527f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(rec[1].fPos >= 0 && rec[1].fPos <= 1); 528f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(rec[0].fPos <= rec[1].fPos); 529f2b8662b5c73e03648ed1a154b717e354753a0e1lsalzman while (tiledX < rec->fPos || rec[1].fPosScale == 0) { 530f3182ebc72db2bf2e24119d5cea05f270473a491reed rec -= 1; 531f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(rec[0].fPos >= 0 && rec[0].fPos <= 1); 532f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(rec[1].fPos >= 0 && rec[1].fPos <= 1); 533f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(rec[0].fPos <= rec[1].fPos); 534f3182ebc72db2bf2e24119d5cea05f270473a491reed } 535f3182ebc72db2bf2e24119d5cea05f270473a491reed return rec; 536f3182ebc72db2bf2e24119d5cea05f270473a491reed} 537f3182ebc72db2bf2e24119d5cea05f270473a491reed 538f3182ebc72db2bf2e24119d5cea05f270473a491reedtemplate <bool apply_alpha> SkPMColor trunc_from_255(const Sk4f& x) { 539f3182ebc72db2bf2e24119d5cea05f270473a491reed SkPMColor c; 540507ef6d68115ae9e6d884bb36436a1463523d893mtklein SkNx_cast<uint8_t>(x).store(&c); 541f3182ebc72db2bf2e24119d5cea05f270473a491reed if (apply_alpha) { 542f3182ebc72db2bf2e24119d5cea05f270473a491reed c = SkPreMultiplyARGB(SkGetPackedA32(c), SkGetPackedR32(c), 543f3182ebc72db2bf2e24119d5cea05f270473a491reed SkGetPackedG32(c), SkGetPackedB32(c)); 544f3182ebc72db2bf2e24119d5cea05f270473a491reed } 545f3182ebc72db2bf2e24119d5cea05f270473a491reed return c; 546f3182ebc72db2bf2e24119d5cea05f270473a491reed} 547f3182ebc72db2bf2e24119d5cea05f270473a491reed 548f3182ebc72db2bf2e24119d5cea05f270473a491reedtemplate <bool apply_alpha> void fill(SkPMColor dst[], int count, 549f3182ebc72db2bf2e24119d5cea05f270473a491reed const Sk4f& c4, const Sk4f& c4other) { 550f3182ebc72db2bf2e24119d5cea05f270473a491reed sk_memset32_dither(dst, trunc_from_255<apply_alpha>(c4), 551f3182ebc72db2bf2e24119d5cea05f270473a491reed trunc_from_255<apply_alpha>(c4other), count); 552f3182ebc72db2bf2e24119d5cea05f270473a491reed} 553f3182ebc72db2bf2e24119d5cea05f270473a491reed 554f3182ebc72db2bf2e24119d5cea05f270473a491reedtemplate <bool apply_alpha> void fill(SkPMColor dst[], int count, const Sk4f& c4) { 555f3182ebc72db2bf2e24119d5cea05f270473a491reed // Assumes that c4 does not need to be dithered. 556f3182ebc72db2bf2e24119d5cea05f270473a491reed sk_memset32(dst, trunc_from_255<apply_alpha>(c4), count); 557f3182ebc72db2bf2e24119d5cea05f270473a491reed} 558f3182ebc72db2bf2e24119d5cea05f270473a491reed 559f3182ebc72db2bf2e24119d5cea05f270473a491reed/* 560f3182ebc72db2bf2e24119d5cea05f270473a491reed * TODOs 561f3182ebc72db2bf2e24119d5cea05f270473a491reed * 562f3182ebc72db2bf2e24119d5cea05f270473a491reed * - tilemodes 563f3182ebc72db2bf2e24119d5cea05f270473a491reed * - interp before or after premul 564f3182ebc72db2bf2e24119d5cea05f270473a491reed * - perspective 565f3182ebc72db2bf2e24119d5cea05f270473a491reed * - optimizations 566f3182ebc72db2bf2e24119d5cea05f270473a491reed * - use fixed (32bit or 16bit) instead of floats? 567f3182ebc72db2bf2e24119d5cea05f270473a491reed */ 568f3182ebc72db2bf2e24119d5cea05f270473a491reed 569f3182ebc72db2bf2e24119d5cea05f270473a491reedstatic Sk4f lerp_color(float fx, const SkLinearGradient::LinearGradientContext::Rec* rec) { 570de3aac8cea8a7113f31591e6e02c51fe0ac45280reed SkASSERT(fx >= rec[0].fPos); 571de3aac8cea8a7113f31591e6e02c51fe0ac45280reed SkASSERT(fx <= rec[1].fPos); 572de3aac8cea8a7113f31591e6e02c51fe0ac45280reed 573f3182ebc72db2bf2e24119d5cea05f270473a491reed const float p0 = rec[0].fPos; 574f3182ebc72db2bf2e24119d5cea05f270473a491reed const Sk4f c0 = rec[0].fColor; 575f3182ebc72db2bf2e24119d5cea05f270473a491reed const Sk4f c1 = rec[1].fColor; 576f3182ebc72db2bf2e24119d5cea05f270473a491reed const Sk4f diffc = c1 - c0; 577f3182ebc72db2bf2e24119d5cea05f270473a491reed const float scale = rec[1].fPosScale; 578f3182ebc72db2bf2e24119d5cea05f270473a491reed const float t = (fx - p0) * scale; 579f3182ebc72db2bf2e24119d5cea05f270473a491reed return c0 + Sk4f(t) * diffc; 580f3182ebc72db2bf2e24119d5cea05f270473a491reed} 581f3182ebc72db2bf2e24119d5cea05f270473a491reed 582f3182ebc72db2bf2e24119d5cea05f270473a491reedtemplate <bool apply_alpha> void ramp(SkPMColor dstC[], int n, const Sk4f& c, const Sk4f& dc, 583f3182ebc72db2bf2e24119d5cea05f270473a491reed const Sk4f& dither0, const Sk4f& dither1) { 584f3182ebc72db2bf2e24119d5cea05f270473a491reed Sk4f dc2 = dc + dc; 585f3182ebc72db2bf2e24119d5cea05f270473a491reed Sk4f dc4 = dc2 + dc2; 586f3182ebc72db2bf2e24119d5cea05f270473a491reed Sk4f cd0 = c + dither0; 587f3182ebc72db2bf2e24119d5cea05f270473a491reed Sk4f cd1 = c + dc + dither1; 588f3182ebc72db2bf2e24119d5cea05f270473a491reed Sk4f cd2 = cd0 + dc2; 589f3182ebc72db2bf2e24119d5cea05f270473a491reed Sk4f cd3 = cd1 + dc2; 590f3182ebc72db2bf2e24119d5cea05f270473a491reed while (n >= 4) { 5919db43ac4ee1a83a4f7b332fe6c00f592b6237349mtklein if (!apply_alpha) { 5926f37b4a4757ea3eb00c76162cc37f8a56c3b8bdbmtklein Sk4f_ToBytes((uint8_t*)dstC, cd0, cd1, cd2, cd3); 5939db43ac4ee1a83a4f7b332fe6c00f592b6237349mtklein dstC += 4; 5949db43ac4ee1a83a4f7b332fe6c00f592b6237349mtklein } else { 5959db43ac4ee1a83a4f7b332fe6c00f592b6237349mtklein *dstC++ = trunc_from_255<apply_alpha>(cd0); 5969db43ac4ee1a83a4f7b332fe6c00f592b6237349mtklein *dstC++ = trunc_from_255<apply_alpha>(cd1); 5979db43ac4ee1a83a4f7b332fe6c00f592b6237349mtklein *dstC++ = trunc_from_255<apply_alpha>(cd2); 5989db43ac4ee1a83a4f7b332fe6c00f592b6237349mtklein *dstC++ = trunc_from_255<apply_alpha>(cd3); 5999db43ac4ee1a83a4f7b332fe6c00f592b6237349mtklein } 600f3182ebc72db2bf2e24119d5cea05f270473a491reed cd0 = cd0 + dc4; 601f3182ebc72db2bf2e24119d5cea05f270473a491reed cd1 = cd1 + dc4; 602f3182ebc72db2bf2e24119d5cea05f270473a491reed cd2 = cd2 + dc4; 603f3182ebc72db2bf2e24119d5cea05f270473a491reed cd3 = cd3 + dc4; 604f3182ebc72db2bf2e24119d5cea05f270473a491reed n -= 4; 605f3182ebc72db2bf2e24119d5cea05f270473a491reed } 606f3182ebc72db2bf2e24119d5cea05f270473a491reed if (n & 2) { 607f3182ebc72db2bf2e24119d5cea05f270473a491reed *dstC++ = trunc_from_255<apply_alpha>(cd0); 608f3182ebc72db2bf2e24119d5cea05f270473a491reed *dstC++ = trunc_from_255<apply_alpha>(cd1); 609f3182ebc72db2bf2e24119d5cea05f270473a491reed cd0 = cd0 + dc2; 610f3182ebc72db2bf2e24119d5cea05f270473a491reed } 611f3182ebc72db2bf2e24119d5cea05f270473a491reed if (n & 1) { 612f3182ebc72db2bf2e24119d5cea05f270473a491reed *dstC++ = trunc_from_255<apply_alpha>(cd0); 613f3182ebc72db2bf2e24119d5cea05f270473a491reed } 614f3182ebc72db2bf2e24119d5cea05f270473a491reed} 615f3182ebc72db2bf2e24119d5cea05f270473a491reed 616f3182ebc72db2bf2e24119d5cea05f270473a491reedtemplate <bool apply_alpha, bool dx_is_pos> 617f3182ebc72db2bf2e24119d5cea05f270473a491reedvoid SkLinearGradient::LinearGradientContext::shade4_dx_clamp(SkPMColor dstC[], int count, 618f3182ebc72db2bf2e24119d5cea05f270473a491reed float fx, float dx, float invDx, 619f3182ebc72db2bf2e24119d5cea05f270473a491reed const float dither[2]) { 620f3182ebc72db2bf2e24119d5cea05f270473a491reed Sk4f dither0(dither[0]); 621f3182ebc72db2bf2e24119d5cea05f270473a491reed Sk4f dither1(dither[1]); 622f3182ebc72db2bf2e24119d5cea05f270473a491reed const Rec* rec = fRecs.begin(); 623f3182ebc72db2bf2e24119d5cea05f270473a491reed 624f3182ebc72db2bf2e24119d5cea05f270473a491reed const Sk4f dx4 = Sk4f(dx); 625f3182ebc72db2bf2e24119d5cea05f270473a491reed SkDEBUGCODE(SkPMColor* endDstC = dstC + count;) 626f3182ebc72db2bf2e24119d5cea05f270473a491reed 627f3182ebc72db2bf2e24119d5cea05f270473a491reed if (dx_is_pos) { 628f3182ebc72db2bf2e24119d5cea05f270473a491reed if (fx < 0) { 629f3182ebc72db2bf2e24119d5cea05f270473a491reed int n = SkTMin(SkFloatToIntFloor(-fx * invDx) + 1, count); 630f3182ebc72db2bf2e24119d5cea05f270473a491reed fill<apply_alpha>(dstC, n, rec[0].fColor); 631f3182ebc72db2bf2e24119d5cea05f270473a491reed count -= n; 632f3182ebc72db2bf2e24119d5cea05f270473a491reed dstC += n; 633f3182ebc72db2bf2e24119d5cea05f270473a491reed fx += n * dx; 634f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(0 == count || fx >= 0); 635f3182ebc72db2bf2e24119d5cea05f270473a491reed if (n & 1) { 636f3182ebc72db2bf2e24119d5cea05f270473a491reed SkTSwap(dither0, dither1); 637f3182ebc72db2bf2e24119d5cea05f270473a491reed } 638f3182ebc72db2bf2e24119d5cea05f270473a491reed } 639f3182ebc72db2bf2e24119d5cea05f270473a491reed } else { // dx < 0 640f3182ebc72db2bf2e24119d5cea05f270473a491reed if (fx > 1) { 641f3182ebc72db2bf2e24119d5cea05f270473a491reed int n = SkTMin(SkFloatToIntFloor((1 - fx) * invDx) + 1, count); 642f3182ebc72db2bf2e24119d5cea05f270473a491reed fill<apply_alpha>(dstC, n, rec[fRecs.count() - 1].fColor); 643f3182ebc72db2bf2e24119d5cea05f270473a491reed count -= n; 644f3182ebc72db2bf2e24119d5cea05f270473a491reed dstC += n; 645f3182ebc72db2bf2e24119d5cea05f270473a491reed fx += n * dx; 646f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(0 == count || fx <= 1); 647f3182ebc72db2bf2e24119d5cea05f270473a491reed if (n & 1) { 648f3182ebc72db2bf2e24119d5cea05f270473a491reed SkTSwap(dither0, dither1); 649f3182ebc72db2bf2e24119d5cea05f270473a491reed } 650f3182ebc72db2bf2e24119d5cea05f270473a491reed } 651f3182ebc72db2bf2e24119d5cea05f270473a491reed } 652f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(count >= 0); 653f3182ebc72db2bf2e24119d5cea05f270473a491reed 654f3182ebc72db2bf2e24119d5cea05f270473a491reed const Rec* r; 655f3182ebc72db2bf2e24119d5cea05f270473a491reed if (dx_is_pos) { 656f3182ebc72db2bf2e24119d5cea05f270473a491reed r = fRecs.begin(); // start at the beginning 657f3182ebc72db2bf2e24119d5cea05f270473a491reed } else { 658f3182ebc72db2bf2e24119d5cea05f270473a491reed r = fRecs.begin() + fRecs.count() - 2; // start at the end 659f3182ebc72db2bf2e24119d5cea05f270473a491reed } 660f3182ebc72db2bf2e24119d5cea05f270473a491reed 661f3182ebc72db2bf2e24119d5cea05f270473a491reed while (count > 0) { 662f3182ebc72db2bf2e24119d5cea05f270473a491reed if (dx_is_pos) { 663f3182ebc72db2bf2e24119d5cea05f270473a491reed if (fx >= 1) { 664f3182ebc72db2bf2e24119d5cea05f270473a491reed fill<apply_alpha>(dstC, count, rec[fRecs.count() - 1].fColor); 665f3182ebc72db2bf2e24119d5cea05f270473a491reed return; 666f3182ebc72db2bf2e24119d5cea05f270473a491reed } 667f3182ebc72db2bf2e24119d5cea05f270473a491reed } else { // dx < 0 668f3182ebc72db2bf2e24119d5cea05f270473a491reed if (fx <= 0) { 669f3182ebc72db2bf2e24119d5cea05f270473a491reed fill<apply_alpha>(dstC, count, rec[0].fColor); 670f3182ebc72db2bf2e24119d5cea05f270473a491reed return; 671f3182ebc72db2bf2e24119d5cea05f270473a491reed } 672f3182ebc72db2bf2e24119d5cea05f270473a491reed } 673f3182ebc72db2bf2e24119d5cea05f270473a491reed 674f3182ebc72db2bf2e24119d5cea05f270473a491reed if (dx_is_pos) { 675f3182ebc72db2bf2e24119d5cea05f270473a491reed r = find_forward(r, fx); 676f3182ebc72db2bf2e24119d5cea05f270473a491reed } else { 677f3182ebc72db2bf2e24119d5cea05f270473a491reed r = find_backward(r, fx); 678f3182ebc72db2bf2e24119d5cea05f270473a491reed } 679f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(r >= fRecs.begin() && r < fRecs.begin() + fRecs.count() - 1); 680f3182ebc72db2bf2e24119d5cea05f270473a491reed 681f3182ebc72db2bf2e24119d5cea05f270473a491reed const float p0 = r[0].fPos; 682f3182ebc72db2bf2e24119d5cea05f270473a491reed const Sk4f c0 = r[0].fColor; 683f3182ebc72db2bf2e24119d5cea05f270473a491reed const float p1 = r[1].fPos; 684f3182ebc72db2bf2e24119d5cea05f270473a491reed const Sk4f diffc = Sk4f(r[1].fColor) - c0; 685f3182ebc72db2bf2e24119d5cea05f270473a491reed const float scale = r[1].fPosScale; 686f3182ebc72db2bf2e24119d5cea05f270473a491reed const float t = (fx - p0) * scale; 687f3182ebc72db2bf2e24119d5cea05f270473a491reed const Sk4f c = c0 + Sk4f(t) * diffc; 688f3182ebc72db2bf2e24119d5cea05f270473a491reed const Sk4f dc = diffc * dx4 * Sk4f(scale); 689f3182ebc72db2bf2e24119d5cea05f270473a491reed 690f3182ebc72db2bf2e24119d5cea05f270473a491reed int n; 691f3182ebc72db2bf2e24119d5cea05f270473a491reed if (dx_is_pos) { 692f3182ebc72db2bf2e24119d5cea05f270473a491reed n = SkTMin((int)((p1 - fx) * invDx) + 1, count); 693f3182ebc72db2bf2e24119d5cea05f270473a491reed } else { 694f3182ebc72db2bf2e24119d5cea05f270473a491reed n = SkTMin((int)((p0 - fx) * invDx) + 1, count); 695f3182ebc72db2bf2e24119d5cea05f270473a491reed } 696f3182ebc72db2bf2e24119d5cea05f270473a491reed 697f3182ebc72db2bf2e24119d5cea05f270473a491reed fx += n * dx; 698aeab8ea4d7492dc996fa72de7298de81f8deed93reed // fx should now outside of the p0..p1 interval. However, due to float precision loss, 699aeab8ea4d7492dc996fa72de7298de81f8deed93reed // its possible that fx is slightly too small/large, so we clamp it. 700f3182ebc72db2bf2e24119d5cea05f270473a491reed if (dx_is_pos) { 701aeab8ea4d7492dc996fa72de7298de81f8deed93reed fx = SkTMax(fx, p1); 702f3182ebc72db2bf2e24119d5cea05f270473a491reed } else { 703aeab8ea4d7492dc996fa72de7298de81f8deed93reed fx = SkTMin(fx, p0); 704f3182ebc72db2bf2e24119d5cea05f270473a491reed } 705f3182ebc72db2bf2e24119d5cea05f270473a491reed 706f3182ebc72db2bf2e24119d5cea05f270473a491reed ramp<apply_alpha>(dstC, n, c, dc, dither0, dither1); 707f3182ebc72db2bf2e24119d5cea05f270473a491reed dstC += n; 708f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(dstC <= endDstC); 7099db43ac4ee1a83a4f7b332fe6c00f592b6237349mtklein 710f3182ebc72db2bf2e24119d5cea05f270473a491reed if (n & 1) { 711f3182ebc72db2bf2e24119d5cea05f270473a491reed SkTSwap(dither0, dither1); 712f3182ebc72db2bf2e24119d5cea05f270473a491reed } 713aeab8ea4d7492dc996fa72de7298de81f8deed93reed 714aeab8ea4d7492dc996fa72de7298de81f8deed93reed count -= n; 715aeab8ea4d7492dc996fa72de7298de81f8deed93reed SkASSERT(count >= 0); 716f3182ebc72db2bf2e24119d5cea05f270473a491reed } 717f3182ebc72db2bf2e24119d5cea05f270473a491reed} 718f3182ebc72db2bf2e24119d5cea05f270473a491reed 719f3182ebc72db2bf2e24119d5cea05f270473a491reedvoid SkLinearGradient::LinearGradientContext::shade4_clamp(int x, int y, SkPMColor dstC[], 720f3182ebc72db2bf2e24119d5cea05f270473a491reed int count) { 721f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(count > 0); 722f3182ebc72db2bf2e24119d5cea05f270473a491reed SkASSERT(kLinear_MatrixClass == fDstToIndexClass); 723f3182ebc72db2bf2e24119d5cea05f270473a491reed 724f3182ebc72db2bf2e24119d5cea05f270473a491reed SkPoint srcPt; 725f3182ebc72db2bf2e24119d5cea05f270473a491reed fDstToIndexProc(fDstToIndex, x + SK_ScalarHalf, y + SK_ScalarHalf, &srcPt); 726f3182ebc72db2bf2e24119d5cea05f270473a491reed float fx = srcPt.x(); 727f3182ebc72db2bf2e24119d5cea05f270473a491reed const float dx = fDstToIndex.getScaleX(); 728f3182ebc72db2bf2e24119d5cea05f270473a491reed 729f3182ebc72db2bf2e24119d5cea05f270473a491reed // Default our dither bias values to 1/2, (rounding), which is no dithering 730f3182ebc72db2bf2e24119d5cea05f270473a491reed float dither0 = 0.5f; 731f3182ebc72db2bf2e24119d5cea05f270473a491reed float dither1 = 0.5f; 732f3182ebc72db2bf2e24119d5cea05f270473a491reed if (fDither) { 733f3182ebc72db2bf2e24119d5cea05f270473a491reed const float ditherCell[] = { 734f3182ebc72db2bf2e24119d5cea05f270473a491reed 1/8.0f, 5/8.0f, 735f3182ebc72db2bf2e24119d5cea05f270473a491reed 7/8.0f, 3/8.0f, 736f3182ebc72db2bf2e24119d5cea05f270473a491reed }; 737f3182ebc72db2bf2e24119d5cea05f270473a491reed const int rowIndex = (y & 1) << 1; 738f3182ebc72db2bf2e24119d5cea05f270473a491reed dither0 = ditherCell[rowIndex]; 739f3182ebc72db2bf2e24119d5cea05f270473a491reed dither1 = ditherCell[rowIndex + 1]; 740f3182ebc72db2bf2e24119d5cea05f270473a491reed if (x & 1) { 741f3182ebc72db2bf2e24119d5cea05f270473a491reed SkTSwap(dither0, dither1); 742f3182ebc72db2bf2e24119d5cea05f270473a491reed } 743f3182ebc72db2bf2e24119d5cea05f270473a491reed } 744f3182ebc72db2bf2e24119d5cea05f270473a491reed const float dither[2] = { dither0, dither1 }; 745f3182ebc72db2bf2e24119d5cea05f270473a491reed const float invDx = 1 / dx; 746f3182ebc72db2bf2e24119d5cea05f270473a491reed 7472b46913c99319de9567390e8a543057be0c162e3fmalita if (SkScalarNearlyZero(dx * count)) { // gradient is vertical 748de3aac8cea8a7113f31591e6e02c51fe0ac45280reed const float pinFx = SkTPin(fx, 0.0f, 1.0f); 749de3aac8cea8a7113f31591e6e02c51fe0ac45280reed Sk4f c = lerp_color(pinFx, find_forward(fRecs.begin(), pinFx)); 750f3182ebc72db2bf2e24119d5cea05f270473a491reed if (fApplyAlphaAfterInterp) { 751f3182ebc72db2bf2e24119d5cea05f270473a491reed fill<true>(dstC, count, c + dither0, c + dither1); 752f3182ebc72db2bf2e24119d5cea05f270473a491reed } else { 753f3182ebc72db2bf2e24119d5cea05f270473a491reed fill<false>(dstC, count, c + dither0, c + dither1); 754f3182ebc72db2bf2e24119d5cea05f270473a491reed } 755f3182ebc72db2bf2e24119d5cea05f270473a491reed return; 756f3182ebc72db2bf2e24119d5cea05f270473a491reed } 757f3182ebc72db2bf2e24119d5cea05f270473a491reed 758f3182ebc72db2bf2e24119d5cea05f270473a491reed if (dx > 0) { 759f3182ebc72db2bf2e24119d5cea05f270473a491reed if (fApplyAlphaAfterInterp) { 760f3182ebc72db2bf2e24119d5cea05f270473a491reed this->shade4_dx_clamp<true, true>(dstC, count, fx, dx, invDx, dither); 761f3182ebc72db2bf2e24119d5cea05f270473a491reed } else { 762f3182ebc72db2bf2e24119d5cea05f270473a491reed this->shade4_dx_clamp<false, true>(dstC, count, fx, dx, invDx, dither); 763f3182ebc72db2bf2e24119d5cea05f270473a491reed } 764f3182ebc72db2bf2e24119d5cea05f270473a491reed } else { 765f3182ebc72db2bf2e24119d5cea05f270473a491reed if (fApplyAlphaAfterInterp) { 766f3182ebc72db2bf2e24119d5cea05f270473a491reed this->shade4_dx_clamp<true, false>(dstC, count, fx, dx, invDx, dither); 767f3182ebc72db2bf2e24119d5cea05f270473a491reed } else { 768f3182ebc72db2bf2e24119d5cea05f270473a491reed this->shade4_dx_clamp<false, false>(dstC, count, fx, dx, invDx, dither); 769f3182ebc72db2bf2e24119d5cea05f270473a491reed } 770f3182ebc72db2bf2e24119d5cea05f270473a491reed } 771f3182ebc72db2bf2e24119d5cea05f270473a491reed} 772