1 /*
2 * Copyright (c) 2021 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 "common/rs_obj_abs_geometry.h"
17 #include "utils/camera3d.h"
18
19 namespace OHOS {
20 namespace Rosen {
21 constexpr unsigned RECT_POINT_NUM = 4;
22 constexpr unsigned LEFT_TOP_POINT = 0;
23 constexpr unsigned RIGHT_TOP_POINT = 1;
24 constexpr unsigned RIGHT_BOTTOM_POINT = 2;
25 constexpr unsigned LEFT_BOTTOM_POINT = 3;
26 constexpr float INCH_TO_PIXEL = 72;
27 constexpr float EPSILON = 1e-6f;
28 constexpr float DEGREE_TO_RADIAN = M_PI / 180;
29
30 RSObjAbsGeometry::RSObjAbsGeometry() = default;
31 RSObjAbsGeometry::~RSObjAbsGeometry() = default;
32
ConcatMatrix(const Drawing::Matrix & matrix)33 void RSObjAbsGeometry::ConcatMatrix(const Drawing::Matrix& matrix)
34 {
35 if (matrix.IsIdentity()) {
36 return;
37 }
38 matrix_.PreConcat(matrix);
39 if (absMatrix_.has_value()) {
40 absMatrix_->PreConcat(matrix);
41 }
42 SetAbsRect();
43 }
44
45 /**
46 * @brief Updates the matrix of the view with respect to its parent view.
47 *
48 * @param parent The parent view of the current view.
49 * @param offset The offset of the current view with respect to its parent.
50 * @param clipRect The optional clipping rectangle of the current view.
51 */
UpdateMatrix(const Drawing::Matrix * parentMatrix,const std::optional<Drawing::Point> & offset)52 void RSObjAbsGeometry::UpdateMatrix(const Drawing::Matrix* parentMatrix, const std::optional<Drawing::Point>& offset)
53 {
54 // Initialize the absolute matrix with the absolute matrix of the parent view if the parent view exists
55 if (parentMatrix == nullptr) {
56 absMatrix_.reset();
57 } else {
58 absMatrix_ = *parentMatrix;
59 if (offset.has_value()) {
60 absMatrix_->PreTranslate(offset->GetX(), offset->GetY());
61 }
62 }
63 // Reset the matrix of the current view
64 matrix_.Reset();
65 // filter invalid width and height
66 if (IsEmpty()) {
67 return;
68 }
69 // If the view has no transformations or only 2D transformations, update the absolute matrix with 2D
70 // transformations
71 if (!trans_ || (ROSEN_EQ(trans_->translateZ_, 0.f) && ROSEN_EQ(trans_->rotationX_, 0.f) &&
72 ROSEN_EQ(trans_->rotationY_, 0.f) && trans_->quaternion_.IsIdentity() && ROSEN_EQ(trans_->scaleZ_, 1.f))) {
73 UpdateAbsMatrix2D();
74 } else {
75 // Otherwise, update the absolute matrix with 3D transformations
76 UpdateAbsMatrix3D();
77 }
78 // If the context matrix of the current view exists, update the current matrix with it
79 if (contextMatrix_.has_value()) {
80 matrix_.PostConcat(*contextMatrix_);
81 }
82 // If the absolute matrix of the current view exists, update it with the context matrix and the current matrix
83 if (absMatrix_.has_value()) {
84 absMatrix_->PreConcat(matrix_);
85 }
86 // Update the absolute rectangle of the current view
87 SetAbsRect();
88 }
89
90 /**
91 * @brief Updates the matrix of the view without its parent view.
92 */
UpdateByMatrixFromSelf()93 void RSObjAbsGeometry::UpdateByMatrixFromSelf()
94 {
95 absMatrix_.reset();
96 matrix_.Reset();
97
98 // If the view has no transformations or only 2D transformations, update the absolute matrix with 2D transformations
99 if (!trans_ || (ROSEN_EQ(trans_->translateZ_, 0.f) && ROSEN_EQ(trans_->rotationX_, 0.f) &&
100 ROSEN_EQ(trans_->rotationY_, 0.f) && trans_->quaternion_.IsIdentity() && ROSEN_EQ(trans_->scaleZ_, 1.f))) {
101 UpdateAbsMatrix2D();
102 } else {
103 // Otherwise, update the absolute matrix with 3D transformations
104 UpdateAbsMatrix3D();
105 }
106
107 // If the context matrix of the view exists, update the current matrix with it
108 if (contextMatrix_.has_value()) {
109 matrix_.PostConcat(*contextMatrix_);
110 }
111
112 // Update the absolute rectangle of the view
113 SetAbsRect();
114 }
115
IsNeedClientCompose() const116 bool RSObjAbsGeometry::IsNeedClientCompose() const
117 {
118 if (!trans_) {
119 return false;
120 }
121 // return false if rotation degree is times of 90
122 return !ROSEN_EQ(std::remainder(trans_->rotation_, 90.f), 0.f, EPSILON);
123 }
124
125 namespace {
ApplySkewToMatrix44(const RSTransform & trans,Drawing::Matrix44 & m44,bool preConcat)126 void ApplySkewToMatrix44(const RSTransform& trans, Drawing::Matrix44& m44, bool preConcat)
127 {
128 if (!ROSEN_EQ(trans.skewX_, 0.f, EPSILON) || !ROSEN_EQ(trans.skewY_, 0.f, EPSILON)) {
129 Drawing::Matrix44 skewM44 {};
130 skewM44.SetMatrix44RowMajor({1.f, trans.skewX_, 0.f, 0.f,
131 trans.skewY_, 1.f, 0.f, 0.f,
132 0.f, 0.f, 1.f, 0.f,
133 0.f, 0.f, 0.f, 1.f});
134 if (preConcat) {
135 m44 = m44 * skewM44;
136 } else {
137 m44 = skewM44 * m44;
138 }
139 }
140 }
141
ApplyPerspToMatrix(const RSTransform & trans,Drawing::Matrix & m,bool preConcat)142 void ApplyPerspToMatrix(const RSTransform& trans, Drawing::Matrix& m, bool preConcat)
143 {
144 if (!ROSEN_EQ(trans.perspX_, 0.f, EPSILON)
145 || !ROSEN_EQ(trans.perspY_, 0.f, EPSILON)
146 || !ROSEN_EQ(trans.perspW_, 1.f, EPSILON)) {
147 Drawing::Matrix perspM {};
148 perspM.SetMatrix(1.f, 0.f, 0.f,
149 0.f, 1.f, 0.f,
150 trans.perspX_, trans.perspY_, trans.perspW_);
151 if (preConcat) {
152 m = m * perspM;
153 } else {
154 m = perspM * m;
155 }
156 }
157 }
158
ApplyPerspToMatrix44(const RSTransform & trans,Drawing::Matrix44 & m44,bool preConcat)159 void ApplyPerspToMatrix44(const RSTransform& trans, Drawing::Matrix44& m44, bool preConcat)
160 {
161 if (!ROSEN_EQ(trans.perspX_, 0.f, EPSILON)
162 || !ROSEN_EQ(trans.perspY_, 0.f, EPSILON)
163 || !ROSEN_EQ(trans.perspZ_, 0.f, EPSILON)
164 || !ROSEN_EQ(trans.perspW_, 1.f, EPSILON)) {
165 Drawing::Matrix44 perspM44 {};
166 perspM44.SetMatrix44RowMajor({1.f, 0.f, 0.f, 0.f,
167 0.f, 1.f, 0.f, 0.f,
168 0.f, 0.f, 1.f, 0.f,
169 trans.perspX_, trans.perspY_, trans.perspZ_, trans.perspW_});
170 if (preConcat) {
171 m44 = m44 * perspM44;
172 } else {
173 m44 = perspM44 * m44;
174 }
175 }
176 }
177 }
178
UpdateAbsMatrix2D()179 void RSObjAbsGeometry::UpdateAbsMatrix2D()
180 {
181 if (!trans_) {
182 matrix_.PreTranslate(x_, y_);
183 } else {
184 // Persp
185 if (!ROSEN_EQ(trans_->perspX_, 0.f, EPSILON)
186 || !ROSEN_EQ(trans_->perspY_, 0.f, EPSILON)
187 || !ROSEN_EQ(trans_->perspW_, 1.f, EPSILON)) {
188 matrix_.PreTranslate(trans_->pivotX_ * width_, trans_->pivotY_ * height_);
189 ApplyPerspToMatrix(trans_.value(), matrix_, true);
190 matrix_.PreTranslate(-trans_->pivotX_ * width_, -trans_->pivotY_ * height_);
191 }
192
193 // Local Translate
194 if (!ROSEN_EQ(trans_->translateX_, 0.f, EPSILON) || !ROSEN_EQ(trans_->translateY_, 0.f, EPSILON)) {
195 matrix_.PreTranslate(trans_->translateX_, trans_->translateY_);
196 }
197
198 // rotation
199 if (!ROSEN_EQ(trans_->rotation_, 0.f, EPSILON)) {
200 matrix_.PreRotate(trans_->rotation_, trans_->pivotX_ * width_, trans_->pivotY_ * height_);
201 }
202
203 // Skew
204 if (!ROSEN_EQ(trans_->skewX_, 0.f, EPSILON) || !ROSEN_EQ(trans_->skewY_, 0.f, EPSILON)) {
205 matrix_.PreSkew(trans_->skewX_, trans_->skewY_, trans_->pivotX_ * width_, trans_->pivotY_ * height_);
206 }
207
208 // Scale
209 if (!ROSEN_EQ(trans_->scaleX_, 1.f) || !ROSEN_EQ(trans_->scaleY_, 1.f)) {
210 matrix_.PreScale(trans_->scaleX_, trans_->scaleY_, trans_->pivotX_ * width_, trans_->pivotY_ * height_);
211 }
212
213 // Global Translate
214 if (!ROSEN_EQ(x_, 0.f, EPSILON) || !ROSEN_EQ(y_, 0.f, EPSILON)) {
215 matrix_.PostTranslate(x_, y_);
216 }
217 }
218 }
219
220 /**
221 * Update the absolute matrix in 3D space
222 */
UpdateAbsMatrix3D()223 void RSObjAbsGeometry::UpdateAbsMatrix3D()
224 {
225 // If the view has a non-identity quaternion, apply 3D transformations
226 if (!trans_->quaternion_.IsIdentity()) {
227 Drawing::Matrix44 matrix3D;
228 // Pivot
229 matrix3D.Translate(trans_->pivotX_ * width_, trans_->pivotY_ * height_, 0);
230
231 // Persp
232 ApplyPerspToMatrix44(trans_.value(), matrix3D, true);
233
234 // Translate
235 matrix3D.PreTranslate(trans_->translateX_, trans_->translateY_, trans_->translateZ_);
236
237 // Rotate
238 float x = trans_->quaternion_[0];
239 float y = trans_->quaternion_[1];
240 float z = trans_->quaternion_[2];
241 float w = trans_->quaternion_[3];
242 float magnitudeRecp = 1.0f / sqrt((x * x) + (y * y) + (z * z) + (w * w));
243 x *= magnitudeRecp;
244 y *= magnitudeRecp;
245 z *= magnitudeRecp;
246 w *= magnitudeRecp;
247 Drawing::Matrix44::Buffer buffer = {
248 1.f - 2.f * (y * y + z * z), 2.f * (x * y + z * w), 2.f * (x * z - y * w), 0, // m00 ~ m30
249 2.f * (x * y - z * w), 1.f - 2.f * (x * x + z * z), 2.f * (y * z + x * w), 0, // m01 ~ m31
250 2.f * (x * z + y * w), 2.f * (y * z - x * w), 1.f - 2.f * (x * x + y * y), 0, // m02 ~ m32
251 0, 0, 0, 1 }; // m03 ~ m33
252 Drawing::Matrix44 matrix4;
253 matrix4.SetMatrix44ColMajor(buffer);
254 matrix3D = matrix3D * matrix4;
255
256 // Skew
257 ApplySkewToMatrix44(trans_.value(), matrix3D, true);
258
259 // Scale
260 if (!ROSEN_EQ(trans_->scaleX_, 1.f) || !ROSEN_EQ(trans_->scaleY_, 1.f) || !ROSEN_EQ(trans_->scaleZ_, 1.f)) {
261 matrix3D.PreScale(trans_->scaleX_, trans_->scaleY_, trans_->scaleZ_);
262 }
263
264 // Translate
265 matrix3D.PreTranslate(-trans_->pivotX_ * width_, -trans_->pivotY_ * height_, 0);
266
267 matrix3D.PostTranslate(x_, y_);
268
269 // Concatenate the 3D matrix with the 2D matrix
270 matrix_.PreConcat(matrix3D);
271 } else {
272 Drawing::Matrix matrix3D;
273 Drawing::Camera3D camera;
274 // Z Position
275 if (isZApplicableCamera3D_) {
276 camera.Translate(0, 0, z_ + trans_->translateZ_);
277 } else {
278 camera.Translate(0, 0, trans_->translateZ_);
279 }
280
281 // Set camera distance
282 if (trans_->cameraDistance_ == 0) {
283 float zOffSet = sqrt(width_ * width_ + height_ * height_) / 2;
284 camera.SetCameraPos(0, 0, camera.GetCameraPosZ() - zOffSet / INCH_TO_PIXEL);
285 } else {
286 camera.SetCameraPos(0, 0, trans_->cameraDistance_);
287 }
288 // Rotate
289 if (!ROSEN_EQ(trans_->pivotZ_, 0.f, EPSILON)) {
290 camera.Translate(-sin(trans_->rotationY_ * DEGREE_TO_RADIAN) * trans_->pivotZ_,
291 -sin(trans_->rotationX_ * DEGREE_TO_RADIAN) * trans_->pivotZ_,
292 (1 - cos(trans_->rotationX_ * DEGREE_TO_RADIAN) * cos(trans_->rotationY_ * DEGREE_TO_RADIAN)) *
293 trans_->pivotZ_);
294 }
295 camera.RotateXDegrees(-trans_->rotationX_);
296 camera.RotateYDegrees(-trans_->rotationY_);
297 camera.RotateZDegrees(-trans_->rotation_);
298 camera.ApplyToMatrix(matrix3D);
299 // Skew
300 if (!ROSEN_EQ(trans_->skewX_, 0.f, EPSILON) || !ROSEN_EQ(trans_->skewY_, 0.f, EPSILON)) {
301 matrix3D.PreSkew(trans_->skewX_, trans_->skewY_);
302 }
303 // Scale
304 if (!ROSEN_EQ(trans_->scaleX_, 1.f) || !ROSEN_EQ(trans_->scaleY_, 1.f)) {
305 matrix3D.PreScale(trans_->scaleX_, trans_->scaleY_);
306 }
307 // Pivot
308 matrix3D.PreTranslate(-trans_->pivotX_ * width_, -trans_->pivotY_ * height_);
309
310 // Translate
311 matrix3D.PostTranslate(x_ + trans_->translateX_, y_ + trans_->translateY_);
312 // PostPersp
313 ApplyPerspToMatrix(trans_.value(), matrix3D, false);
314 // Pivot
315 matrix3D.PostTranslate(trans_->pivotX_ * width_, trans_->pivotY_ * height_);
316
317 // Concatenate the 3D matrix with the 2D matrix
318 matrix_.PreConcat(matrix3D);
319 }
320 }
321
SetAbsRect()322 void RSObjAbsGeometry::SetAbsRect()
323 {
324 absRect_ = MapAbsRect(RectF(0.f, 0.f, width_, height_));
325 }
326
DeflateToRectI(const RectF & rect)327 RectI RSObjAbsGeometry::DeflateToRectI(const RectF& rect)
328 {
329 RectI dstRect;
330 dstRect.left_ = static_cast<int>(std::ceil(rect.GetLeft()));
331 dstRect.top_ = static_cast<int>(std::ceil(rect.GetTop()));
332 dstRect.width_ = static_cast<int>(std::floor(rect.GetRight() - dstRect.left_));
333 dstRect.height_ = static_cast<int>(std::floor(rect.GetBottom() - dstRect.top_));
334 return dstRect;
335 }
336
InflateToRectI(const RectF & rect)337 RectI RSObjAbsGeometry::InflateToRectI(const RectF& rect)
338 {
339 RectI dstRect;
340 dstRect.left_ = static_cast<int>(std::floor(rect.GetLeft()));
341 dstRect.top_ = static_cast<int>(std::floor(rect.GetTop()));
342 dstRect.width_ = static_cast<int>(std::ceil(rect.GetRight() - dstRect.left_));
343 dstRect.height_ = static_cast<int>(std::ceil(rect.GetBottom() - dstRect.top_));
344 return dstRect;
345 }
346
MapRectWithoutRounding(const RectF & rect,const Drawing::Matrix & matrix)347 RectF RSObjAbsGeometry::MapRectWithoutRounding(const RectF& rect, const Drawing::Matrix& matrix)
348 {
349 RectF absRect;
350 // Check if the matrix has skew or negative scaling
351 if (!ROSEN_EQ(matrix.Get(Drawing::Matrix::PERSP_0), 0.f, EPSILON) ||
352 !ROSEN_EQ(matrix.Get(Drawing::Matrix::PERSP_1), 0.f, EPSILON) ||
353 !ROSEN_EQ(matrix.Get(Drawing::Matrix::PERSP_2), 0.f, EPSILON)) {
354 Drawing::RectF src(rect.GetLeft(), rect.GetTop(), rect.GetRight(), rect.GetBottom());
355 Drawing::RectF dst;
356 matrix.MapRect(dst, src);
357 absRect.left_ = dst.GetLeft();
358 absRect.top_ = dst.GetTop();
359 absRect.width_ = dst.GetRight() - absRect.left_;
360 absRect.height_ = dst.GetBottom() - absRect.top_;
361 } else if (!ROSEN_EQ(matrix.Get(Drawing::Matrix::SKEW_X), 0.f) || (matrix.Get(Drawing::Matrix::SCALE_X) < 0) ||
362 !ROSEN_EQ(matrix.Get(Drawing::Matrix::SKEW_Y), 0.f) || (matrix.Get(Drawing::Matrix::SCALE_Y) < 0)) {
363 // Map the rectangle's points to the absolute matrix
364 std::vector<Drawing::Point> p(RECT_POINT_NUM);
365 p[LEFT_TOP_POINT] = {rect.left_, rect.top_};
366 p[RIGHT_TOP_POINT] = {rect.left_ + rect.width_, rect.top_};
367 p[RIGHT_BOTTOM_POINT] = {rect.left_ + rect.width_, rect.top_ + rect.height_};
368 p[LEFT_BOTTOM_POINT] = {rect.left_, rect.top_ + rect.height_};
369 matrix.MapPoints(p, p, RECT_POINT_NUM);
370
371 Vector2f xRange = GetDataRange(p[LEFT_TOP_POINT].GetX(), p[RIGHT_TOP_POINT].GetX(),
372 p[RIGHT_BOTTOM_POINT].GetX(), p[LEFT_BOTTOM_POINT].GetX());
373 Vector2f yRange = GetDataRange(p[LEFT_TOP_POINT].GetY(), p[RIGHT_TOP_POINT].GetY(),
374 p[RIGHT_BOTTOM_POINT].GetY(), p[LEFT_BOTTOM_POINT].GetY());
375
376 // Set the absolute rectangle's properties
377 absRect.left_ = xRange[0];
378 absRect.top_ = yRange[0];
379 absRect.width_ = xRange[1] - absRect.left_;
380 absRect.height_ = yRange[1] - absRect.top_;
381 } else {
382 // Calculate the absolute rectangle based on the matrix's translation and scaling
383 Drawing::scalar transX = matrix.Get(Drawing::Matrix::TRANS_X);
384 Drawing::scalar transY = matrix.Get(Drawing::Matrix::TRANS_Y);
385 Drawing::scalar scaleX = matrix.Get(Drawing::Matrix::SCALE_X);
386 Drawing::scalar scaleY = matrix.Get(Drawing::Matrix::SCALE_Y);
387 absRect.left_ = rect.left_ * scaleX + transX;
388 absRect.top_ = rect.top_ * scaleY + transY;
389 float right = (rect.left_ + rect.width_) * scaleX + transX;
390 float bottom = (rect.top_ + rect.height_) * scaleY + transY;
391 absRect.width_ = right - absRect.left_;
392 absRect.height_ = bottom - absRect.top_;
393 }
394 return absRect;
395 }
396
397 /**
398 * Map the rectangle with specific matrix
399 * [planning] replaced by Drawing::MapRect
400 * @param rect the rectangle to map
401 * @param matrix the specific to map
402 * @return the mapped absolute rectangle
403 */
MapRect(const RectF & rect,const Drawing::Matrix & matrix)404 RectI RSObjAbsGeometry::MapRect(const RectF& rect, const Drawing::Matrix& matrix)
405 {
406 return InflateToRectI(MapRectWithoutRounding(rect, matrix));
407 }
408
409 /**
410 * Map a set of rectangles (i.e. region) with specific matrix.
411 * @param region: the region to map
412 * @return the mapped region
413 */
MapRegion(const Occlusion::Region & region,const Drawing::Matrix & matrix)414 Occlusion::Region RSObjAbsGeometry::MapRegion(const Occlusion::Region& region, const Drawing::Matrix& matrix)
415 {
416 std::vector<RectI> regionRects = region.GetRegionRectIs();
417 Occlusion::Region mappedRegion;
418 for (const auto& rect : regionRects) {
419 mappedRegion.OrSelf(Occlusion::Region{ Occlusion::Rect { MapRect(rect.ConvertTo<float>(), matrix) } });
420 }
421 return mappedRegion;
422 }
423
424 /**
425 * Map the absolute rectangle
426 * @param rect the rectangle to map
427 * @return the mapped absolute rectangle
428 */
MapAbsRect(const RectF & rect) const429 RectI RSObjAbsGeometry::MapAbsRect(const RectF& rect) const
430 {
431 return MapRect(rect, GetAbsMatrix());
432 }
433
434 /**
435 * Map a set of rectangles (i.e. region) to the absolute coordinates.
436 * @param region: the region to map
437 * @return the mapped absolute region
438 */
MapAbsRegion(const Occlusion::Region & region) const439 Occlusion::Region RSObjAbsGeometry::MapAbsRegion(const Occlusion::Region& region) const
440 {
441 return MapRegion(region, GetAbsMatrix());
442 }
443
GetDataRange(float d0,float d1,float d2,float d3)444 Vector2f RSObjAbsGeometry::GetDataRange(float d0, float d1, float d2, float d3)
445 {
446 float min = d0;
447 float max = d0;
448 if (d0 > d1) {
449 min = d1;
450 } else {
451 max = d1;
452 }
453 if (d2 > d3) {
454 if (min > d3) {
455 min = d3;
456 }
457 if (max < d2) {
458 max = d2;
459 }
460 } else {
461 if (min > d2) {
462 min = d2;
463 }
464 if (max < d3) {
465 max = d3;
466 }
467 }
468 return {min, max};
469 }
470
SetContextMatrix(const std::optional<Drawing::Matrix> & matrix)471 void RSObjAbsGeometry::SetContextMatrix(const std::optional<Drawing::Matrix>& matrix)
472 {
473 contextMatrix_ = matrix;
474 }
475
SetAbsMatrix(const std::optional<Drawing::Matrix> & matrix)476 void RSObjAbsGeometry::SetAbsMatrix(const std::optional<Drawing::Matrix>& matrix)
477 {
478 absMatrix_ = matrix;
479 }
480
GetMatrix() const481 const Drawing::Matrix& RSObjAbsGeometry::GetMatrix() const
482 {
483 return matrix_;
484 }
485
GetAbsMatrix() const486 const Drawing::Matrix& RSObjAbsGeometry::GetAbsMatrix() const
487 {
488 // if absMatrix_ is empty, return matrix_ instead
489 return absMatrix_ ? *absMatrix_ : matrix_;
490 }
491 } // namespace Rosen
492 } // namespace OHOS
493