1/*
2 * Copyright 2019 Google LLC
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
8#include "include/core/SkMatrix.h"
9#include "src/core/SkImageFilterTypes.h"
10#include "src/core/SkImageFilter_Base.h"
11
12// Both [I]Vectors and Sk[I]Sizes are transformed as non-positioned values, i.e. go through
13// mapVectors() not mapPoints().
14static SkIVector map_as_vector(int32_t x, int32_t y, const SkMatrix& matrix) {
15 SkVector v = SkVector::Make(SkIntToScalar(x), SkIntToScalar(y));
16 matrix.mapVectors(&v, 1);
17 return SkIVector::Make(SkScalarRoundToInt(v.fX), SkScalarRoundToInt(v.fY));
18}
19
20static SkVector map_as_vector(SkScalar x, SkScalar y, const SkMatrix& matrix) {
21 SkVector v = SkVector::Make(x, y);
22 matrix.mapVectors(&v, 1);
23 return v;
24}
25
26namespace skif {
27
28Mapping Mapping::Make(const SkMatrix& ctm, const SkImageFilter* filter) {
29 SkMatrix remainder, layer;
30 SkSize scale;
31 if (ctm.isScaleTranslate() || as_IFB(filter)->canHandleComplexCTM()) {
32 // It doesn't matter what type of matrix ctm is, we can have layer space be equivalent to
33 // device space.
34 remainder = SkMatrix::I();
35 layer = ctm;
36 } else if (ctm.decomposeScale(&scale, &remainder)) {
37 // TODO (michaelludwig) - Should maybe strip out any fractional part of the translation in
38 // 'ctm' so that can be incorporated during regular drawing, instead of by resampling the
39 // filtered image.
40 layer = SkMatrix::MakeScale(scale.fWidth, scale.fHeight);
41 } else {
42 // Perspective
43 // TODO (michaelludwig) - Should investigate choosing a scale factor for the layer matrix
44 // that minimizes the aliasing in the final draw.
45 remainder = ctm;
46 layer = SkMatrix::I();
47 }
48 return Mapping(remainder, layer);
49}
50
51// Instantiate map specializations for the 6 geometric types used during filtering
52template<>
53SkIRect Mapping::map<SkIRect>(const SkIRect& geom, const SkMatrix& matrix) {
54 return matrix.mapRect(SkRect::Make(geom)).roundOut();
55}
56
57template<>
58SkRect Mapping::map<SkRect>(const SkRect& geom, const SkMatrix& matrix) {
59 return matrix.mapRect(geom);
60}
61
62template<>
63SkIPoint Mapping::map<SkIPoint>(const SkIPoint& geom, const SkMatrix& matrix) {
64 SkPoint p = SkPoint::Make(SkIntToScalar(geom.fX), SkIntToScalar(geom.fY));
65 matrix.mapPoints(&p, 1);
66 return SkIPoint::Make(SkScalarRoundToInt(p.fX), SkScalarRoundToInt(p.fY));
67}
68
69template<>
70SkPoint Mapping::map<SkPoint>(const SkPoint& geom, const SkMatrix& matrix) {
71 SkPoint p;
72 matrix.mapPoints(&p, &geom, 1);
73 return p;
74}
75
76template<>
77IVector Mapping::map<IVector>(const IVector& geom, const SkMatrix& matrix) {
78 return IVector(map_as_vector(geom.fX, geom.fY, matrix));
79}
80
81template<>
82Vector Mapping::map<Vector>(const Vector& geom, const SkMatrix& matrix) {
83 return Vector(map_as_vector(geom.fX, geom.fY, matrix));
84}
85
86template<>
87SkISize Mapping::map<SkISize>(const SkISize& geom, const SkMatrix& matrix) {
88 SkIVector v = map_as_vector(geom.fWidth, geom.fHeight, matrix);
89 return SkISize::Make(v.fX, v.fY);
90}
91
92template<>
93SkSize Mapping::map<SkSize>(const SkSize& geom, const SkMatrix& matrix) {
94 SkVector v = map_as_vector(geom.fWidth, geom.fHeight, matrix);
95 return SkSize::Make(v.fX, v.fY);
96}
97
98} // end namespace skif
99