SkGradientShader.cpp revision a641f3f18e5319773989812a888f3fad49e4f2ad
1589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 2589708bf7c706348b763e8277004cb160b202bdbrileya@google.com/* 3589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * Copyright 2006 The Android Open Source Project 4589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * 5589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * Use of this source code is governed by a BSD-style license that can be 6589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * found in the LICENSE file. 7589708bf7c706348b763e8277004cb160b202bdbrileya@google.com */ 8589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 9589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#include "SkGradientShaderPriv.h" 10589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#include "SkLinearGradient.h" 11589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#include "SkRadialGradient.h" 12589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#include "SkTwoPointRadialGradient.h" 13589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#include "SkTwoPointConicalGradient.h" 14589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#include "SkSweepGradient.h" 15589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 16589708bf7c706348b763e8277004cb160b202bdbrileya@google.comSkGradientShaderBase::SkGradientShaderBase(const SkColor colors[], const SkScalar pos[], 17589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper) { 18589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(colorCount > 1); 19589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 20589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCacheAlpha = 256; // init to a value that paint.getAlpha() can't return 21589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 22589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fMapper = mapper; 23589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkSafeRef(mapper); 24589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 25589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT((unsigned)mode < SkShader::kTileModeCount); 26589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs)); 27589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fTileMode = mode; 28589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fTileProc = gTileProcs[mode]; 29589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 30589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCache16 = fCache16Storage = NULL; 31589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCache32 = NULL; 32589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCache32PixelRef = NULL; 33589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 34589708bf7c706348b763e8277004cb160b202bdbrileya@google.com /* Note: we let the caller skip the first and/or last position. 35589708bf7c706348b763e8277004cb160b202bdbrileya@google.com i.e. pos[0] = 0.3, pos[1] = 0.7 36589708bf7c706348b763e8277004cb160b202bdbrileya@google.com In these cases, we insert dummy entries to ensure that the final data 37589708bf7c706348b763e8277004cb160b202bdbrileya@google.com will be bracketed by [0, 1]. 38589708bf7c706348b763e8277004cb160b202bdbrileya@google.com i.e. our_pos[0] = 0, our_pos[1] = 0.3, our_pos[2] = 0.7, our_pos[3] = 1 39589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 40589708bf7c706348b763e8277004cb160b202bdbrileya@google.com Thus colorCount (the caller's value, and fColorCount (our value) may 41589708bf7c706348b763e8277004cb160b202bdbrileya@google.com differ by up to 2. In the above example: 42589708bf7c706348b763e8277004cb160b202bdbrileya@google.com colorCount = 2 43589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fColorCount = 4 44589708bf7c706348b763e8277004cb160b202bdbrileya@google.com */ 45589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fColorCount = colorCount; 46589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // check if we need to add in dummy start and/or end position/colors 47589708bf7c706348b763e8277004cb160b202bdbrileya@google.com bool dummyFirst = false; 48589708bf7c706348b763e8277004cb160b202bdbrileya@google.com bool dummyLast = false; 49589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (pos) { 50589708bf7c706348b763e8277004cb160b202bdbrileya@google.com dummyFirst = pos[0] != 0; 51589708bf7c706348b763e8277004cb160b202bdbrileya@google.com dummyLast = pos[colorCount - 1] != SK_Scalar1; 52589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fColorCount += dummyFirst + dummyLast; 53589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 54589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 55589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fColorCount > kColorStorageCount) { 56589708bf7c706348b763e8277004cb160b202bdbrileya@google.com size_t size = sizeof(SkColor) + sizeof(Rec); 57589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fOrigColors = reinterpret_cast<SkColor*>( 58589708bf7c706348b763e8277004cb160b202bdbrileya@google.com sk_malloc_throw(size * fColorCount)); 59589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 60589708bf7c706348b763e8277004cb160b202bdbrileya@google.com else { 61589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fOrigColors = fStorage; 62589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 63589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 64589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // Now copy over the colors, adding the dummies as needed 65589708bf7c706348b763e8277004cb160b202bdbrileya@google.com { 66589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkColor* origColors = fOrigColors; 67589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (dummyFirst) { 68589708bf7c706348b763e8277004cb160b202bdbrileya@google.com *origColors++ = colors[0]; 69589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 70589708bf7c706348b763e8277004cb160b202bdbrileya@google.com memcpy(origColors, colors, colorCount * sizeof(SkColor)); 71589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (dummyLast) { 72589708bf7c706348b763e8277004cb160b202bdbrileya@google.com origColors += colorCount; 73589708bf7c706348b763e8277004cb160b202bdbrileya@google.com *origColors = colors[colorCount - 1]; 74589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 75589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 76589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 77589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fRecs = (Rec*)(fOrigColors + fColorCount); 78589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fColorCount > 2) { 79589708bf7c706348b763e8277004cb160b202bdbrileya@google.com Rec* recs = fRecs; 80589708bf7c706348b763e8277004cb160b202bdbrileya@google.com recs->fPos = 0; 81589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // recs->fScale = 0; // unused; 82589708bf7c706348b763e8277004cb160b202bdbrileya@google.com recs += 1; 83589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (pos) { 84589708bf7c706348b763e8277004cb160b202bdbrileya@google.com /* We need to convert the user's array of relative positions into 85589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fixed-point positions and scale factors. We need these results 86589708bf7c706348b763e8277004cb160b202bdbrileya@google.com to be strictly monotonic (no two values equal or out of order). 87589708bf7c706348b763e8277004cb160b202bdbrileya@google.com Hence this complex loop that just jams a zero for the scale 88589708bf7c706348b763e8277004cb160b202bdbrileya@google.com value if it sees a segment out of order, and it assures that 89589708bf7c706348b763e8277004cb160b202bdbrileya@google.com we start at 0 and end at 1.0 90589708bf7c706348b763e8277004cb160b202bdbrileya@google.com */ 91589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed prev = 0; 92589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int startIndex = dummyFirst ? 0 : 1; 93589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int count = colorCount + dummyLast; 94589708bf7c706348b763e8277004cb160b202bdbrileya@google.com for (int i = startIndex; i < count; i++) { 95589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // force the last value to be 1.0 96589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed curr; 97589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (i == colorCount) { // we're really at the dummyLast 98589708bf7c706348b763e8277004cb160b202bdbrileya@google.com curr = SK_Fixed1; 99589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } else { 100589708bf7c706348b763e8277004cb160b202bdbrileya@google.com curr = SkScalarToFixed(pos[i]); 101589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 102589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // pin curr withing range 103589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (curr < 0) { 104589708bf7c706348b763e8277004cb160b202bdbrileya@google.com curr = 0; 105589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } else if (curr > SK_Fixed1) { 106589708bf7c706348b763e8277004cb160b202bdbrileya@google.com curr = SK_Fixed1; 107589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 108589708bf7c706348b763e8277004cb160b202bdbrileya@google.com recs->fPos = curr; 109589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (curr > prev) { 110589708bf7c706348b763e8277004cb160b202bdbrileya@google.com recs->fScale = (1 << 24) / (curr - prev); 111589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } else { 112589708bf7c706348b763e8277004cb160b202bdbrileya@google.com recs->fScale = 0; // ignore this segment 113589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 114589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // get ready for the next value 115589708bf7c706348b763e8277004cb160b202bdbrileya@google.com prev = curr; 116589708bf7c706348b763e8277004cb160b202bdbrileya@google.com recs += 1; 117589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 118589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } else { // assume even distribution 119589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed dp = SK_Fixed1 / (colorCount - 1); 120589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed p = dp; 121589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed scale = (colorCount - 1) << 8; // (1 << 24) / dp 122589708bf7c706348b763e8277004cb160b202bdbrileya@google.com for (int i = 1; i < colorCount; i++) { 123589708bf7c706348b763e8277004cb160b202bdbrileya@google.com recs->fPos = p; 124589708bf7c706348b763e8277004cb160b202bdbrileya@google.com recs->fScale = scale; 125589708bf7c706348b763e8277004cb160b202bdbrileya@google.com recs += 1; 126589708bf7c706348b763e8277004cb160b202bdbrileya@google.com p += dp; 127589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 128589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 129589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 130589708bf7c706348b763e8277004cb160b202bdbrileya@google.com this->initCommon(); 131589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 132589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 133589708bf7c706348b763e8277004cb160b202bdbrileya@google.comSkGradientShaderBase::SkGradientShaderBase(SkFlattenableReadBuffer& buffer) : 134589708bf7c706348b763e8277004cb160b202bdbrileya@google.com INHERITED(buffer) { 135589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCacheAlpha = 256; 136589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 137c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com fMapper = buffer.readFlattenableT<SkUnitMapper>(); 138589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 139589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCache16 = fCache16Storage = NULL; 140589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCache32 = NULL; 141589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCache32PixelRef = NULL; 142589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 143c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com int colorCount = fColorCount = buffer.getArrayCount(); 144589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (colorCount > kColorStorageCount) { 145589708bf7c706348b763e8277004cb160b202bdbrileya@google.com size_t size = sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec); 146589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fOrigColors = (SkColor*)sk_malloc_throw(size * colorCount); 147589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } else { 148589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fOrigColors = fStorage; 149589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 150c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com buffer.readColorArray(fOrigColors); 151589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 152c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com fTileMode = (TileMode)buffer.readUInt(); 153589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fTileProc = gTileProcs[fTileMode]; 154589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fRecs = (Rec*)(fOrigColors + colorCount); 155589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (colorCount > 2) { 156589708bf7c706348b763e8277004cb160b202bdbrileya@google.com Rec* recs = fRecs; 157589708bf7c706348b763e8277004cb160b202bdbrileya@google.com recs[0].fPos = 0; 158589708bf7c706348b763e8277004cb160b202bdbrileya@google.com for (int i = 1; i < colorCount; i++) { 159c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com recs[i].fPos = buffer.readInt(); 160c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com recs[i].fScale = buffer.readUInt(); 161589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 162589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 163589708bf7c706348b763e8277004cb160b202bdbrileya@google.com buffer.readMatrix(&fPtsToUnit); 164589708bf7c706348b763e8277004cb160b202bdbrileya@google.com this->initCommon(); 165589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 166589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 167589708bf7c706348b763e8277004cb160b202bdbrileya@google.comSkGradientShaderBase::~SkGradientShaderBase() { 168589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fCache16Storage) { 169589708bf7c706348b763e8277004cb160b202bdbrileya@google.com sk_free(fCache16Storage); 170589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 171589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkSafeUnref(fCache32PixelRef); 172589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fOrigColors != fStorage) { 173589708bf7c706348b763e8277004cb160b202bdbrileya@google.com sk_free(fOrigColors); 174589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 175589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkSafeUnref(fMapper); 176589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 177589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 178589708bf7c706348b763e8277004cb160b202bdbrileya@google.comvoid SkGradientShaderBase::initCommon() { 179589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fFlags = 0; 180589708bf7c706348b763e8277004cb160b202bdbrileya@google.com unsigned colorAlpha = 0xFF; 181589708bf7c706348b763e8277004cb160b202bdbrileya@google.com for (int i = 0; i < fColorCount; i++) { 182589708bf7c706348b763e8277004cb160b202bdbrileya@google.com colorAlpha &= SkColorGetA(fOrigColors[i]); 183589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 184589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fColorsAreOpaque = colorAlpha == 0xFF; 185589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 186589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 187589708bf7c706348b763e8277004cb160b202bdbrileya@google.comvoid SkGradientShaderBase::flatten(SkFlattenableWriteBuffer& buffer) const { 188589708bf7c706348b763e8277004cb160b202bdbrileya@google.com this->INHERITED::flatten(buffer); 189589708bf7c706348b763e8277004cb160b202bdbrileya@google.com buffer.writeFlattenable(fMapper); 190c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com buffer.writeColorArray(fOrigColors, fColorCount); 191c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com buffer.writeUInt(fTileMode); 192589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fColorCount > 2) { 193589708bf7c706348b763e8277004cb160b202bdbrileya@google.com Rec* recs = fRecs; 194589708bf7c706348b763e8277004cb160b202bdbrileya@google.com for (int i = 1; i < fColorCount; i++) { 195c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com buffer.writeInt(recs[i].fPos); 196c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com buffer.writeUInt(recs[i].fScale); 197589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 198589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 199589708bf7c706348b763e8277004cb160b202bdbrileya@google.com buffer.writeMatrix(fPtsToUnit); 200589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 201589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 202589708bf7c706348b763e8277004cb160b202bdbrileya@google.combool SkGradientShaderBase::isOpaque() const { 203589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return fColorsAreOpaque; 204589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 205589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 206589708bf7c706348b763e8277004cb160b202bdbrileya@google.combool SkGradientShaderBase::setContext(const SkBitmap& device, 207589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const SkPaint& paint, 208589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const SkMatrix& matrix) { 209589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (!this->INHERITED::setContext(device, paint, matrix)) { 210589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return false; 211589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 212589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 213589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const SkMatrix& inverse = this->getTotalInverse(); 214589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 215589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (!fDstToIndex.setConcat(fPtsToUnit, inverse)) { 216a641f3f18e5319773989812a888f3fad49e4f2adreed@google.com // need to keep our set/end context calls balanced. 217a641f3f18e5319773989812a888f3fad49e4f2adreed@google.com this->INHERITED::endContext(); 218589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return false; 219589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 220589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 221589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fDstToIndexProc = fDstToIndex.getMapXYProc(); 222589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fDstToIndexClass = (uint8_t)SkShader::ComputeMatrixClass(fDstToIndex); 223589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 224589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // now convert our colors in to PMColors 225589708bf7c706348b763e8277004cb160b202bdbrileya@google.com unsigned paintAlpha = this->getPaintAlpha(); 226589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 227589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fFlags = this->INHERITED::getFlags(); 228589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fColorsAreOpaque && paintAlpha == 0xFF) { 229589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fFlags |= kOpaqueAlpha_Flag; 230589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 231589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // we can do span16 as long as our individual colors are opaque, 232589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // regardless of the paint's alpha 233589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fColorsAreOpaque) { 234589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fFlags |= kHasSpan16_Flag; 235589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 236589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 237589708bf7c706348b763e8277004cb160b202bdbrileya@google.com this->setCacheAlpha(paintAlpha); 238589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return true; 239589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 240589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 241589708bf7c706348b763e8277004cb160b202bdbrileya@google.comvoid SkGradientShaderBase::setCacheAlpha(U8CPU alpha) const { 242589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // if the new alpha differs from the previous time we were called, inval our cache 243589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // this will trigger the cache to be rebuilt. 244589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // we don't care about the first time, since the cache ptrs will already be NULL 245589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fCacheAlpha != alpha) { 246589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCache16 = NULL; // inval the cache 247589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCache32 = NULL; // inval the cache 248589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCacheAlpha = alpha; // record the new alpha 249589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // inform our subclasses 250589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fCache32PixelRef) { 251589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCache32PixelRef->notifyPixelsChanged(); 252589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 253589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 254589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 255589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 256589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#define Fixed_To_Dot8(x) (((x) + 0x80) >> 8) 257589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 258589708bf7c706348b763e8277004cb160b202bdbrileya@google.com/** We take the original colors, not our premultiplied PMColors, since we can 259589708bf7c706348b763e8277004cb160b202bdbrileya@google.com build a 16bit table as long as the original colors are opaque, even if the 260589708bf7c706348b763e8277004cb160b202bdbrileya@google.com paint specifies a non-opaque alpha. 261589708bf7c706348b763e8277004cb160b202bdbrileya@google.com*/ 262589708bf7c706348b763e8277004cb160b202bdbrileya@google.comvoid SkGradientShaderBase::Build16bitCache(uint16_t cache[], SkColor c0, SkColor c1, 263589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int count) { 264589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(count > 1); 265589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(SkColorGetA(c0) == 0xFF); 266589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(SkColorGetA(c1) == 0xFF); 267589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 268589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed r = SkColorGetR(c0); 269589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed g = SkColorGetG(c0); 270589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed b = SkColorGetB(c0); 271589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 272589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1); 273589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1); 274589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1); 275589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 276589708bf7c706348b763e8277004cb160b202bdbrileya@google.com r = SkIntToFixed(r) + 0x8000; 277589708bf7c706348b763e8277004cb160b202bdbrileya@google.com g = SkIntToFixed(g) + 0x8000; 278589708bf7c706348b763e8277004cb160b202bdbrileya@google.com b = SkIntToFixed(b) + 0x8000; 279589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 280589708bf7c706348b763e8277004cb160b202bdbrileya@google.com do { 281589708bf7c706348b763e8277004cb160b202bdbrileya@google.com unsigned rr = r >> 16; 282589708bf7c706348b763e8277004cb160b202bdbrileya@google.com unsigned gg = g >> 16; 283589708bf7c706348b763e8277004cb160b202bdbrileya@google.com unsigned bb = b >> 16; 284589708bf7c706348b763e8277004cb160b202bdbrileya@google.com cache[0] = SkPackRGB16(SkR32ToR16(rr), SkG32ToG16(gg), SkB32ToB16(bb)); 285589708bf7c706348b763e8277004cb160b202bdbrileya@google.com cache[kCache16Count] = SkDitherPack888ToRGB16(rr, gg, bb); 286589708bf7c706348b763e8277004cb160b202bdbrileya@google.com cache += 1; 287589708bf7c706348b763e8277004cb160b202bdbrileya@google.com r += dr; 288589708bf7c706348b763e8277004cb160b202bdbrileya@google.com g += dg; 289589708bf7c706348b763e8277004cb160b202bdbrileya@google.com b += db; 290589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } while (--count != 0); 291589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 292589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 293589708bf7c706348b763e8277004cb160b202bdbrileya@google.com/* 294589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * 2x2 dither a fixed-point color component (8.16) down to 8, matching the 295589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * semantics of how we 2x2 dither 32->16 296589708bf7c706348b763e8277004cb160b202bdbrileya@google.com */ 297589708bf7c706348b763e8277004cb160b202bdbrileya@google.comstatic inline U8CPU dither_fixed_to_8(SkFixed n) { 298589708bf7c706348b763e8277004cb160b202bdbrileya@google.com n >>= 8; 299589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return ((n << 1) - ((n >> 8 << 8) | (n >> 8))) >> 8; 300589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 301589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 302589708bf7c706348b763e8277004cb160b202bdbrileya@google.com/* 303589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * For dithering with premultiply, we want to ceiling the alpha component, 304589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * to ensure that it is always >= any color component. 305589708bf7c706348b763e8277004cb160b202bdbrileya@google.com */ 306589708bf7c706348b763e8277004cb160b202bdbrileya@google.comstatic inline U8CPU dither_ceil_fixed_to_8(SkFixed n) { 307589708bf7c706348b763e8277004cb160b202bdbrileya@google.com n >>= 8; 308589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return ((n << 1) - (n | (n >> 8))) >> 8; 309589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 310589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 311589708bf7c706348b763e8277004cb160b202bdbrileya@google.comvoid SkGradientShaderBase::Build32bitCache(SkPMColor cache[], SkColor c0, SkColor c1, 312589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int count, U8CPU paintAlpha) { 313589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(count > 1); 314589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 315589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // need to apply paintAlpha to our two endpoints 316589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed a = SkMulDiv255Round(SkColorGetA(c0), paintAlpha); 317589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed da; 318589708bf7c706348b763e8277004cb160b202bdbrileya@google.com { 319589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int tmp = SkMulDiv255Round(SkColorGetA(c1), paintAlpha); 320589708bf7c706348b763e8277004cb160b202bdbrileya@google.com da = SkIntToFixed(tmp - a) / (count - 1); 321589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 322589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 323589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed r = SkColorGetR(c0); 324589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed g = SkColorGetG(c0); 325589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed b = SkColorGetB(c0); 326589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1); 327589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1); 328589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1); 329589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 330589708bf7c706348b763e8277004cb160b202bdbrileya@google.com a = SkIntToFixed(a) + 0x8000; 331589708bf7c706348b763e8277004cb160b202bdbrileya@google.com r = SkIntToFixed(r) + 0x8000; 332589708bf7c706348b763e8277004cb160b202bdbrileya@google.com g = SkIntToFixed(g) + 0x8000; 333589708bf7c706348b763e8277004cb160b202bdbrileya@google.com b = SkIntToFixed(b) + 0x8000; 334589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 335589708bf7c706348b763e8277004cb160b202bdbrileya@google.com do { 336589708bf7c706348b763e8277004cb160b202bdbrileya@google.com cache[0] = SkPremultiplyARGBInline(a >> 16, r >> 16, g >> 16, b >> 16); 337589708bf7c706348b763e8277004cb160b202bdbrileya@google.com cache[kCache32Count] = 338589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkPremultiplyARGBInline(dither_ceil_fixed_to_8(a), 339589708bf7c706348b763e8277004cb160b202bdbrileya@google.com dither_fixed_to_8(r), 340589708bf7c706348b763e8277004cb160b202bdbrileya@google.com dither_fixed_to_8(g), 341589708bf7c706348b763e8277004cb160b202bdbrileya@google.com dither_fixed_to_8(b)); 342589708bf7c706348b763e8277004cb160b202bdbrileya@google.com cache += 1; 343589708bf7c706348b763e8277004cb160b202bdbrileya@google.com a += da; 344589708bf7c706348b763e8277004cb160b202bdbrileya@google.com r += dr; 345589708bf7c706348b763e8277004cb160b202bdbrileya@google.com g += dg; 346589708bf7c706348b763e8277004cb160b202bdbrileya@google.com b += db; 347589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } while (--count != 0); 348589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 349589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 350589708bf7c706348b763e8277004cb160b202bdbrileya@google.comstatic inline int SkFixedToFFFF(SkFixed x) { 351589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT((unsigned)x <= SK_Fixed1); 352589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return x - (x >> 16); 353589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 354589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 355589708bf7c706348b763e8277004cb160b202bdbrileya@google.comstatic inline U16CPU bitsTo16(unsigned x, const unsigned bits) { 356589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(x < (1U << bits)); 357589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (6 == bits) { 358589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return (x << 10) | (x << 4) | (x >> 2); 359589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 360589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (8 == bits) { 361589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return (x << 8) | x; 362589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 363589708bf7c706348b763e8277004cb160b202bdbrileya@google.com sk_throw(); 364589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return 0; 365589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 366589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 367589708bf7c706348b763e8277004cb160b202bdbrileya@google.com/** We duplicate the last value in each half of the cache so that 368589708bf7c706348b763e8277004cb160b202bdbrileya@google.com interpolation doesn't have to special-case being at the last point. 369589708bf7c706348b763e8277004cb160b202bdbrileya@google.com*/ 370589708bf7c706348b763e8277004cb160b202bdbrileya@google.comstatic void complete_16bit_cache(uint16_t* cache, int stride) { 371589708bf7c706348b763e8277004cb160b202bdbrileya@google.com cache[stride - 1] = cache[stride - 2]; 372589708bf7c706348b763e8277004cb160b202bdbrileya@google.com cache[2 * stride - 1] = cache[2 * stride - 2]; 373589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 374589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 375589708bf7c706348b763e8277004cb160b202bdbrileya@google.comconst uint16_t* SkGradientShaderBase::getCache16() const { 376589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fCache16 == NULL) { 377589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // double the count for dither entries 378589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const int entryCount = kCache16Count * 2; 379589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const size_t allocSize = sizeof(uint16_t) * entryCount; 380589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 381589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fCache16Storage == NULL) { // set the storage and our working ptr 382589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize); 383589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 384589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCache16 = fCache16Storage; 385589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fColorCount == 2) { 386589708bf7c706348b763e8277004cb160b202bdbrileya@google.com Build16bitCache(fCache16, fOrigColors[0], fOrigColors[1], 387589708bf7c706348b763e8277004cb160b202bdbrileya@google.com kGradient16Length); 388589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } else { 389589708bf7c706348b763e8277004cb160b202bdbrileya@google.com Rec* rec = fRecs; 390589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int prevIndex = 0; 391589708bf7c706348b763e8277004cb160b202bdbrileya@google.com for (int i = 1; i < fColorCount; i++) { 392589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache16Shift; 393589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(nextIndex < kCache16Count); 394589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 395589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (nextIndex > prevIndex) 396589708bf7c706348b763e8277004cb160b202bdbrileya@google.com Build16bitCache(fCache16 + prevIndex, fOrigColors[i-1], fOrigColors[i], nextIndex - prevIndex + 1); 397589708bf7c706348b763e8277004cb160b202bdbrileya@google.com prevIndex = nextIndex; 398589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 399589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // one extra space left over at the end for complete_16bit_cache() 400589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(prevIndex == kGradient16Length - 1); 401589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 402589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 403589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fMapper) { 404589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize); 405589708bf7c706348b763e8277004cb160b202bdbrileya@google.com uint16_t* linear = fCache16; // just computed linear data 406589708bf7c706348b763e8277004cb160b202bdbrileya@google.com uint16_t* mapped = fCache16Storage; // storage for mapped data 407589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkUnitMapper* map = fMapper; 408589708bf7c706348b763e8277004cb160b202bdbrileya@google.com for (int i = 0; i < kGradient16Length; i++) { 409589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int index = map->mapUnit16(bitsTo16(i, kCache16Bits)) >> kCache16Shift; 410589708bf7c706348b763e8277004cb160b202bdbrileya@google.com mapped[i] = linear[index]; 411589708bf7c706348b763e8277004cb160b202bdbrileya@google.com mapped[i + kCache16Count] = linear[index + kCache16Count]; 412589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 413589708bf7c706348b763e8277004cb160b202bdbrileya@google.com sk_free(fCache16); 414589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCache16 = fCache16Storage; 415589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 416589708bf7c706348b763e8277004cb160b202bdbrileya@google.com complete_16bit_cache(fCache16, kCache16Count); 417589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 418589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return fCache16; 419589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 420589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 421589708bf7c706348b763e8277004cb160b202bdbrileya@google.com/** We duplicate the last value in each half of the cache so that 422589708bf7c706348b763e8277004cb160b202bdbrileya@google.com interpolation doesn't have to special-case being at the last point. 423589708bf7c706348b763e8277004cb160b202bdbrileya@google.com*/ 424589708bf7c706348b763e8277004cb160b202bdbrileya@google.comstatic void complete_32bit_cache(SkPMColor* cache, int stride) { 425589708bf7c706348b763e8277004cb160b202bdbrileya@google.com cache[stride - 1] = cache[stride - 2]; 426589708bf7c706348b763e8277004cb160b202bdbrileya@google.com cache[2 * stride - 1] = cache[2 * stride - 2]; 427589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 428589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 429589708bf7c706348b763e8277004cb160b202bdbrileya@google.comconst SkPMColor* SkGradientShaderBase::getCache32() const { 430589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fCache32 == NULL) { 431589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // double the count for dither entries 432589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const int entryCount = kCache32Count * 2; 433589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const size_t allocSize = sizeof(SkPMColor) * entryCount; 434589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 435589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (NULL == fCache32PixelRef) { 436589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCache32PixelRef = SkNEW_ARGS(SkMallocPixelRef, 437589708bf7c706348b763e8277004cb160b202bdbrileya@google.com (NULL, allocSize, NULL)); 438589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 439589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCache32 = (SkPMColor*)fCache32PixelRef->getAddr(); 440589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fColorCount == 2) { 441589708bf7c706348b763e8277004cb160b202bdbrileya@google.com Build32bitCache(fCache32, fOrigColors[0], fOrigColors[1], 442589708bf7c706348b763e8277004cb160b202bdbrileya@google.com kGradient32Length, fCacheAlpha); 443589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } else { 444589708bf7c706348b763e8277004cb160b202bdbrileya@google.com Rec* rec = fRecs; 445589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int prevIndex = 0; 446589708bf7c706348b763e8277004cb160b202bdbrileya@google.com for (int i = 1; i < fColorCount; i++) { 447589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift; 448589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(nextIndex < kGradient32Length); 449589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 450589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (nextIndex > prevIndex) 451589708bf7c706348b763e8277004cb160b202bdbrileya@google.com Build32bitCache(fCache32 + prevIndex, fOrigColors[i-1], 452589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fOrigColors[i], 453589708bf7c706348b763e8277004cb160b202bdbrileya@google.com nextIndex - prevIndex + 1, fCacheAlpha); 454589708bf7c706348b763e8277004cb160b202bdbrileya@google.com prevIndex = nextIndex; 455589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 456589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(prevIndex == kGradient32Length - 1); 457589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 458589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 459589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fMapper) { 460589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkMallocPixelRef* newPR = SkNEW_ARGS(SkMallocPixelRef, 461589708bf7c706348b763e8277004cb160b202bdbrileya@google.com (NULL, allocSize, NULL)); 462589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkPMColor* linear = fCache32; // just computed linear data 463589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkPMColor* mapped = (SkPMColor*)newPR->getAddr(); // storage for mapped data 464589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkUnitMapper* map = fMapper; 465589708bf7c706348b763e8277004cb160b202bdbrileya@google.com for (int i = 0; i < kGradient32Length; i++) { 466589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int index = map->mapUnit16((i << 8) | i) >> 8; 467589708bf7c706348b763e8277004cb160b202bdbrileya@google.com mapped[i] = linear[index]; 468589708bf7c706348b763e8277004cb160b202bdbrileya@google.com mapped[i + kCache32Count] = linear[index + kCache32Count]; 469589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 470589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCache32PixelRef->unref(); 471589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCache32PixelRef = newPR; 472589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCache32 = (SkPMColor*)newPR->getAddr(); 473589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 474589708bf7c706348b763e8277004cb160b202bdbrileya@google.com complete_32bit_cache(fCache32, kCache32Count); 475589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 476589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return fCache32; 477589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 478589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 479589708bf7c706348b763e8277004cb160b202bdbrileya@google.com/* 480589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * Because our caller might rebuild the same (logically the same) gradient 481589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * over and over, we'd like to return exactly the same "bitmap" if possible, 482589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * allowing the client to utilize a cache of our bitmap (e.g. with a GPU). 483589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * To do that, we maintain a private cache of built-bitmaps, based on our 484589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * colors and positions. Note: we don't try to flatten the fMapper, so if one 485589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * is present, we skip the cache for now. 486589708bf7c706348b763e8277004cb160b202bdbrileya@google.com */ 4871c6d64b78b24083ee9fd7411dac8a4a7e2d03a3crileya@google.comvoid SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap) const { 488589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // our caller assumes no external alpha, so we ensure that our cache is 489589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // built with 0xFF 490589708bf7c706348b763e8277004cb160b202bdbrileya@google.com this->setCacheAlpha(0xFF); 491589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 492589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // don't have a way to put the mapper into our cache-key yet 493589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fMapper) { 494589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // force our cahce32pixelref to be built 495589708bf7c706348b763e8277004cb160b202bdbrileya@google.com (void)this->getCache32(); 496589708bf7c706348b763e8277004cb160b202bdbrileya@google.com bitmap->setConfig(SkBitmap::kARGB_8888_Config, kGradient32Length, 1); 497589708bf7c706348b763e8277004cb160b202bdbrileya@google.com bitmap->setPixelRef(fCache32PixelRef); 498589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return; 499589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 500589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 501589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // build our key: [numColors + colors[] + {positions[]} ] 502589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int count = 1 + fColorCount; 503589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fColorCount > 2) { 504589708bf7c706348b763e8277004cb160b202bdbrileya@google.com count += fColorCount - 1; // fRecs[].fPos 505589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 506589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 507589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkAutoSTMalloc<16, int32_t> storage(count); 508589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int32_t* buffer = storage.get(); 509589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 510589708bf7c706348b763e8277004cb160b202bdbrileya@google.com *buffer++ = fColorCount; 511589708bf7c706348b763e8277004cb160b202bdbrileya@google.com memcpy(buffer, fOrigColors, fColorCount * sizeof(SkColor)); 512589708bf7c706348b763e8277004cb160b202bdbrileya@google.com buffer += fColorCount; 513589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fColorCount > 2) { 514589708bf7c706348b763e8277004cb160b202bdbrileya@google.com for (int i = 1; i < fColorCount; i++) { 515589708bf7c706348b763e8277004cb160b202bdbrileya@google.com *buffer++ = fRecs[i].fPos; 516589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 517589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 518589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(buffer - storage.get() == count); 519589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 520589708bf7c706348b763e8277004cb160b202bdbrileya@google.com /////////////////////////////////// 521589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 522589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SK_DECLARE_STATIC_MUTEX(gMutex); 523589708bf7c706348b763e8277004cb160b202bdbrileya@google.com static SkBitmapCache* gCache; 524589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // each cache cost 1K of RAM, since each bitmap will be 1x256 at 32bpp 525589708bf7c706348b763e8277004cb160b202bdbrileya@google.com static const int MAX_NUM_CACHED_GRADIENT_BITMAPS = 32; 526589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkAutoMutexAcquire ama(gMutex); 527589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 528589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (NULL == gCache) { 529589708bf7c706348b763e8277004cb160b202bdbrileya@google.com gCache = SkNEW_ARGS(SkBitmapCache, (MAX_NUM_CACHED_GRADIENT_BITMAPS)); 530589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 531589708bf7c706348b763e8277004cb160b202bdbrileya@google.com size_t size = count * sizeof(int32_t); 532589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 533589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (!gCache->find(storage.get(), size, bitmap)) { 534589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // force our cahce32pixelref to be built 535589708bf7c706348b763e8277004cb160b202bdbrileya@google.com (void)this->getCache32(); 536589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // Only expose the linear section of the cache; don't let the caller 537589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // know about the padding at the end to make interpolation faster. 538589708bf7c706348b763e8277004cb160b202bdbrileya@google.com bitmap->setConfig(SkBitmap::kARGB_8888_Config, kGradient32Length, 1); 539589708bf7c706348b763e8277004cb160b202bdbrileya@google.com bitmap->setPixelRef(fCache32PixelRef); 540589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 541589708bf7c706348b763e8277004cb160b202bdbrileya@google.com gCache->add(storage.get(), size, *bitmap); 542589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 543589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 544589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 545589708bf7c706348b763e8277004cb160b202bdbrileya@google.comvoid SkGradientShaderBase::commonAsAGradient(GradientInfo* info) const { 546589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (info) { 547589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (info->fColorCount >= fColorCount) { 548589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (info->fColors) { 549589708bf7c706348b763e8277004cb160b202bdbrileya@google.com memcpy(info->fColors, fOrigColors, 550589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fColorCount * sizeof(SkColor)); 551589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 552589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (info->fColorOffsets) { 553589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fColorCount == 2) { 554589708bf7c706348b763e8277004cb160b202bdbrileya@google.com info->fColorOffsets[0] = 0; 555589708bf7c706348b763e8277004cb160b202bdbrileya@google.com info->fColorOffsets[1] = SK_Scalar1; 556589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } else if (fColorCount > 2) { 557589708bf7c706348b763e8277004cb160b202bdbrileya@google.com for (int i = 0; i < fColorCount; i++) 558589708bf7c706348b763e8277004cb160b202bdbrileya@google.com info->fColorOffsets[i] = SkFixedToScalar(fRecs[i].fPos); 559589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 560589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 561589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 562589708bf7c706348b763e8277004cb160b202bdbrileya@google.com info->fColorCount = fColorCount; 563589708bf7c706348b763e8277004cb160b202bdbrileya@google.com info->fTileMode = fTileMode; 564589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 565589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 566589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 567589708bf7c706348b763e8277004cb160b202bdbrileya@google.com/////////////////////////////////////////////////////////////////////////////// 568589708bf7c706348b763e8277004cb160b202bdbrileya@google.com/////////////////////////////////////////////////////////////////////////////// 569589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 570589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#include "SkEmptyShader.h" 571589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 572589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// assumes colors is SkColor* and pos is SkScalar* 573589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#define EXPAND_1_COLOR(count) \ 574589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkColor tmp[2]; \ 575589708bf7c706348b763e8277004cb160b202bdbrileya@google.com do { \ 576589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (1 == count) { \ 577589708bf7c706348b763e8277004cb160b202bdbrileya@google.com tmp[0] = tmp[1] = colors[0]; \ 578589708bf7c706348b763e8277004cb160b202bdbrileya@google.com colors = tmp; \ 579589708bf7c706348b763e8277004cb160b202bdbrileya@google.com pos = NULL; \ 580589708bf7c706348b763e8277004cb160b202bdbrileya@google.com count = 2; \ 581589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } \ 582589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } while (0) 583589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 584589708bf7c706348b763e8277004cb160b202bdbrileya@google.comSkShader* SkGradientShader::CreateLinear(const SkPoint pts[2], 585589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const SkColor colors[], 586589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const SkScalar pos[], int colorCount, 587589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkShader::TileMode mode, 588589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkUnitMapper* mapper) { 589589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (NULL == pts || NULL == colors || colorCount < 1) { 590589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return NULL; 591589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 592589708bf7c706348b763e8277004cb160b202bdbrileya@google.com EXPAND_1_COLOR(colorCount); 593589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 594589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return SkNEW_ARGS(SkLinearGradient, 595589708bf7c706348b763e8277004cb160b202bdbrileya@google.com (pts, colors, pos, colorCount, mode, mapper)); 596589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 597589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 598589708bf7c706348b763e8277004cb160b202bdbrileya@google.comSkShader* SkGradientShader::CreateRadial(const SkPoint& center, SkScalar radius, 599589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const SkColor colors[], 600589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const SkScalar pos[], int colorCount, 601589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkShader::TileMode mode, 602589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkUnitMapper* mapper) { 603589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (radius <= 0 || NULL == colors || colorCount < 1) { 604589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return NULL; 605589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 606589708bf7c706348b763e8277004cb160b202bdbrileya@google.com EXPAND_1_COLOR(colorCount); 607589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 608589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return SkNEW_ARGS(SkRadialGradient, 609589708bf7c706348b763e8277004cb160b202bdbrileya@google.com (center, radius, colors, pos, colorCount, mode, mapper)); 610589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 611589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 612589708bf7c706348b763e8277004cb160b202bdbrileya@google.comSkShader* SkGradientShader::CreateTwoPointRadial(const SkPoint& start, 613589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkScalar startRadius, 614589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const SkPoint& end, 615589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkScalar endRadius, 616589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const SkColor colors[], 617589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const SkScalar pos[], 618589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int colorCount, 619589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkShader::TileMode mode, 620589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkUnitMapper* mapper) { 621589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) { 622589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return NULL; 623589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 624589708bf7c706348b763e8277004cb160b202bdbrileya@google.com EXPAND_1_COLOR(colorCount); 625fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 626589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return SkNEW_ARGS(SkTwoPointRadialGradient, 627589708bf7c706348b763e8277004cb160b202bdbrileya@google.com (start, startRadius, end, endRadius, colors, pos, 628589708bf7c706348b763e8277004cb160b202bdbrileya@google.com colorCount, mode, mapper)); 629589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 630589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 631589708bf7c706348b763e8277004cb160b202bdbrileya@google.comSkShader* SkGradientShader::CreateTwoPointConical(const SkPoint& start, 632589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkScalar startRadius, 633589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const SkPoint& end, 634589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkScalar endRadius, 635589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const SkColor colors[], 636589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const SkScalar pos[], 637589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int colorCount, 638589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkShader::TileMode mode, 639589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkUnitMapper* mapper) { 640589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) { 641589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return NULL; 642589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 643589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (start == end && startRadius == endRadius) { 644589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return SkNEW(SkEmptyShader); 645589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 6461ee7c6a18a511cde879941324f173ad4c8c123f8rileya@google.com EXPAND_1_COLOR(colorCount); 647589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 648589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return SkNEW_ARGS(SkTwoPointConicalGradient, 649589708bf7c706348b763e8277004cb160b202bdbrileya@google.com (start, startRadius, end, endRadius, colors, pos, 650589708bf7c706348b763e8277004cb160b202bdbrileya@google.com colorCount, mode, mapper)); 651589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 652589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 653589708bf7c706348b763e8277004cb160b202bdbrileya@google.comSkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy, 654589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const SkColor colors[], 655589708bf7c706348b763e8277004cb160b202bdbrileya@google.com const SkScalar pos[], 656589708bf7c706348b763e8277004cb160b202bdbrileya@google.com int count, SkUnitMapper* mapper) { 657589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (NULL == colors || count < 1) { 658589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return NULL; 659589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 660589708bf7c706348b763e8277004cb160b202bdbrileya@google.com EXPAND_1_COLOR(count); 661589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 662589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return SkNEW_ARGS(SkSweepGradient, (cx, cy, colors, pos, count, mapper)); 663589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 664589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 665589708bf7c706348b763e8277004cb160b202bdbrileya@google.comSK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGradientShader) 666589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLinearGradient) 667589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRadialGradient) 668589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSweepGradient) 669589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTwoPointRadialGradient) 670589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTwoPointConicalGradient) 671589708bf7c706348b763e8277004cb160b202bdbrileya@google.comSK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 672d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 673d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com/////////////////////////////////////////////////////////////////////////////// 674d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 675cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#if SK_SUPPORT_GPU 676cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com 677b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com#include "effects/GrTextureStripAtlas.h" 678cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#include "SkGr.h" 679cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com 6800707c29413a5a3cc1c2d14b8c65b3692af5c7411bsalomon@google.comGrGLGradientEffect::GrGLGradientEffect(const GrBackendEffectFactory& factory) 681b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com : INHERITED(factory) 68281712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com , fCachedYCoord(SK_ScalarMax) 683d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com , fFSYUni(GrGLUniformManager::kInvalidUniformHandle) { 684d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com} 685d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 6860707c29413a5a3cc1c2d14b8c65b3692af5c7411bsalomon@google.comGrGLGradientEffect::~GrGLGradientEffect() { } 687d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 688f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.comvoid GrGLGradientEffect::emitYCoordUniform(GrGLShaderBuilder* builder) { 689b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com fFSYUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, 690b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com kFloat_GrSLType, "GradientYCoordFS"); 691b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com} 692b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com 69328a15fb8d603847949a61657ef5cb73ed9915021bsalomon@google.comvoid GrGLGradientEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) { 694d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com const GrGradientEffect& e = static_cast<const GrGradientEffect&>(*stage.getEffect()); 695d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com const GrTexture* texture = e.texture(0); 696d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com fEffectMatrix.setData(uman, e.getMatrix(), stage.getCoordChangeMatrix(), texture); 697d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com 69881712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com SkScalar yCoord = e.getYCoord(); 699b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com if (yCoord != fCachedYCoord) { 700b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com uman.set1f(fFSYUni, yCoord); 701b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com fCachedYCoord = yCoord; 702b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com } 703b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com} 704b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com 705d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.comGrGLEffect::EffectKey GrGLGradientEffect::GenMatrixKey(const GrEffectStage& s) { 706d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com const GrGradientEffect& e = static_cast<const GrGradientEffect&>(*s.getEffect()); 707d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com const GrTexture* texture = e.texture(0); 708760f2d95dd22efce0066b663421aa604812c447fskia.committer@gmail.com return GrGLEffectMatrix::GenKey(e.getMatrix(), s.getCoordChangeMatrix(), texture); 709d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com} 710d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com 711d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.comvoid GrGLGradientEffect::setupMatrix(GrGLShaderBuilder* builder, 712d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com EffectKey key, 713d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com const char* vertexCoords, 714d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com const char** fsCoordName, 715d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com const char** vsVaryingName, 716d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com GrSLType* vsVaryingType) { 717d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com fEffectMatrix.emitCodeMakeFSCoords2D(builder, 718d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com key & kMatrixKeyMask, 719d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com vertexCoords, 720d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com fsCoordName, 721d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com vsVaryingName, 722d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com vsVaryingType); 723d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com} 724d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com 7250707c29413a5a3cc1c2d14b8c65b3692af5c7411bsalomon@google.comvoid GrGLGradientEffect::emitColorLookup(GrGLShaderBuilder* builder, 7260707c29413a5a3cc1c2d14b8c65b3692af5c7411bsalomon@google.com const char* gradientTValue, 7270707c29413a5a3cc1c2d14b8c65b3692af5c7411bsalomon@google.com const char* outputColor, 7280707c29413a5a3cc1c2d14b8c65b3692af5c7411bsalomon@google.com const char* inputColor, 7290707c29413a5a3cc1c2d14b8c65b3692af5c7411bsalomon@google.com const GrGLShaderBuilder::TextureSampler& sampler) { 73034bcb9f80336fe0dc56ad5f67aeb0859bf84d92ebsalomon@google.com 731868a8e7fc83e9ac6ee1418e75b84a0595605626cbsalomon@google.com SkString* code = &builder->fFSCode; 732868a8e7fc83e9ac6ee1418e75b84a0595605626cbsalomon@google.com code->appendf("\tvec2 coord = vec2(%s, %s);\n", 733868a8e7fc83e9ac6ee1418e75b84a0595605626cbsalomon@google.com gradientTValue, 734868a8e7fc83e9ac6ee1418e75b84a0595605626cbsalomon@google.com builder->getUniformVariable(fFSYUni).c_str()); 735868a8e7fc83e9ac6ee1418e75b84a0595605626cbsalomon@google.com code->appendf("\t%s = ", outputColor); 736f06df1bb9ab201a78bfc906a9e95326c6e15a119bsalomon@google.com builder->appendTextureLookupAndModulate(code, inputColor, sampler, "coord"); 737868a8e7fc83e9ac6ee1418e75b84a0595605626cbsalomon@google.com code->append(";\n"); 738d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com} 739d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 740d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com///////////////////////////////////////////////////////////////////// 741d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 742fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.comGrGradientEffect::GrGradientEffect(GrContext* ctx, 7431c6d64b78b24083ee9fd7411dac8a4a7e2d03a3crileya@google.com const SkGradientShaderBase& shader, 744d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com const SkMatrix& matrix, 7451ce49fc91714ce8974d11246d29ebe7b97b5fe98bsalomon@google.com SkShader::TileMode tileMode) 746e6e62d1de9ab6cd7ad098a5e953bf207047389e8bsalomon@google.com : INHERITED(1) { 747d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com // TODO: check for simple cases where we don't need a texture: 748d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com //GradientInfo info; 749d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com //shader.asAGradient(&info); 750d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com //if (info.fColorCount == 2) { ... 751d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 752d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com fMatrix = matrix; 753d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com 754d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com SkBitmap bitmap; 7551c6d64b78b24083ee9fd7411dac8a4a7e2d03a3crileya@google.com shader.getGradientTableBitmap(&bitmap); 756d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 757b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com GrTextureStripAtlas::Desc desc; 758b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com desc.fWidth = bitmap.width(); 759b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com desc.fHeight = 32; 760b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com desc.fRowHeight = bitmap.height(); 761b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com desc.fContext = ctx; 762b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com desc.fConfig = SkBitmapConfig2GrPixelConfig(bitmap.config()); 763b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com fAtlas = GrTextureStripAtlas::GetAtlas(desc); 764b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com GrAssert(NULL != fAtlas); 765fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 7661ce49fc91714ce8974d11246d29ebe7b97b5fe98bsalomon@google.com // We always filter the gradient table. Each table is one row of a texture, so always y-clamp. 7671ce49fc91714ce8974d11246d29ebe7b97b5fe98bsalomon@google.com GrTextureParams params; 7681ce49fc91714ce8974d11246d29ebe7b97b5fe98bsalomon@google.com params.setBilerp(true); 7691ce49fc91714ce8974d11246d29ebe7b97b5fe98bsalomon@google.com params.setTileModeX(tileMode); 7701ce49fc91714ce8974d11246d29ebe7b97b5fe98bsalomon@google.com 771b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com fRow = fAtlas->lockRow(bitmap); 772b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com if (-1 != fRow) { 77381712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com fYCoord = fAtlas->getYOffset(fRow) + SK_ScalarHalf * 774b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com fAtlas->getVerticalScaleFactor(); 7751ce49fc91714ce8974d11246d29ebe7b97b5fe98bsalomon@google.com fTextureAccess.reset(fAtlas->getTexture(), params); 776b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com } else { 7771ce49fc91714ce8974d11246d29ebe7b97b5fe98bsalomon@google.com GrTexture* texture = GrLockCachedBitmapTexture(ctx, bitmap, ¶ms); 7781ce49fc91714ce8974d11246d29ebe7b97b5fe98bsalomon@google.com fTextureAccess.reset(texture, params); 77981712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com fYCoord = SK_ScalarHalf; 780fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 781b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com // Unlock immediately, this is not great, but we don't have a way of 782b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com // knowing when else to unlock it currently, so it may get purged from 783b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com // the cache, but it'll still be ref'd until it's no longer being used. 7846d003d1ddced3e71684b8b3785d1e5a16255688dbsalomon@google.com GrUnlockCachedBitmapTexture(texture); 785b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com } 786d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com} 787d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 788d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.comGrGradientEffect::~GrGradientEffect() { 789b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com if (this->useAtlas()) { 790b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com fAtlas->unlockRow(fRow); 791b3e50f23c57d058820701219e66b6bfb8e0681a4rileya@google.com } 792d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com} 793d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 7946d003d1ddced3e71684b8b3785d1e5a16255688dbsalomon@google.comconst GrTextureAccess& GrGradientEffect::textureAccess(int index) const { 795e6e62d1de9ab6cd7ad098a5e953bf207047389e8bsalomon@google.com GrAssert(0 == index); 7966d003d1ddced3e71684b8b3785d1e5a16255688dbsalomon@google.com return fTextureAccess; 797d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com} 798d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 799d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.comint GrGradientEffect::RandomGradientParams(SkRandom* random, 800d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com SkColor colors[], 801d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com SkScalar** stops, 802d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com SkShader::TileMode* tm) { 803d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com int outColors = random->nextRangeU(1, kMaxRandomGradientColors); 804d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com 805d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com // if one color, omit stops, otherwise randomly decide whether or not to 806d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com if (outColors == 1 || (outColors >= 2 && random->nextBool())) { 807d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com *stops = NULL; 808d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com } 809d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com 81081712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com SkScalar stop = 0.f; 811d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com for (int i = 0; i < outColors; ++i) { 812d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com colors[i] = random->nextU(); 813d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com if (NULL != *stops) { 814d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com (*stops)[i] = stop; 815d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com stop = i < outColors - 1 ? stop + random->nextUScalar1() * (1.f - stop) : 1.f; 816d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com } 817d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com } 818d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com *tm = static_cast<SkShader::TileMode>(random->nextULessThan(SkShader::kTileModeCount)); 819d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com 820d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com return outColors; 821d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com} 822d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com 823cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#endif 824