1b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com/* 2b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com * Copyright 2013 Google Inc. 3b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com * 4b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com * Use of this source code is governed by a BSD-style license that can be 5b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com * found in the LICENSE file. 6b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com */ 7b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com 8138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com#include "SkErrorInternals.h" 9138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com#include "SkConvolver.h" 10b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com#include "SkBitmapProcState.h" 11b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com#include "SkBitmap.h" 12b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com#include "SkColor.h" 13b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com#include "SkColorPriv.h" 14138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com#include "SkConvolver.h" 15b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com#include "SkUnPreMultiply.h" 16b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com#include "SkShader.h" 17b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com#include "SkRTConf.h" 18b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com#include "SkMath.h" 19b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com 20138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com// These are the per-scanline callbacks that are used when we must resort to 21138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com// resampling an image as it is blitted. Typically these are used only when 22138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com// the image is rotated or has some other complex transformation applied. 23138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com// Scaled images will usually be rescaled directly before rasterization. 24138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com 250dc546c37c7dff3885188054d191cf852d899e32mtklein@google.comnamespace { 26b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com 270dc546c37c7dff3885188054d191cf852d899e32mtklein@google.comtemplate <typename Color, typename ColorPacker> 280dc546c37c7dff3885188054d191cf852d899e32mtklein@google.comvoid highQualityFilter(ColorPacker pack, const SkBitmapProcState& s, int x, int y, Color* SK_RESTRICT colors, int count) { 297af78e0d6ae874877a729a27e3f8008719b4d1c2commit-bot@chromium.org const int maxX = s.fBitmap->width(); 307af78e0d6ae874877a729a27e3f8008719b4d1c2commit-bot@chromium.org const int maxY = s.fBitmap->height(); 31d3f6e893df53fb0cfeefd01a8a49a77c72d742bdqiankun.miao SkAutoTMalloc<SkScalar> xWeights(maxX); 32b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com 33b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com while (count-- > 0) { 34b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com SkPoint srcPt; 354b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org s.fInvProc(s.fInvMatrix, x + 0.5f, 364b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org y + 0.5f, &srcPt); 37b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com srcPt.fX -= SK_ScalarHalf; 38b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com srcPt.fY -= SK_ScalarHalf; 39b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com 409c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com SkScalar weight = 0; 419c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com SkScalar fr = 0, fg = 0, fb = 0, fa = 0; 429e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com 439c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com int y0 = SkClampMax(SkScalarCeilToInt(srcPt.fY-s.getBitmapFilter()->width()), maxY); 44785f2e1426b2f90cab2fdd4460d8ccd0970d987ecommit-bot@chromium.org int y1 = SkClampMax(SkScalarFloorToInt(srcPt.fY+s.getBitmapFilter()->width()+1), maxY); 459c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com int x0 = SkClampMax(SkScalarCeilToInt(srcPt.fX-s.getBitmapFilter()->width()), maxX); 46785f2e1426b2f90cab2fdd4460d8ccd0970d987ecommit-bot@chromium.org int x1 = SkClampMax(SkScalarFloorToInt(srcPt.fX+s.getBitmapFilter()->width())+1, maxX); 479e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com 48d3f6e893df53fb0cfeefd01a8a49a77c72d742bdqiankun.miao for (int srcX = x0; srcX < x1 ; srcX++) { 49d3f6e893df53fb0cfeefd01a8a49a77c72d742bdqiankun.miao // Looking these up once instead of each loop is a ~15% speedup. 50d3f6e893df53fb0cfeefd01a8a49a77c72d742bdqiankun.miao xWeights[srcX - x0] = s.getBitmapFilter()->lookupScalar((srcPt.fX - srcX)); 51d3f6e893df53fb0cfeefd01a8a49a77c72d742bdqiankun.miao } 52d3f6e893df53fb0cfeefd01a8a49a77c72d742bdqiankun.miao 53785f2e1426b2f90cab2fdd4460d8ccd0970d987ecommit-bot@chromium.org for (int srcY = y0; srcY < y1; srcY++) { 549c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com SkScalar yWeight = s.getBitmapFilter()->lookupScalar((srcPt.fY - srcY)); 559e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com 56785f2e1426b2f90cab2fdd4460d8ccd0970d987ecommit-bot@chromium.org for (int srcX = x0; srcX < x1 ; srcX++) { 57d3f6e893df53fb0cfeefd01a8a49a77c72d742bdqiankun.miao SkScalar xWeight = xWeights[srcX - x0]; 589e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com 599c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com SkScalar combined_weight = SkScalarMul(xWeight, yWeight); 609e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com 619c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com SkPMColor c = *s.fBitmap->getAddr32(srcX, srcY); 62b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com fr += combined_weight * SkGetPackedR32(c); 63b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com fg += combined_weight * SkGetPackedG32(c); 64b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com fb += combined_weight * SkGetPackedB32(c); 65b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com fa += combined_weight * SkGetPackedA32(c); 66b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com weight += combined_weight; 67b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com } 68b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com } 69b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com 709c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com fr = SkScalarDiv(fr, weight); 719c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com fg = SkScalarDiv(fg, weight); 729c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com fb = SkScalarDiv(fb, weight); 739c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com fa = SkScalarDiv(fa, weight); 74b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com 759c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com int a = SkClampMax(SkScalarRoundToInt(fa), 255); 769c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com int r = SkClampMax(SkScalarRoundToInt(fr), a); 779c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com int g = SkClampMax(SkScalarRoundToInt(fg), a); 789c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com int b = SkClampMax(SkScalarRoundToInt(fb), a); 79b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com 800dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com *colors++ = pack(a, r, g, b); 81b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com 82b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com x++; 83b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com } 84b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com} 85b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com 860dc546c37c7dff3885188054d191cf852d899e32mtklein@google.comuint16_t PackTo565(int /*a*/, int r, int g, int b) { 870dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com return SkPack888ToRGB16(r, g, b); 880dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com} 890dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com 900dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com} // namespace 910dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com 920dc546c37c7dff3885188054d191cf852d899e32mtklein@google.comvoid highQualityFilter32(const SkBitmapProcState& s, int x, int y, SkPMColor* SK_RESTRICT colors, int count) { 930dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com highQualityFilter(&SkPackARGB32, s, x, y, colors, count); 940dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com} 950dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com 960dc546c37c7dff3885188054d191cf852d899e32mtklein@google.comvoid highQualityFilter16(const SkBitmapProcState& s, int x, int y, uint16_t* SK_RESTRICT colors, int count) { 970dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com highQualityFilter(&PackTo565, s, x, y, colors, count); 980dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com} 990dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com 1000dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com 101138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.comSK_CONF_DECLARE(const char *, c_bitmapFilter, "bitmap.filter", "mitchell", "Which scanline bitmap filter to use [mitchell, lanczos, hamming, gaussian, triangle, box]"); 102b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com 103138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.comSkBitmapFilter *SkBitmapFilter::Allocate() { 104b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com if (!strcmp(c_bitmapFilter, "mitchell")) { 105b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com return SkNEW_ARGS(SkMitchellFilter,(1.f/3.f,1.f/3.f)); 106138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com } else if (!strcmp(c_bitmapFilter, "lanczos")) { 107138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com return SkNEW(SkLanczosFilter); 108138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com } else if (!strcmp(c_bitmapFilter, "hamming")) { 109138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com return SkNEW(SkHammingFilter); 110b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com } else if (!strcmp(c_bitmapFilter, "gaussian")) { 111b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com return SkNEW_ARGS(SkGaussianFilter,(2)); 112b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com } else if (!strcmp(c_bitmapFilter, "triangle")) { 113b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com return SkNEW(SkTriangleFilter); 114b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com } else if (!strcmp(c_bitmapFilter, "box")) { 115b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com return SkNEW(SkBoxFilter); 116b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com } else { 117330313a8a8343876ee596da39da06a5d69badd9cmtklein@google.com SkDEBUGFAIL("Unknown filter type"); 118b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com } 1199e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com 120b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com return NULL; 121b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com} 122b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com 1230dc546c37c7dff3885188054d191cf852d899e32mtklein@google.combool SkBitmapProcState::setBitmapFilterProcs() { 1249cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com if (fFilterLevel != SkPaint::kHigh_FilterLevel) { 1250dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com return false; 1269c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com } 1279c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com 1289c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com if (fAlphaScale != 256) { 1290dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com return false; 130b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com } 131b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com 132900ecf2f1579d42c9d2959831787af0346320f86reed@google.com // TODO: consider supporting other colortypes (e.g. 565, A8) 13328fcae2ec77eb16a79e155f8d788b20457f1c951commit-bot@chromium.org if (fBitmap->colorType() != kN32_SkColorType) { 1340dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com return false; 135b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com } 136b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com 137b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com // TODO: consider supporting repeat and mirror 138b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com if (SkShader::kClamp_TileMode != fTileModeX || SkShader::kClamp_TileMode != fTileModeY) { 1390dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com return false; 140b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com } 141b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com 1420dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com // TODO: is this right? do we want fBitmapFilter allocated even if we can't set shader procs? 143b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com if (fInvType & (SkMatrix::kAffine_Mask | SkMatrix::kScale_Mask)) { 144138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com fBitmapFilter = SkBitmapFilter::Allocate(); 145b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com } 1469e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com 147138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com if (fInvType & SkMatrix::kScale_Mask) { 1480dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com fShaderProc32 = highQualityFilter32; 1490dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com fShaderProc16 = highQualityFilter16; 1500dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com return true; 151b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com } else { 1520dc546c37c7dff3885188054d191cf852d899e32mtklein@google.com return false; 153b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com } 154b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com} 155