1 /*
2 * Copyright (c) 2021-2025 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
16 #include "rs_render_thread_util.h"
17
18 #include "platform/common/rs_log.h"
19 #include "utils/camera3d.h"
20 #ifdef ROSEN_OHOS
21 #include "bundle_mgr_interface.h"
22 #include "iservice_registry.h"
23 #include "system_ability_definition.h"
24 #endif
25
26 namespace OHOS {
27 namespace Rosen {
SrcRectScaleDown(TextureExportBufferDrawParam & params,const RectF & localBounds)28 void RSRenderThreadUtil::SrcRectScaleDown(TextureExportBufferDrawParam& params, const RectF& localBounds)
29 {
30 uint32_t newWidth = static_cast<uint32_t>(params.srcRect.GetWidth());
31 uint32_t newHeight = static_cast<uint32_t>(params.srcRect.GetHeight());
32 // Canvas is able to handle the situation when the window is out of screen, using bounds instead of dst.
33 uint32_t boundsWidth = static_cast<uint32_t>(localBounds.GetWidth());
34 uint32_t boundsHeight = static_cast<uint32_t>(localBounds.GetHeight());
35
36 uint32_t newWidthBoundsHeight = newWidth * boundsHeight;
37 uint32_t newHeightBoundsWidth = newHeight * boundsWidth;
38
39 if (newWidthBoundsHeight > newHeightBoundsWidth) {
40 newWidth = boundsWidth * newHeight / boundsHeight;
41 } else if (newWidthBoundsHeight < newHeightBoundsWidth) {
42 newHeight = boundsHeight * newWidth / boundsWidth;
43 } else {
44 return;
45 }
46
47 uint32_t currentWidth = static_cast<uint32_t>(params.srcRect.GetWidth());
48 uint32_t currentHeight = static_cast<uint32_t>(params.srcRect.GetHeight());
49 if (newWidth < currentWidth) {
50 // the crop is too wide
51 uint32_t dw = currentWidth - newWidth;
52 auto halfdw = dw / 2;
53 params.srcRect = Drawing::Rect(params.srcRect.GetLeft() + static_cast<int32_t>(halfdw), params.srcRect.GetTop(),
54 params.srcRect.GetLeft() + static_cast<int32_t>(halfdw) + static_cast<int32_t>(newWidth),
55 params.srcRect.GetTop() + params.srcRect.GetHeight());
56 } else {
57 // thr crop is too tall
58 uint32_t dh = currentHeight - newHeight;
59 auto halfdh = dh / 2;
60 params.srcRect = Drawing::Rect(params.srcRect.GetLeft(), params.srcRect.GetTop() + static_cast<int32_t>(halfdh),
61 params.srcRect.GetLeft() + params.srcRect.GetWidth(),
62 params.srcRect.GetTop() + static_cast<int32_t>(halfdh) + static_cast<int32_t>(newHeight));
63 }
64 }
65
SrcRectScaleFit(TextureExportBufferDrawParam & params,const RectF & localBounds)66 void RSRenderThreadUtil::SrcRectScaleFit(TextureExportBufferDrawParam& params, const RectF& localBounds)
67 {
68 uint32_t srcWidth = static_cast<uint32_t>(params.srcRect.GetWidth());
69 uint32_t srcHeight = static_cast<uint32_t>(params.srcRect.GetHeight());
70 float newWidth = 0.0f;
71 float newHeight = 0.0f;
72 // Canvas is able to handle the situation when the window is out of screen, using bounds instead of dst.
73 uint32_t boundsWidth = static_cast<uint32_t>(localBounds.GetWidth());
74 uint32_t boundsHeight = static_cast<uint32_t>(localBounds.GetHeight());
75 if (boundsWidth == 0 || boundsHeight == 0 || srcWidth == 0 || srcHeight == 0) {
76 return;
77 }
78
79 if (srcWidth * boundsHeight > srcHeight * boundsWidth) {
80 newWidth = boundsWidth;
81 newHeight = srcHeight * newWidth / srcWidth;
82 } else if (srcWidth * boundsHeight < srcHeight * boundsWidth) {
83 newHeight = boundsHeight;
84 newWidth = newHeight * srcWidth / srcHeight;
85 } else {
86 newWidth = boundsWidth;
87 newHeight = boundsHeight;
88 }
89 newHeight = newHeight * srcHeight / boundsHeight;
90 newWidth = newWidth * srcWidth / boundsWidth;
91 if (newWidth < srcWidth) {
92 float halfdw = (srcWidth - newWidth) / 2;
93 params.dstRect = Drawing::Rect(params.srcRect.GetLeft() + halfdw, params.srcRect.GetTop(),
94 params.srcRect.GetLeft() + halfdw + newWidth, params.srcRect.GetTop() + params.srcRect.GetHeight());
95 } else if (newHeight < srcHeight) {
96 float halfdh = (srcHeight - newHeight) / 2;
97 params.dstRect = Drawing::Rect(params.srcRect.GetLeft(), params.srcRect.GetTop() + halfdh,
98 params.srcRect.GetLeft() + params.srcRect.GetWidth(), params.srcRect.GetTop() + halfdh + newHeight);
99 }
100 }
101
GetFlipTransform(GraphicTransformType transform)102 GraphicTransformType RSRenderThreadUtil::GetFlipTransform(GraphicTransformType transform)
103 {
104 switch (transform) {
105 case GraphicTransformType::GRAPHIC_FLIP_H_ROT90:
106 case GraphicTransformType::GRAPHIC_FLIP_H_ROT180:
107 case GraphicTransformType::GRAPHIC_FLIP_H_ROT270: {
108 return GraphicTransformType::GRAPHIC_FLIP_H;
109 }
110 case GraphicTransformType::GRAPHIC_FLIP_V_ROT90:
111 case GraphicTransformType::GRAPHIC_FLIP_V_ROT180:
112 case GraphicTransformType::GRAPHIC_FLIP_V_ROT270: {
113 return GraphicTransformType::GRAPHIC_FLIP_V;
114 }
115 default: {
116 return transform;
117 }
118 }
119 }
120
FlipMatrix(GraphicTransformType transform,TextureExportBufferDrawParam & params)121 void RSRenderThreadUtil::FlipMatrix(GraphicTransformType transform, TextureExportBufferDrawParam& params)
122 {
123 GraphicTransformType type = GetFlipTransform(transform);
124 if (type != GraphicTransformType::GRAPHIC_FLIP_H && type != GraphicTransformType::GRAPHIC_FLIP_V) {
125 return;
126 }
127
128 const int angle = 180;
129 Drawing::Camera3D camera3D;
130 switch (type) {
131 case GraphicTransformType::GRAPHIC_FLIP_H: {
132 camera3D.RotateYDegrees(angle);
133 break;
134 }
135 case GraphicTransformType::GRAPHIC_FLIP_V: {
136 camera3D.RotateXDegrees(angle);
137 break;
138 }
139 default: {
140 return;
141 }
142 }
143 Drawing::Matrix flip;
144 camera3D.ApplyToMatrix(flip);
145 const float half = 0.5f;
146 flip.PreTranslate(-half * params.dstRect.GetWidth(), -half * params.dstRect.GetHeight());
147 flip.PostTranslate(half * params.dstRect.GetWidth(), half * params.dstRect.GetHeight());
148 params.matrix.PreConcat(flip);
149 }
150
GetSurfaceTransformMatrix(GraphicTransformType rotationTransform,const RectF & bufferBounds)151 Drawing::Matrix RSRenderThreadUtil::GetSurfaceTransformMatrix(
152 GraphicTransformType rotationTransform, const RectF& bufferBounds)
153 {
154 Drawing::Matrix matrix;
155 const float bufferWidth = bufferBounds.GetWidth();
156 const float bufferHeight = bufferBounds.GetHeight();
157
158 switch (rotationTransform) {
159 case GraphicTransformType::GRAPHIC_ROTATE_90: {
160 matrix.PreTranslate(0, bufferHeight);
161 matrix.PreRotate(-90); // rotate 90 degrees anti-clockwise at last.
162 break;
163 }
164 case GraphicTransformType::GRAPHIC_ROTATE_180: {
165 matrix.PreTranslate(bufferWidth, bufferHeight);
166 matrix.PreRotate(-180); // rotate 180 degrees anti-clockwise at last.
167 break;
168 }
169 case GraphicTransformType::GRAPHIC_ROTATE_270: {
170 matrix.PreTranslate(bufferWidth, 0);
171 matrix.PreRotate(-270); // rotate 270 degrees anti-clockwise at last.
172 break;
173 }
174 default:
175 break;
176 }
177 return matrix;
178 }
179
GetGravityMatrix(Gravity gravity,const RectF & bufferBounds,const RectF & bounds)180 Drawing::Matrix RSRenderThreadUtil::GetGravityMatrix(
181 Gravity gravity, const RectF& bufferBounds, const RectF& bounds)
182 {
183 Drawing::Matrix gravityMatrix;
184 auto frameWidth = bufferBounds.GetWidth();
185 auto frameHeight = bufferBounds.GetHeight();
186 const float boundsWidth = bounds.GetWidth();
187 const float boundsHeight = bounds.GetHeight();
188 if (ROSEN_EQ(frameWidth, boundsWidth) && ROSEN_EQ(frameHeight, boundsHeight)) {
189 return gravityMatrix;
190 }
191
192 if (!RSPropertiesPainter::GetGravityMatrix(gravity,
193 RectF {0.0f, 0.0f, boundsWidth, boundsHeight}, frameWidth, frameHeight, gravityMatrix)) {
194 RS_LOGD("RSRenderThreadUtil::DealWithNodeGravity did not obtain gravity matrix.");
195 }
196
197 return gravityMatrix;
198 }
199
GetRotateTransform(GraphicTransformType transform)200 GraphicTransformType RSRenderThreadUtil::GetRotateTransform(GraphicTransformType transform)
201 {
202 switch (transform) {
203 case GraphicTransformType::GRAPHIC_FLIP_H:
204 case GraphicTransformType::GRAPHIC_FLIP_V: {
205 return GraphicTransformType::GRAPHIC_ROTATE_NONE;
206 }
207 case GraphicTransformType::GRAPHIC_FLIP_H_ROT90:
208 case GraphicTransformType::GRAPHIC_FLIP_V_ROT90: {
209 return GraphicTransformType::GRAPHIC_ROTATE_90;
210 }
211 case GraphicTransformType::GRAPHIC_FLIP_H_ROT180:
212 case GraphicTransformType::GRAPHIC_FLIP_V_ROT180: {
213 return GraphicTransformType::GRAPHIC_ROTATE_180;
214 }
215 case GraphicTransformType::GRAPHIC_FLIP_H_ROT270:
216 case GraphicTransformType::GRAPHIC_FLIP_V_ROT270: {
217 return GraphicTransformType::GRAPHIC_ROTATE_270;
218 }
219 default: {
220 return transform;
221 }
222 }
223 }
224
225 #ifdef ROSEN_OHOS
DealWithSurfaceRotationAndGravity(GraphicTransformType transform,Gravity gravity,RectF & localBounds,TextureExportBufferDrawParam & params)226 void RSRenderThreadUtil::DealWithSurfaceRotationAndGravity(GraphicTransformType transform, Gravity gravity,
227 RectF& localBounds, TextureExportBufferDrawParam& params)
228 {
229 auto rotationTransform = GetRotateTransform(transform);
230 RectF bufferBounds = {0.0f, 0.0f, 0.0f, 0.0f};
231 if (params.buffer != nullptr) {
232 bufferBounds = {0.0f, 0.0f, params.buffer->GetSurfaceBufferWidth(), params.buffer->GetSurfaceBufferHeight()};
233 if (rotationTransform == GraphicTransformType::GRAPHIC_ROTATE_90 ||
234 rotationTransform == GraphicTransformType::GRAPHIC_ROTATE_270) {
235 std::swap(bufferBounds.width_, bufferBounds.height_);
236 }
237 }
238 // deal with gravity
239 params.matrix.PreConcat(GetGravityMatrix(gravity, bufferBounds, localBounds));
240 // deal with transformType
241 params.matrix.PreConcat(GetSurfaceTransformMatrix(rotationTransform, bufferBounds));
242
243 if (rotationTransform == GraphicTransformType::GRAPHIC_ROTATE_90 ||
244 rotationTransform == GraphicTransformType::GRAPHIC_ROTATE_270) {
245 // after rotate, we should swap dstRect and bound's width and height.
246 std::swap(localBounds.width_, localBounds.height_);
247 }
248 // because we use the gravity matrix above(which will implicitly includes scale effect),
249 // we must disable the scale effect that from srcRect to dstRect.
250 params.dstRect = params.srcRect;
251 }
252
CreateTextureExportBufferDrawParams(RSSurfaceRenderNode & surfaceNode,GraphicTransformType graphicTransformType,sptr<OHOS::SurfaceBuffer> buffer)253 TextureExportBufferDrawParam RSRenderThreadUtil::CreateTextureExportBufferDrawParams(
254 RSSurfaceRenderNode& surfaceNode, GraphicTransformType graphicTransformType, sptr<OHOS::SurfaceBuffer> buffer)
255 {
256 TextureExportBufferDrawParam params;
257 if (buffer == nullptr) {
258 return params;
259 }
260 params.buffer = buffer;
261 params.srcRect = Drawing::Rect(0, 0, buffer->GetSurfaceBufferWidth(), buffer->GetSurfaceBufferHeight());
262 const auto& property = surfaceNode.GetRenderProperties();
263 const float boundsWidth = property.GetBoundsWidth();
264 const float boundsHeight = property.GetBoundsHeight();
265 params.dstRect = Drawing::Rect(0, 0, boundsWidth, boundsHeight);
266 RectF localBounds = {0.f, 0.f, boundsWidth, boundsHeight};
267 auto gravity = property.GetFrameGravity();
268 DealWithSurfaceRotationAndGravity(graphicTransformType, gravity, localBounds, params);
269 FlipMatrix(graphicTransformType, params);
270 ScalingMode scalingMode = buffer->GetSurfaceBufferScalingMode();
271 if (scalingMode == ScalingMode::SCALING_MODE_SCALE_CROP) {
272 SrcRectScaleDown(params, localBounds);
273 } else if (scalingMode == ScalingMode::SCALING_MODE_SCALE_FIT) {
274 SrcRectScaleFit(params, localBounds);
275 }
276 return params;
277 }
278 #endif
279 } // namespace Rosen
280 } // namespace OHOS