blob: c2f68d4879a5ee965449dccf3cc7e8b8b50e919b [file] [log] [blame]
humper@google.comb0889472013-07-09 21:37:14 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
humper@google.com138ebc32013-07-19 20:20:04 +00008#include "SkErrorInternals.h"
9#include "SkConvolver.h"
humper@google.comb0889472013-07-09 21:37:14 +000010#include "SkBitmapProcState.h"
11#include "SkBitmap.h"
12#include "SkColor.h"
13#include "SkColorPriv.h"
humper@google.com138ebc32013-07-19 20:20:04 +000014#include "SkConvolver.h"
humper@google.comb0889472013-07-09 21:37:14 +000015#include "SkUnPreMultiply.h"
16#include "SkShader.h"
17#include "SkRTConf.h"
18#include "SkMath.h"
19
humper@google.com138ebc32013-07-19 20:20:04 +000020// These are the per-scanline callbacks that are used when we must resort to
21// resampling an image as it is blitted. Typically these are used only when
22// the image is rotated or has some other complex transformation applied.
23// Scaled images will usually be rescaled directly before rasterization.
24
humper@google.comb0889472013-07-09 21:37:14 +000025void highQualityFilter(const SkBitmapProcState& s, int x, int y,
26 SkPMColor* SK_RESTRICT colors, int count) {
27
28 const int maxX = s.fBitmap->width() - 1;
29 const int maxY = s.fBitmap->height() - 1;
30
31 while (count-- > 0) {
32 SkPoint srcPt;
humper@google.com9c96d4b2013-07-14 01:44:59 +000033 s.fInvProc(s.fInvMatrix, SkFloatToScalar(x + 0.5f),
humper@google.coma8fc2682013-07-10 22:34:05 +000034 SkFloatToScalar(y + 0.5f), &srcPt);
humper@google.comb0889472013-07-09 21:37:14 +000035 srcPt.fX -= SK_ScalarHalf;
36 srcPt.fY -= SK_ScalarHalf;
37
humper@google.com9c96d4b2013-07-14 01:44:59 +000038 SkScalar weight = 0;
39 SkScalar fr = 0, fg = 0, fb = 0, fa = 0;
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000040
humper@google.com9c96d4b2013-07-14 01:44:59 +000041 int y0 = SkClampMax(SkScalarCeilToInt(srcPt.fY-s.getBitmapFilter()->width()), maxY);
42 int y1 = SkClampMax(SkScalarFloorToInt(srcPt.fY+s.getBitmapFilter()->width()), maxY);
43 int x0 = SkClampMax(SkScalarCeilToInt(srcPt.fX-s.getBitmapFilter()->width()), maxX);
44 int x1 = SkClampMax(SkScalarFloorToInt(srcPt.fX+s.getBitmapFilter()->width()), maxX);
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000045
humper@google.com9c96d4b2013-07-14 01:44:59 +000046 for (int srcY = y0; srcY <= y1; srcY++) {
47 SkScalar yWeight = s.getBitmapFilter()->lookupScalar((srcPt.fY - srcY));
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000048
humper@google.com9c96d4b2013-07-14 01:44:59 +000049 for (int srcX = x0; srcX <= x1 ; srcX++) {
50 SkScalar xWeight = s.getBitmapFilter()->lookupScalar((srcPt.fX - srcX));
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000051
humper@google.com9c96d4b2013-07-14 01:44:59 +000052 SkScalar combined_weight = SkScalarMul(xWeight, yWeight);
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000053
humper@google.com9c96d4b2013-07-14 01:44:59 +000054 SkPMColor c = *s.fBitmap->getAddr32(srcX, srcY);
humper@google.comb0889472013-07-09 21:37:14 +000055 fr += combined_weight * SkGetPackedR32(c);
56 fg += combined_weight * SkGetPackedG32(c);
57 fb += combined_weight * SkGetPackedB32(c);
58 fa += combined_weight * SkGetPackedA32(c);
59 weight += combined_weight;
60 }
61 }
62
humper@google.com9c96d4b2013-07-14 01:44:59 +000063 fr = SkScalarDiv(fr, weight);
64 fg = SkScalarDiv(fg, weight);
65 fb = SkScalarDiv(fb, weight);
66 fa = SkScalarDiv(fa, weight);
humper@google.comb0889472013-07-09 21:37:14 +000067
humper@google.com9c96d4b2013-07-14 01:44:59 +000068 int a = SkClampMax(SkScalarRoundToInt(fa), 255);
69 int r = SkClampMax(SkScalarRoundToInt(fr), a);
70 int g = SkClampMax(SkScalarRoundToInt(fg), a);
71 int b = SkClampMax(SkScalarRoundToInt(fb), a);
humper@google.comb0889472013-07-09 21:37:14 +000072
73 *colors++ = SkPackARGB32(a, r, g, b);
74
75 x++;
76 }
77}
78
humper@google.com138ebc32013-07-19 20:20:04 +000079SK_CONF_DECLARE(const char *, c_bitmapFilter, "bitmap.filter", "mitchell", "Which scanline bitmap filter to use [mitchell, lanczos, hamming, gaussian, triangle, box]");
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000080
humper@google.com138ebc32013-07-19 20:20:04 +000081SkBitmapFilter *SkBitmapFilter::Allocate() {
humper@google.comb0889472013-07-09 21:37:14 +000082 if (!strcmp(c_bitmapFilter, "mitchell")) {
83 return SkNEW_ARGS(SkMitchellFilter,(1.f/3.f,1.f/3.f));
humper@google.com138ebc32013-07-19 20:20:04 +000084 } else if (!strcmp(c_bitmapFilter, "lanczos")) {
85 return SkNEW(SkLanczosFilter);
86 } else if (!strcmp(c_bitmapFilter, "hamming")) {
87 return SkNEW(SkHammingFilter);
humper@google.comb0889472013-07-09 21:37:14 +000088 } else if (!strcmp(c_bitmapFilter, "gaussian")) {
89 return SkNEW_ARGS(SkGaussianFilter,(2));
90 } else if (!strcmp(c_bitmapFilter, "triangle")) {
91 return SkNEW(SkTriangleFilter);
92 } else if (!strcmp(c_bitmapFilter, "box")) {
93 return SkNEW(SkBoxFilter);
94 } else {
95 SkASSERT(!!!"Unknown filter type");
96 }
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000097
humper@google.comb0889472013-07-09 21:37:14 +000098 return NULL;
99}
100
101SkBitmapProcState::ShaderProc32
humper@google.com9c96d4b2013-07-14 01:44:59 +0000102SkBitmapProcState::chooseBitmapFilterProc() {
103
reed@google.com9cfc83c2013-07-22 17:18:18 +0000104 if (fFilterLevel != SkPaint::kHigh_FilterLevel) {
humper@google.com9c96d4b2013-07-14 01:44:59 +0000105 return NULL;
106 }
107
108 if (fAlphaScale != 256) {
humper@google.comb0889472013-07-09 21:37:14 +0000109 return NULL;
110 }
111
112 // TODO: consider supporting other configs (e.g. 565, A8)
113 if (fBitmap->config() != SkBitmap::kARGB_8888_Config) {
114 return NULL;
115 }
116
117 // TODO: consider supporting repeat and mirror
118 if (SkShader::kClamp_TileMode != fTileModeX || SkShader::kClamp_TileMode != fTileModeY) {
119 return NULL;
120 }
121
humper@google.comb0889472013-07-09 21:37:14 +0000122 if (fInvType & (SkMatrix::kAffine_Mask | SkMatrix::kScale_Mask)) {
humper@google.com138ebc32013-07-19 20:20:04 +0000123 fBitmapFilter = SkBitmapFilter::Allocate();
humper@google.comb0889472013-07-09 21:37:14 +0000124 }
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +0000125
humper@google.com138ebc32013-07-19 20:20:04 +0000126 if (fInvType & SkMatrix::kScale_Mask) {
humper@google.comb0889472013-07-09 21:37:14 +0000127 return highQualityFilter;
humper@google.comb0889472013-07-09 21:37:14 +0000128 } else {
129 return NULL;
130 }
131}