1685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com 2685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com/* 3685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Copyright 2011 Google Inc. 4685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * 5685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Use of this source code is governed by a BSD-style license that can be 6685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * found in the LICENSE file. 7685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com */ 8bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkBitmapProcShader.h" 9bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkColorPriv.h" 109ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com#include "SkFlattenableBuffers.h" 11bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkPixelRef.h" 1229ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com#include "SkErrorInternals.h" 13bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 14bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.combool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) { 15bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com switch (bm.config()) { 16bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com case SkBitmap::kA8_Config: 17bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com case SkBitmap::kRGB_565_Config: 18bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com case SkBitmap::kIndex8_Config: 19bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com case SkBitmap::kARGB_8888_Config: 20bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx)) 21bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return true; 22bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com default: 23bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com break; 24bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 25bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return false; 26bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 27bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 28bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, 29bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com TileMode tmx, TileMode tmy) { 30bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fRawBitmap = src; 31bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fState.fTileModeX = (uint8_t)tmx; 32bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fState.fTileModeY = (uint8_t)tmy; 33badeafac94730d6c53098c3d90abc05509ebd6a1reed@android.com fFlags = 0; // computed in setContext 34bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 35bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 36bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer) 37bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com : INHERITED(buffer) { 389ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com buffer.readBitmap(&fRawBitmap); 3960293dcc4d90d75e748eddde055059fc9cb94062reed@google.com fRawBitmap.setImmutable(); 409ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com fState.fTileModeX = buffer.readUInt(); 419ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com fState.fTileModeY = buffer.readUInt(); 42badeafac94730d6c53098c3d90abc05509ebd6a1reed@android.com fFlags = 0; // computed in setContext 43bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 44bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 45092e2ef83749d3711c0772677502df77a622f75areed@google.comSkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture, 46092e2ef83749d3711c0772677502df77a622f75areed@google.com SkMatrix* texM, 47fb2135b20e5c62b084bd64fa6d651f3e4362cd4drileya@google.com TileMode xy[]) const { 48bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (texture) { 49bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com *texture = fRawBitmap; 50bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 51bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (texM) { 52bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com texM->reset(); 53bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 54bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (xy) { 55bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com xy[0] = (TileMode)fState.fTileModeX; 56bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com xy[1] = (TileMode)fState.fTileModeY; 57bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 58e216b62841acd5db9d91b63960805568259a2e0ereed@android.com return kDefault_BitmapType; 59bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 60bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 61cd2e444e946f5cfec4723f5bc46e9487d82e8e54djsollen@google.comvoid SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) const { 62bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com this->INHERITED::flatten(buffer); 63bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 649ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com buffer.writeBitmap(fRawBitmap); 659ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com buffer.writeUInt(fState.fTileModeX); 669ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com buffer.writeUInt(fState.fTileModeY); 67bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 68bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 699ed8f76ef95fdda704a60a0e787395612bc70443reed@android.comstatic bool only_scale_and_translate(const SkMatrix& matrix) { 709ed8f76ef95fdda704a60a0e787395612bc70443reed@android.com unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; 719ed8f76ef95fdda704a60a0e787395612bc70443reed@android.com return (matrix.getType() & ~mask) == 0; 729ed8f76ef95fdda704a60a0e787395612bc70443reed@android.com} 739ed8f76ef95fdda704a60a0e787395612bc70443reed@android.com 749601a62f74301f2f773240b3b0614e3cb152a024junov@chromium.orgbool SkBitmapProcShader::isOpaque() const { 759601a62f74301f2f773240b3b0614e3cb152a024junov@chromium.org return fRawBitmap.isOpaque(); 769601a62f74301f2f773240b3b0614e3cb152a024junov@chromium.org} 779601a62f74301f2f773240b3b0614e3cb152a024junov@chromium.org 78bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.combool SkBitmapProcShader::setContext(const SkBitmap& device, 79bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com const SkPaint& paint, 80bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com const SkMatrix& matrix) { 81bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // do this first, so we have a correct inverse matrix 82bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (!this->INHERITED::setContext(device, paint, matrix)) { 83bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return false; 84bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 85bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 86bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fState.fOrigBitmap = fRawBitmap; 87bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fState.fOrigBitmap.lockPixels(); 88e216b62841acd5db9d91b63960805568259a2e0ereed@android.com if (!fState.fOrigBitmap.getTexture() && !fState.fOrigBitmap.readyToDraw()) { 89bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fState.fOrigBitmap.unlockPixels(); 90d65131b413804c06fe7eab7af5205e32ca709332mike@reedtribe.org this->INHERITED::endContext(); 91bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return false; 92bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 93bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 94bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (!fState.chooseProcs(this->getTotalInverse(), paint)) { 95bd370925b712814b8467a32e31f9d7d921f9f476reed@google.com fState.fOrigBitmap.unlockPixels(); 96d65131b413804c06fe7eab7af5205e32ca709332mike@reedtribe.org this->INHERITED::endContext(); 97bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return false; 98bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 99bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 100f4eda68d26c9221e3ccb0de8add5c4e53e054fadreed@android.com const SkBitmap& bitmap = *fState.fBitmap; 101f4eda68d26c9221e3ccb0de8add5c4e53e054fadreed@android.com bool bitmapIsOpaque = bitmap.isOpaque(); 102092e2ef83749d3711c0772677502df77a622f75areed@google.com 103bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // update fFlags 104dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com uint32_t flags = 0; 105bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (bitmapIsOpaque && (255 == this->getPaintAlpha())) { 106dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com flags |= kOpaqueAlpha_Flag; 107bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 108bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 109f4eda68d26c9221e3ccb0de8add5c4e53e054fadreed@android.com switch (bitmap.config()) { 110bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com case SkBitmap::kRGB_565_Config: 111dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag); 112bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com break; 113bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com case SkBitmap::kIndex8_Config: 114bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com case SkBitmap::kARGB_8888_Config: 115bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (bitmapIsOpaque) { 116dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com flags |= kHasSpan16_Flag; 117bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 118bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com break; 119bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com case SkBitmap::kA8_Config: 120bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com break; // never set kHasSpan16_Flag 121bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com default: 122bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com break; 123bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 1249ed8f76ef95fdda704a60a0e787395612bc70443reed@android.com 125f4eda68d26c9221e3ccb0de8add5c4e53e054fadreed@android.com if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) { 126dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com // gradients can auto-dither in their 16bit sampler, but we don't so 127f4eda68d26c9221e3ccb0de8add5c4e53e054fadreed@android.com // we clear the flag here. 128dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com flags &= ~kHasSpan16_Flag; 129dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com } 130dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com 131bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com // if we're only 1-pixel high, and we don't rotate, then we can claim this 132f4eda68d26c9221e3ccb0de8add5c4e53e054fadreed@android.com if (1 == bitmap.height() && 1339ed8f76ef95fdda704a60a0e787395612bc70443reed@android.com only_scale_and_translate(this->getTotalInverse())) { 13489b7cb1226f0410b0bfda732714571f1876e6aeereed@android.com flags |= kConstInY32_Flag; 13589b7cb1226f0410b0bfda732714571f1876e6aeereed@android.com if (flags & kHasSpan16_Flag) { 13689b7cb1226f0410b0bfda732714571f1876e6aeereed@android.com flags |= kConstInY16_Flag; 13789b7cb1226f0410b0bfda732714571f1876e6aeereed@android.com } 1389ed8f76ef95fdda704a60a0e787395612bc70443reed@android.com } 139dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com 140dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com fFlags = flags; 141bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return true; 142bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 143bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 144bd370925b712814b8467a32e31f9d7d921f9f476reed@google.comvoid SkBitmapProcShader::endContext() { 145bd370925b712814b8467a32e31f9d7d921f9f476reed@google.com fState.fOrigBitmap.unlockPixels(); 1466212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com fState.endContext(); 147bd370925b712814b8467a32e31f9d7d921f9f476reed@google.com this->INHERITED::endContext(); 148bd370925b712814b8467a32e31f9d7d921f9f476reed@google.com} 149bd370925b712814b8467a32e31f9d7d921f9f476reed@google.com 150bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define BUF_MAX 128 151bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 152d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com#define TEST_BUFFER_OVERRITEx 153d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com 154d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com#ifdef TEST_BUFFER_OVERRITE 155d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com #define TEST_BUFFER_EXTRA 32 156d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com #define TEST_PATTERN 0x88888888 157d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com#else 158d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com #define TEST_BUFFER_EXTRA 0 159d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com#endif 160d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com 161bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { 16213224b7848ecb2753914a5946feab6e503fbf614reed@android.com const SkBitmapProcState& state = fState; 163ff37996c5611f53208808d91926aac16d4c9f8aereed@google.com if (state.getShaderProc32()) { 164ff37996c5611f53208808d91926aac16d4c9f8aereed@google.com state.getShaderProc32()(state, x, y, dstC, count); 16513224b7848ecb2753914a5946feab6e503fbf614reed@android.com return; 16613224b7848ecb2753914a5946feab6e503fbf614reed@android.com } 167bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 168d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA]; 169ff37996c5611f53208808d91926aac16d4c9f8aereed@google.com SkBitmapProcState::MatrixProc mproc = state.getMatrixProc(); 170ff37996c5611f53208808d91926aac16d4c9f8aereed@google.com SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32(); 171d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX); 172bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 173bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(state.fBitmap->getPixels()); 174bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(state.fBitmap->pixelRef() == NULL || 175e0f5c7da0d07c811789773d1bd555edba3a1cf40reed@google.com state.fBitmap->pixelRef()->isLocked()); 176bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 177bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com for (;;) { 178bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int n = count; 179bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (n > max) { 180bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com n = max; 181bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 182d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com SkASSERT(n > 0 && n < BUF_MAX*2); 183d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com#ifdef TEST_BUFFER_OVERRITE 184d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com for (int i = 0; i < TEST_BUFFER_EXTRA; i++) { 185d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com buffer[BUF_MAX + i] = TEST_PATTERN; 186d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com } 187d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com#endif 188bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com mproc(state, buffer, n, x, y); 189d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com#ifdef TEST_BUFFER_OVERRITE 190d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com for (int j = 0; j < TEST_BUFFER_EXTRA; j++) { 191d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN); 192d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com } 193d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com#endif 194bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com sproc(state, buffer, n, dstC); 195092e2ef83749d3711c0772677502df77a622f75areed@google.com 196bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if ((count -= n) == 0) { 197bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com break; 198bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 199d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com SkASSERT(count > 0); 200bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com x += n; 201bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com dstC += n; 202bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 203bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 204bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 205f1bbd533e266687c5c2b6b406e06ae28bc500920reed@google.comSkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) { 206f1bbd533e266687c5c2b6b406e06ae28bc500920reed@google.com if (fState.getShaderProc32()) { 207f1bbd533e266687c5c2b6b406e06ae28bc500920reed@google.com *ctx = &fState; 208f1bbd533e266687c5c2b6b406e06ae28bc500920reed@google.com return (ShadeProc)fState.getShaderProc32(); 209f1bbd533e266687c5c2b6b406e06ae28bc500920reed@google.com } 210f1bbd533e266687c5c2b6b406e06ae28bc500920reed@google.com return NULL; 211f1bbd533e266687c5c2b6b406e06ae28bc500920reed@google.com} 212f1bbd533e266687c5c2b6b406e06ae28bc500920reed@google.com 213bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) { 21413224b7848ecb2753914a5946feab6e503fbf614reed@android.com const SkBitmapProcState& state = fState; 215ff37996c5611f53208808d91926aac16d4c9f8aereed@google.com if (state.getShaderProc16()) { 216ff37996c5611f53208808d91926aac16d4c9f8aereed@google.com state.getShaderProc16()(state, x, y, dstC, count); 21713224b7848ecb2753914a5946feab6e503fbf614reed@android.com return; 21813224b7848ecb2753914a5946feab6e503fbf614reed@android.com } 219092e2ef83749d3711c0772677502df77a622f75areed@google.com 22013224b7848ecb2753914a5946feab6e503fbf614reed@android.com uint32_t buffer[BUF_MAX]; 221ff37996c5611f53208808d91926aac16d4c9f8aereed@google.com SkBitmapProcState::MatrixProc mproc = state.getMatrixProc(); 222ff37996c5611f53208808d91926aac16d4c9f8aereed@google.com SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16(); 223cf87e774356ef088b6d221da46a8702d16e19219reed@android.com int max = fState.maxCountForBufferSize(sizeof(buffer)); 224bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 225bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(state.fBitmap->getPixels()); 226bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(state.fBitmap->pixelRef() == NULL || 227e0f5c7da0d07c811789773d1bd555edba3a1cf40reed@google.com state.fBitmap->pixelRef()->isLocked()); 228bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 229bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com for (;;) { 230bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int n = count; 231bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (n > max) { 232bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com n = max; 233bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 234bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com mproc(state, buffer, n, x, y); 235bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com sproc(state, buffer, n, dstC); 236092e2ef83749d3711c0772677502df77a622f75areed@google.com 237bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if ((count -= n) == 0) { 238bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com break; 239bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 240bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com x += n; 241bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com dstC += n; 242bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 243bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 244bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 245bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com/////////////////////////////////////////////////////////////////////////////// 246bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 24735820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com#include "SkUnPreMultiply.h" 24835820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com#include "SkColorShader.h" 24956dd3b35cc39a66ea2e9e86529dc3c272f3e120creed@google.com#include "SkEmptyShader.h" 25035820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com 25135820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com// returns true and set color if the bitmap can be drawn as a single color 25235820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com// (for efficiency) 25335820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.comstatic bool canUseColorShader(const SkBitmap& bm, SkColor* color) { 25435820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com if (1 != bm.width() || 1 != bm.height()) { 25535820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com return false; 25635820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com } 25735820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com 25835820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com SkAutoLockPixels alp(bm); 25935820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com if (!bm.readyToDraw()) { 26035820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com return false; 26135820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com } 26235820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com 26335820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com switch (bm.config()) { 26435820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com case SkBitmap::kARGB_8888_Config: 26535820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0)); 26635820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com return true; 26735820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com case SkBitmap::kRGB_565_Config: 26835820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com *color = SkPixel16ToColor(*bm.getAddr16(0, 0)); 26935820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com return true; 27035820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com case SkBitmap::kIndex8_Config: 27135820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0)); 27235820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com return true; 27335820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com default: // just skip the other configs for now 27435820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com break; 27535820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com } 27635820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com return false; 27735820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com} 27835820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com 279bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkTemplatesPriv.h" 280bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 28199cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.comstatic bool bitmapIsTooBig(const SkBitmap& bm) { 28299cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it 28399cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com // communicates between its matrix-proc and its sampler-proc. Until we can 28499cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com // widen that, we have to reject bitmaps that are larger. 28599cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com // 28699cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com const int maxSize = 65535; 28799cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com 28899cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com return bm.width() > maxSize || bm.height() > maxSize; 28999cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com} 29099cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com 291bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkShader* SkShader::CreateBitmapShader(const SkBitmap& src, 292bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com TileMode tmx, TileMode tmy, 293bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com void* storage, size_t storageSize) { 294bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkShader* shader; 29535820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com SkColor color; 29699cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com if (src.isNull() || bitmapIsTooBig(src)) { 29756dd3b35cc39a66ea2e9e86529dc3c272f3e120creed@google.com SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize); 29856dd3b35cc39a66ea2e9e86529dc3c272f3e120creed@google.com } 29956dd3b35cc39a66ea2e9e86529dc3c272f3e120creed@google.com else if (canUseColorShader(src, &color)) { 30035820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize, 30135820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com (color)); 30235820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com } else { 30335820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage, 30435820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com storageSize, (src, tmx, tmy)); 30535820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com } 306bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return shader; 307bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 308bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 309bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com/////////////////////////////////////////////////////////////////////////////// 310bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 311bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com#ifdef SK_DEVELOPER 312bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.comvoid SkBitmapProcShader::toString(SkString* str) const { 313bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com static const char* gTileModeName[SkShader::kTileModeCount] = { 314bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com "clamp", "repeat", "mirror" 315bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com }; 316092e2ef83749d3711c0772677502df77a622f75areed@google.com 317bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com str->append("BitmapShader: ("); 318092e2ef83749d3711c0772677502df77a622f75areed@google.com 319bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com str->appendf("(%s, %s)", 320bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com gTileModeName[fState.fTileModeX], 321bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com gTileModeName[fState.fTileModeY]); 322bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com 323bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com str->append(" "); 324bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com fRawBitmap.toString(str); 325bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com 326bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com this->INHERITED::toString(str); 327bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com 328bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com str->append(")"); 329bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 330bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com#endif 331bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com 33205614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com/////////////////////////////////////////////////////////////////////////////// 33305614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com 33405614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com#if SK_SUPPORT_GPU 33505614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com 33605614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com#include "GrTextureAccess.h" 337c230a788e0c4339ca1638b79c493055d75ceefc5bsalomon@google.com#include "effects/GrSimpleTextureEffect.h" 33805614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com#include "SkGr.h" 33905614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com 34038b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.comGrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint) const { 34105614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com SkMatrix matrix; 34205614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height()); 34305614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com 34405614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com if (this->hasLocalMatrix()) { 34505614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com SkMatrix inverse; 34605614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com if (!this->getLocalMatrix().invert(&inverse)) { 34702c64b785b2a2e18c80c2f27b9a89613bd849791humper@google.com return NULL; 34805614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com } 34905614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com matrix.preConcat(inverse); 35005614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com } 35105614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com SkShader::TileMode tm[] = { 35205614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com (TileMode)fState.fTileModeX, 35305614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com (TileMode)fState.fTileModeY, 35405614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com }; 35505614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com 35605614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com // Must set wrap and filter on the sampler before requesting a texture. 35729ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com SkPaint::FilterLevel paintFilterLevel = paint.getFilterLevel(); 35829ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com GrTextureParams::FilterMode textureFilterMode; 35929ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com switch(paintFilterLevel) { 36029ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com case SkPaint::kNone_FilterLevel: 36129ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com textureFilterMode = GrTextureParams::kNone_FilterMode; 36229ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com break; 36329ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com case SkPaint::kLow_FilterLevel: 36429ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com textureFilterMode = GrTextureParams::kBilerp_FilterMode; 36529ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com break; 36629ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com case SkPaint::kMedium_FilterLevel: 36729ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com textureFilterMode = GrTextureParams::kMipMap_FilterMode; 36829ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com break; 36929ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com case SkPaint::kHigh_FilterLevel: 37029ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com SkErrorInternals::SetError( kInvalidPaint_SkError, 37129ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com "Sorry, I don't yet support high quality " 37229ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com "filtering on the GPU; falling back to " 37329ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com "MIPMaps."); 37429ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com textureFilterMode = GrTextureParams::kMipMap_FilterMode; 37529ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com break; 376459084d27d8682c8795548e69087a313b1649385humper@google.com default: 377459084d27d8682c8795548e69087a313b1649385humper@google.com SkErrorInternals::SetError( kInvalidPaint_SkError, 378459084d27d8682c8795548e69087a313b1649385humper@google.com "Sorry, I don't understand the filtering " 379459084d27d8682c8795548e69087a313b1649385humper@google.com "mode you asked for. Falling back to " 380459084d27d8682c8795548e69087a313b1649385humper@google.com "MIPMaps."); 381459084d27d8682c8795548e69087a313b1649385humper@google.com textureFilterMode = GrTextureParams::kMipMap_FilterMode; 382459084d27d8682c8795548e69087a313b1649385humper@google.com break; 38337d2c1133a35ca9ef444823d7f1a6a79b3f7871fskia.committer@gmail.com 38429ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com } 38529ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com GrTextureParams params(tm, textureFilterMode); 3868f5dc5a363c2e9548f3b48325a1579a5da92e21absalomon@google.com GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, fRawBitmap, ¶ms); 38705614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com 38805614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com if (NULL == texture) { 38905614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com SkDebugf("Couldn't convert bitmap to texture.\n"); 39005614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com return NULL; 39105614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com } 392bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 393c230a788e0c4339ca1638b79c493055d75ceefc5bsalomon@google.com GrEffectRef* effect = GrSimpleTextureEffect::Create(texture, matrix, params); 3948f5dc5a363c2e9548f3b48325a1579a5da92e21absalomon@google.com GrUnlockAndUnrefCachedBitmapTexture(texture); 39505614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com return effect; 39605614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com} 39705614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com#endif 398