1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "image_painter_utils.h"
16 
17 namespace {
18 // The [GRAY_COLOR_MATRIX] is of dimension [4 x 5], which transforms a RGB source color (R, G, B, A) to the
19 // destination color (R', G', B', A').
20 //
21 // A classic color image to grayscale conversion formula is [Gray = R * 0.3 + G * 0.59 + B * 0.11].
22 // Hence we get the following conversion:
23 //
24 // | M11 M12 M13 M14 M15 |   | R |   | R' |
25 // | M21 M22 M23 M24 M25 |   | G |   | G' |
26 // | M31 M32 M33 M34 M35 | x | B | = | B' |
27 // | M41 M42 M43 M44 M45 |   | A |   | A' |
28 //                           | 1 |
29 const float GRAY_COLOR_MATRIX[20] = { 0.30f, 0.59f, 0.11f, 0, 0, // red
30     0.30f, 0.59f, 0.11f, 0, 0,                                   // green
31     0.30f, 0.59f, 0.11f, 0, 0,                                   // blue
32     0, 0, 0, 1.0f, 0 };                                          // alpha transparency
33 } // namespace
34 
35 namespace OHOS::Ace::NG {
36 #ifndef USE_ROSEN_DRAWING
ToSkRadius(const BorderRadiusArray & radiusXY)37 std::unique_ptr<SkVector[]> ImagePainterUtils::ToSkRadius(const BorderRadiusArray& radiusXY)
38 {
39     auto radii = std::make_unique<SkVector[]>(RADIUS_POINTS_SIZE);
40     if (radiusXY.size() == RADIUS_POINTS_SIZE) {
41         radii[SkRRect::kUpperLeft_Corner].set(
42             SkFloatToScalar(std::max(radiusXY[SkRRect::kUpperLeft_Corner].GetX(), 0.0f)),
43             SkFloatToScalar(std::max(radiusXY[SkRRect::kUpperLeft_Corner].GetY(), 0.0f)));
44         radii[SkRRect::kUpperRight_Corner].set(
45             SkFloatToScalar(std::max(radiusXY[SkRRect::kUpperRight_Corner].GetX(), 0.0f)),
46             SkFloatToScalar(std::max(radiusXY[SkRRect::kUpperRight_Corner].GetY(), 0.0f)));
47         radii[SkRRect::kLowerLeft_Corner].set(
48             SkFloatToScalar(std::max(radiusXY[SkRRect::kLowerRight_Corner].GetX(), 0.0f)),
49             SkFloatToScalar(std::max(radiusXY[SkRRect::kLowerRight_Corner].GetY(), 0.0f)));
50         radii[SkRRect::kLowerRight_Corner].set(
51             SkFloatToScalar(std::max(radiusXY[SkRRect::kLowerLeft_Corner].GetX(), 0.0f)),
52             SkFloatToScalar(std::max(radiusXY[SkRRect::kLowerLeft_Corner].GetY(), 0.0f)));
53     }
54     return radii;
55 }
56 #else
57 std::unique_ptr<RSPoint[]> ImagePainterUtils::ToRSRadius(const BorderRadiusArray& radiusXY)
58 {
59     auto radii = std::make_unique<RSPoint[]>(RADIUS_POINTS_SIZE);
60     if (radiusXY.size() == RADIUS_POINTS_SIZE) {
61         radii[RSRoundRect::TOP_LEFT_POS] =
62             RSPoint(static_cast<RSScalar>(std::max(radiusXY[RSRoundRect::TOP_LEFT_POS].GetX(), 0.0f)),
63                 static_cast<RSScalar>(std::max(radiusXY[RSRoundRect::TOP_LEFT_POS].GetY(), 0.0f)));
64         radii[RSRoundRect::TOP_RIGHT_POS] =
65             RSPoint(static_cast<RSScalar>(std::max(radiusXY[RSRoundRect::TOP_RIGHT_POS].GetX(), 0.0f)),
66                 static_cast<RSScalar>(std::max(radiusXY[RSRoundRect::TOP_RIGHT_POS].GetY(), 0.0f)));
67         radii[RSRoundRect::BOTTOM_LEFT_POS] =
68             RSPoint(static_cast<RSScalar>(std::max(radiusXY[RSRoundRect::BOTTOM_RIGHT_POS].GetX(), 0.0f)),
69                 static_cast<RSScalar>(std::max(radiusXY[RSRoundRect::BOTTOM_RIGHT_POS].GetY(), 0.0f)));
70         radii[RSRoundRect::BOTTOM_RIGHT_POS] =
71             RSPoint(static_cast<RSScalar>(std::max(radiusXY[RSRoundRect::BOTTOM_LEFT_POS].GetX(), 0.0f)),
72                 static_cast<RSScalar>(std::max(radiusXY[RSRoundRect::BOTTOM_LEFT_POS].GetY(), 0.0f)));
73     }
74     return radii;
75 }
76 #endif
77 
78 #ifndef USE_ROSEN_DRAWING
79 
AddFilter(SkPaint & paint,SkSamplingOptions & options,const ImagePaintConfig & config)80 void ImagePainterUtils::AddFilter(SkPaint& paint, SkSamplingOptions& options, const ImagePaintConfig& config)
81 {
82     switch (config.imageInterpolation_) {
83         case ImageInterpolation::LOW: {
84             options = SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone);
85             break;
86         }
87         case ImageInterpolation::MEDIUM: {
88             options = SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear);
89             break;
90         }
91         case ImageInterpolation::HIGH: {
92             options = SkSamplingOptions(SkCubicResampler::Mitchell());
93             break;
94         }
95         default:
96             options = SkSamplingOptions();
97             break;
98     }
99 
100     if (config.colorFilter_.colorFilterMatrix_) {
101         paint.setColorFilter(SkColorFilters::Matrix(config.colorFilter_.colorFilterMatrix_->data()));
102     } else if (ImageRenderMode::TEMPLATE == config.renderMode_) {
103         paint.setColorFilter(SkColorFilters::Matrix(GRAY_COLOR_MATRIX));
104     }
105 }
106 #else
AddFilter(RSBrush & brush,RSSamplingOptions & options,const ImagePaintConfig & config)107 void ImagePainterUtils::AddFilter(RSBrush& brush, RSSamplingOptions& options, const ImagePaintConfig& config)
108 {
109     switch (config.imageInterpolation_) {
110         case ImageInterpolation::LOW: {
111             options = RSSamplingOptions(RSFilterMode::LINEAR, RSMipmapMode::NONE);
112             break;
113         }
114         case ImageInterpolation::MEDIUM: {
115             options = RSSamplingOptions(RSFilterMode::LINEAR, RSMipmapMode::LINEAR);
116             break;
117         }
118         case ImageInterpolation::HIGH: {
119             options = RSSamplingOptions(RSCubicResampler::Mitchell());
120             break;
121         }
122         default:
123             options = RSSamplingOptions();
124             break;
125     }
126 
127     auto filter = brush.GetFilter();
128     if (config.colorFilter_.colorFilterMatrix_) {
129         RSColorMatrix colorMatrix;
130         colorMatrix.SetArray(config.colorFilter_.colorFilterMatrix_->data());
131         filter.SetColorFilter(RSRecordingColorFilter::CreateMatrixColorFilter(colorMatrix));
132     } else if (config.colorFilter_.colorFilterDrawing_) {
133         auto colorFilterSptrAddr = static_cast<std::shared_ptr<RSColorFilter>*>(
134             config.colorFilter_.colorFilterDrawing_->GetDrawingColorFilterSptrAddr());
135         if (colorFilterSptrAddr && (*colorFilterSptrAddr)) {
136             filter.SetColorFilter(*colorFilterSptrAddr);
137         }
138     } else if (ImageRenderMode::TEMPLATE == config.renderMode_) {
139         RSColorMatrix colorMatrix;
140         colorMatrix.SetArray(GRAY_COLOR_MATRIX);
141         filter.SetColorFilter(RSRecordingColorFilter::CreateMatrixColorFilter(colorMatrix));
142     }
143     brush.SetFilter(filter);
144 }
145 #endif
146 
ClipRRect(RSCanvas & canvas,const RSRect & dstRect,const BorderRadiusArray & radiusXY)147 void ImagePainterUtils::ClipRRect(RSCanvas& canvas, const RSRect& dstRect, const BorderRadiusArray& radiusXY)
148 {
149     std::vector<RSPoint> radius(ImagePainterUtils::RADIUS_POINTS_SIZE);
150     // Adapt to the graphical interface and adjust the position of the last two parameters
151     radius[0] = RSPoint(radiusXY[0].GetX(), radiusXY[0].GetY());
152     radius[1] = RSPoint(radiusXY[1].GetX(), radiusXY[1].GetY());
153     radius[2] = RSPoint(radiusXY[3].GetX(), radiusXY[3].GetY());
154     radius[3] = RSPoint(radiusXY[2].GetX(), radiusXY[2].GetY());
155     RSRoundRect rRect(dstRect, radius);
156     canvas.ClipRoundRect(rRect, RSClipOp::INTERSECT, true);
157 }
158 } // namespace OHOS::Ace::NG
159