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