14beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com/* 24beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com * Copyright 2013 Google Inc. 34beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com * 44beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com * Use of this source code is governed by a BSD-style license that can be 54beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com * found in the LICENSE file. 64beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com */ 74beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com 80f4a95368de7add7e4be50aa3ed8375746a8cccfhumper@google.com#include "SkErrorInternals.h" 90f4a95368de7add7e4be50aa3ed8375746a8cccfhumper@google.com#include "SkConvolver.h" 104beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com#include "SkBitmapProcState.h" 114beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com#include "SkBitmap.h" 124beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com#include "SkColor.h" 134beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com#include "SkColorPriv.h" 140f4a95368de7add7e4be50aa3ed8375746a8cccfhumper@google.com#include "SkConvolver.h" 154beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com#include "SkUnPreMultiply.h" 164beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com#include "SkShader.h" 174beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com#include "SkRTConf.h" 184beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com#include "SkMath.h" 194beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com 200f4a95368de7add7e4be50aa3ed8375746a8cccfhumper@google.com// These are the per-scanline callbacks that are used when we must resort to 210f4a95368de7add7e4be50aa3ed8375746a8cccfhumper@google.com// resampling an image as it is blitted. Typically these are used only when 220f4a95368de7add7e4be50aa3ed8375746a8cccfhumper@google.com// the image is rotated or has some other complex transformation applied. 230f4a95368de7add7e4be50aa3ed8375746a8cccfhumper@google.com// Scaled images will usually be rescaled directly before rasterization. 240f4a95368de7add7e4be50aa3ed8375746a8cccfhumper@google.com 25e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.comnamespace { 264beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com 27e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.comtemplate <typename Color, typename ColorPacker> 28e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.comvoid highQualityFilter(ColorPacker pack, const SkBitmapProcState& s, int x, int y, Color* SK_RESTRICT colors, int count) { 294beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com const int maxX = s.fBitmap->width() - 1; 304beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com const int maxY = s.fBitmap->height() - 1; 314beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com 324beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com while (count-- > 0) { 334beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com SkPoint srcPt; 34dfc928cc9afc242d1125e8d5ae48e8bca66c4834commit-bot@chromium.org s.fInvProc(s.fInvMatrix, x + 0.5f, 35dfc928cc9afc242d1125e8d5ae48e8bca66c4834commit-bot@chromium.org y + 0.5f, &srcPt); 364beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com srcPt.fX -= SK_ScalarHalf; 374beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com srcPt.fY -= SK_ScalarHalf; 384beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com 396212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com SkScalar weight = 0; 406212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com SkScalar fr = 0, fg = 0, fb = 0, fa = 0; 416f1f1590f1a631733634dff2ce78ff7a8190371askia.committer@gmail.com 426212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com int y0 = SkClampMax(SkScalarCeilToInt(srcPt.fY-s.getBitmapFilter()->width()), maxY); 438516e0953955b0c33bcd872554cadb642bcd9da7commit-bot@chromium.org int y1 = SkClampMax(SkScalarFloorToInt(srcPt.fY+s.getBitmapFilter()->width()+1), maxY); 446212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com int x0 = SkClampMax(SkScalarCeilToInt(srcPt.fX-s.getBitmapFilter()->width()), maxX); 458516e0953955b0c33bcd872554cadb642bcd9da7commit-bot@chromium.org int x1 = SkClampMax(SkScalarFloorToInt(srcPt.fX+s.getBitmapFilter()->width())+1, maxX); 466f1f1590f1a631733634dff2ce78ff7a8190371askia.committer@gmail.com 478516e0953955b0c33bcd872554cadb642bcd9da7commit-bot@chromium.org for (int srcY = y0; srcY < y1; srcY++) { 486212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com SkScalar yWeight = s.getBitmapFilter()->lookupScalar((srcPt.fY - srcY)); 496f1f1590f1a631733634dff2ce78ff7a8190371askia.committer@gmail.com 508516e0953955b0c33bcd872554cadb642bcd9da7commit-bot@chromium.org for (int srcX = x0; srcX < x1 ; srcX++) { 516212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com SkScalar xWeight = s.getBitmapFilter()->lookupScalar((srcPt.fX - srcX)); 526f1f1590f1a631733634dff2ce78ff7a8190371askia.committer@gmail.com 536212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com SkScalar combined_weight = SkScalarMul(xWeight, yWeight); 546f1f1590f1a631733634dff2ce78ff7a8190371askia.committer@gmail.com 556212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com SkPMColor c = *s.fBitmap->getAddr32(srcX, srcY); 564beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com fr += combined_weight * SkGetPackedR32(c); 574beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com fg += combined_weight * SkGetPackedG32(c); 584beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com fb += combined_weight * SkGetPackedB32(c); 594beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com fa += combined_weight * SkGetPackedA32(c); 604beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com weight += combined_weight; 614beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com } 624beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com } 634beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com 646212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com fr = SkScalarDiv(fr, weight); 656212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com fg = SkScalarDiv(fg, weight); 666212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com fb = SkScalarDiv(fb, weight); 676212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com fa = SkScalarDiv(fa, weight); 684beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com 696212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com int a = SkClampMax(SkScalarRoundToInt(fa), 255); 706212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com int r = SkClampMax(SkScalarRoundToInt(fr), a); 716212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com int g = SkClampMax(SkScalarRoundToInt(fg), a); 726212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com int b = SkClampMax(SkScalarRoundToInt(fb), a); 734beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com 74e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com *colors++ = pack(a, r, g, b); 754beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com 764beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com x++; 774beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com } 784beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com} 794beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com 80e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.comuint16_t PackTo565(int /*a*/, int r, int g, int b) { 81e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com return SkPack888ToRGB16(r, g, b); 82e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com} 83e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com 84e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com} // namespace 85e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com 86e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.comvoid highQualityFilter32(const SkBitmapProcState& s, int x, int y, SkPMColor* SK_RESTRICT colors, int count) { 87e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com highQualityFilter(&SkPackARGB32, s, x, y, colors, count); 88e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com} 89e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com 90e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.comvoid highQualityFilter16(const SkBitmapProcState& s, int x, int y, uint16_t* SK_RESTRICT colors, int count) { 91e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com highQualityFilter(&PackTo565, s, x, y, colors, count); 92e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com} 93e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com 94e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com 950f4a95368de7add7e4be50aa3ed8375746a8cccfhumper@google.comSK_CONF_DECLARE(const char *, c_bitmapFilter, "bitmap.filter", "mitchell", "Which scanline bitmap filter to use [mitchell, lanczos, hamming, gaussian, triangle, box]"); 964beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com 970f4a95368de7add7e4be50aa3ed8375746a8cccfhumper@google.comSkBitmapFilter *SkBitmapFilter::Allocate() { 984beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com if (!strcmp(c_bitmapFilter, "mitchell")) { 994beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com return SkNEW_ARGS(SkMitchellFilter,(1.f/3.f,1.f/3.f)); 1000f4a95368de7add7e4be50aa3ed8375746a8cccfhumper@google.com } else if (!strcmp(c_bitmapFilter, "lanczos")) { 1010f4a95368de7add7e4be50aa3ed8375746a8cccfhumper@google.com return SkNEW(SkLanczosFilter); 1020f4a95368de7add7e4be50aa3ed8375746a8cccfhumper@google.com } else if (!strcmp(c_bitmapFilter, "hamming")) { 1030f4a95368de7add7e4be50aa3ed8375746a8cccfhumper@google.com return SkNEW(SkHammingFilter); 1044beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com } else if (!strcmp(c_bitmapFilter, "gaussian")) { 1054beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com return SkNEW_ARGS(SkGaussianFilter,(2)); 1064beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com } else if (!strcmp(c_bitmapFilter, "triangle")) { 1074beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com return SkNEW(SkTriangleFilter); 1084beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com } else if (!strcmp(c_bitmapFilter, "box")) { 1094beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com return SkNEW(SkBoxFilter); 1104beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com } else { 11132826d2ab6453e15c878cdec19fbe965f5eef610mtklein@google.com SkDEBUGFAIL("Unknown filter type"); 1124beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com } 1136f1f1590f1a631733634dff2ce78ff7a8190371askia.committer@gmail.com 1144beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com return NULL; 1154beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com} 1164beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com 117e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.combool SkBitmapProcState::setBitmapFilterProcs() { 1184d112c5bcdd40d9786a685dc142653e31ffbcbabreed@google.com if (fFilterLevel != SkPaint::kHigh_FilterLevel) { 119e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com return false; 1206212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com } 1216212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com 1226212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com if (fAlphaScale != 256) { 123e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com return false; 1244beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com } 1254beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com 1264beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com // TODO: consider supporting other configs (e.g. 565, A8) 1274beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com if (fBitmap->config() != SkBitmap::kARGB_8888_Config) { 128e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com return false; 1294beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com } 1304beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com 1314beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com // TODO: consider supporting repeat and mirror 1324beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com if (SkShader::kClamp_TileMode != fTileModeX || SkShader::kClamp_TileMode != fTileModeY) { 133e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com return false; 1344beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com } 1354beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com 136e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com // TODO: is this right? do we want fBitmapFilter allocated even if we can't set shader procs? 1374beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com if (fInvType & (SkMatrix::kAffine_Mask | SkMatrix::kScale_Mask)) { 1380f4a95368de7add7e4be50aa3ed8375746a8cccfhumper@google.com fBitmapFilter = SkBitmapFilter::Allocate(); 1394beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com } 1406f1f1590f1a631733634dff2ce78ff7a8190371askia.committer@gmail.com 1410f4a95368de7add7e4be50aa3ed8375746a8cccfhumper@google.com if (fInvType & SkMatrix::kScale_Mask) { 142e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com fShaderProc32 = highQualityFilter32; 143e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com fShaderProc16 = highQualityFilter16; 144e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com return true; 1454beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com } else { 146e678c0f878e10b011ec63168990f0edbafcab4f7mtklein@google.com return false; 1474beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com } 1484beaaec29643b528813afa5a08a7aa692a5292a0humper@google.com} 149