blob: a9c3223fbc731531c88263a189412ea11425a85b [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
mtklein@google.com0dc546c2013-08-26 16:21:35 +000025namespace {
humper@google.comb0889472013-07-09 21:37:14 +000026
mtklein@google.com0dc546c2013-08-26 16:21:35 +000027template <typename Color, typename ColorPacker>
28void highQualityFilter(ColorPacker pack, const SkBitmapProcState& s, int x, int y, Color* SK_RESTRICT colors, int count) {
commit-bot@chromium.org7af78e02013-12-18 19:47:57 +000029 const int maxX = s.fBitmap->width();
30 const int maxY = s.fBitmap->height();
humper@google.comb0889472013-07-09 21:37:14 +000031
32 while (count-- > 0) {
33 SkPoint srcPt;
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000034 s.fInvProc(s.fInvMatrix, x + 0.5f,
35 y + 0.5f, &srcPt);
humper@google.comb0889472013-07-09 21:37:14 +000036 srcPt.fX -= SK_ScalarHalf;
37 srcPt.fY -= SK_ScalarHalf;
38
humper@google.com9c96d4b2013-07-14 01:44:59 +000039 SkScalar weight = 0;
40 SkScalar fr = 0, fg = 0, fb = 0, fa = 0;
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000041
humper@google.com9c96d4b2013-07-14 01:44:59 +000042 int y0 = SkClampMax(SkScalarCeilToInt(srcPt.fY-s.getBitmapFilter()->width()), maxY);
commit-bot@chromium.org785f2e12013-12-11 15:35:41 +000043 int y1 = SkClampMax(SkScalarFloorToInt(srcPt.fY+s.getBitmapFilter()->width()+1), maxY);
humper@google.com9c96d4b2013-07-14 01:44:59 +000044 int x0 = SkClampMax(SkScalarCeilToInt(srcPt.fX-s.getBitmapFilter()->width()), maxX);
commit-bot@chromium.org785f2e12013-12-11 15:35:41 +000045 int x1 = SkClampMax(SkScalarFloorToInt(srcPt.fX+s.getBitmapFilter()->width())+1, maxX);
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000046
commit-bot@chromium.org785f2e12013-12-11 15:35:41 +000047 for (int srcY = y0; srcY < y1; srcY++) {
humper@google.com9c96d4b2013-07-14 01:44:59 +000048 SkScalar yWeight = s.getBitmapFilter()->lookupScalar((srcPt.fY - srcY));
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000049
commit-bot@chromium.org785f2e12013-12-11 15:35:41 +000050 for (int srcX = x0; srcX < x1 ; srcX++) {
humper@google.com9c96d4b2013-07-14 01:44:59 +000051 SkScalar xWeight = s.getBitmapFilter()->lookupScalar((srcPt.fX - srcX));
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000052
humper@google.com9c96d4b2013-07-14 01:44:59 +000053 SkScalar combined_weight = SkScalarMul(xWeight, yWeight);
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000054
humper@google.com9c96d4b2013-07-14 01:44:59 +000055 SkPMColor c = *s.fBitmap->getAddr32(srcX, srcY);
humper@google.comb0889472013-07-09 21:37:14 +000056 fr += combined_weight * SkGetPackedR32(c);
57 fg += combined_weight * SkGetPackedG32(c);
58 fb += combined_weight * SkGetPackedB32(c);
59 fa += combined_weight * SkGetPackedA32(c);
60 weight += combined_weight;
61 }
62 }
63
humper@google.com9c96d4b2013-07-14 01:44:59 +000064 fr = SkScalarDiv(fr, weight);
65 fg = SkScalarDiv(fg, weight);
66 fb = SkScalarDiv(fb, weight);
67 fa = SkScalarDiv(fa, weight);
humper@google.comb0889472013-07-09 21:37:14 +000068
humper@google.com9c96d4b2013-07-14 01:44:59 +000069 int a = SkClampMax(SkScalarRoundToInt(fa), 255);
70 int r = SkClampMax(SkScalarRoundToInt(fr), a);
71 int g = SkClampMax(SkScalarRoundToInt(fg), a);
72 int b = SkClampMax(SkScalarRoundToInt(fb), a);
humper@google.comb0889472013-07-09 21:37:14 +000073
mtklein@google.com0dc546c2013-08-26 16:21:35 +000074 *colors++ = pack(a, r, g, b);
humper@google.comb0889472013-07-09 21:37:14 +000075
76 x++;
77 }
78}
79
mtklein@google.com0dc546c2013-08-26 16:21:35 +000080uint16_t PackTo565(int /*a*/, int r, int g, int b) {
81 return SkPack888ToRGB16(r, g, b);
82}
83
84} // namespace
85
86void highQualityFilter32(const SkBitmapProcState& s, int x, int y, SkPMColor* SK_RESTRICT colors, int count) {
87 highQualityFilter(&SkPackARGB32, s, x, y, colors, count);
88}
89
90void highQualityFilter16(const SkBitmapProcState& s, int x, int y, uint16_t* SK_RESTRICT colors, int count) {
91 highQualityFilter(&PackTo565, s, x, y, colors, count);
92}
93
94
humper@google.com138ebc32013-07-19 20:20:04 +000095SK_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 +000096
humper@google.com138ebc32013-07-19 20:20:04 +000097SkBitmapFilter *SkBitmapFilter::Allocate() {
humper@google.comb0889472013-07-09 21:37:14 +000098 if (!strcmp(c_bitmapFilter, "mitchell")) {
99 return SkNEW_ARGS(SkMitchellFilter,(1.f/3.f,1.f/3.f));
humper@google.com138ebc32013-07-19 20:20:04 +0000100 } else if (!strcmp(c_bitmapFilter, "lanczos")) {
101 return SkNEW(SkLanczosFilter);
102 } else if (!strcmp(c_bitmapFilter, "hamming")) {
103 return SkNEW(SkHammingFilter);
humper@google.comb0889472013-07-09 21:37:14 +0000104 } else if (!strcmp(c_bitmapFilter, "gaussian")) {
105 return SkNEW_ARGS(SkGaussianFilter,(2));
106 } else if (!strcmp(c_bitmapFilter, "triangle")) {
107 return SkNEW(SkTriangleFilter);
108 } else if (!strcmp(c_bitmapFilter, "box")) {
109 return SkNEW(SkBoxFilter);
110 } else {
mtklein@google.com330313a2013-08-22 15:37:26 +0000111 SkDEBUGFAIL("Unknown filter type");
humper@google.comb0889472013-07-09 21:37:14 +0000112 }
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +0000113
humper@google.comb0889472013-07-09 21:37:14 +0000114 return NULL;
115}
116
mtklein@google.com0dc546c2013-08-26 16:21:35 +0000117bool SkBitmapProcState::setBitmapFilterProcs() {
reed@google.com9cfc83c2013-07-22 17:18:18 +0000118 if (fFilterLevel != SkPaint::kHigh_FilterLevel) {
mtklein@google.com0dc546c2013-08-26 16:21:35 +0000119 return false;
humper@google.com9c96d4b2013-07-14 01:44:59 +0000120 }
121
122 if (fAlphaScale != 256) {
mtklein@google.com0dc546c2013-08-26 16:21:35 +0000123 return false;
humper@google.comb0889472013-07-09 21:37:14 +0000124 }
125
reed@google.com900ecf22014-02-20 20:55:37 +0000126 // TODO: consider supporting other colortypes (e.g. 565, A8)
commit-bot@chromium.org149e9a12014-04-09 20:45:29 +0000127 if (fBitmap->colorType() != kN32_SkColorType) {
mtklein@google.com0dc546c2013-08-26 16:21:35 +0000128 return false;
humper@google.comb0889472013-07-09 21:37:14 +0000129 }
130
131 // TODO: consider supporting repeat and mirror
132 if (SkShader::kClamp_TileMode != fTileModeX || SkShader::kClamp_TileMode != fTileModeY) {
mtklein@google.com0dc546c2013-08-26 16:21:35 +0000133 return false;
humper@google.comb0889472013-07-09 21:37:14 +0000134 }
135
mtklein@google.com0dc546c2013-08-26 16:21:35 +0000136 // TODO: is this right? do we want fBitmapFilter allocated even if we can't set shader procs?
humper@google.comb0889472013-07-09 21:37:14 +0000137 if (fInvType & (SkMatrix::kAffine_Mask | SkMatrix::kScale_Mask)) {
humper@google.com138ebc32013-07-19 20:20:04 +0000138 fBitmapFilter = SkBitmapFilter::Allocate();
humper@google.comb0889472013-07-09 21:37:14 +0000139 }
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +0000140
humper@google.com138ebc32013-07-19 20:20:04 +0000141 if (fInvType & SkMatrix::kScale_Mask) {
mtklein@google.com0dc546c2013-08-26 16:21:35 +0000142 fShaderProc32 = highQualityFilter32;
143 fShaderProc16 = highQualityFilter16;
144 return true;
humper@google.comb0889472013-07-09 21:37:14 +0000145 } else {
mtklein@google.com0dc546c2013-08-26 16:21:35 +0000146 return false;
humper@google.comb0889472013-07-09 21:37:14 +0000147 }
148}