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