diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index eb2713c557b90..bb5319f176fa2 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -26,6 +26,7 @@ FILE: ../../../flutter/common/task_runners.cc FILE: ../../../flutter/common/task_runners.h FILE: ../../../flutter/flow/compositor_context.cc FILE: ../../../flutter/flow/compositor_context.h +FILE: ../../../flutter/flow/embedded_view_params_unittests.cc FILE: ../../../flutter/flow/embedded_views.cc FILE: ../../../flutter/flow/embedded_views.h FILE: ../../../flutter/flow/gl_context_switch.cc diff --git a/flow/BUILD.gn b/flow/BUILD.gn index a8c3592ccecbf..85c55d2cfba0b 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -130,6 +130,7 @@ executable("flow_unittests") { testonly = true sources = [ + "embedded_view_params_unittests.cc", "flow_run_all_unittests.cc", "flow_test_utils.cc", "flow_test_utils.h", diff --git a/flow/embedded_view_params_unittests.cc b/flow/embedded_view_params_unittests.cc new file mode 100644 index 0000000000000..cb94936e17ddf --- /dev/null +++ b/flow/embedded_view_params_unittests.cc @@ -0,0 +1,98 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/flow/embedded_views.h" +#include "flutter/fml/logging.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { + +TEST(EmbeddedViewParams, GetBoundingRectAfterMutationsWithNoMutations) { + MutatorsStack stack; + SkMatrix matrix; + + EmbeddedViewParams params(matrix, SkSize::Make(1, 1), stack); + const SkRect& rect = params.finalBoundingRect(); + ASSERT_TRUE(SkScalarNearlyEqual(rect.x(), 0)); + ASSERT_TRUE(SkScalarNearlyEqual(rect.y(), 0)); + ASSERT_TRUE(SkScalarNearlyEqual(rect.width(), 1)); + ASSERT_TRUE(SkScalarNearlyEqual(rect.height(), 1)); +} + +TEST(EmbeddedViewParams, GetBoundingRectAfterMutationsWithScale) { + MutatorsStack stack; + SkMatrix matrix = SkMatrix::Scale(2, 2); + stack.PushTransform(matrix); + + EmbeddedViewParams params(matrix, SkSize::Make(1, 1), stack); + const SkRect& rect = params.finalBoundingRect(); + ASSERT_TRUE(SkScalarNearlyEqual(rect.x(), 0)); + ASSERT_TRUE(SkScalarNearlyEqual(rect.y(), 0)); + ASSERT_TRUE(SkScalarNearlyEqual(rect.width(), 2)); + ASSERT_TRUE(SkScalarNearlyEqual(rect.height(), 2)); +} + +TEST(EmbeddedViewParams, GetBoundingRectAfterMutationsWithTranslate) { + MutatorsStack stack; + SkMatrix matrix = SkMatrix::MakeTrans(1, 1); + stack.PushTransform(matrix); + + EmbeddedViewParams params(matrix, SkSize::Make(1, 1), stack); + const SkRect& rect = params.finalBoundingRect(); + ASSERT_TRUE(SkScalarNearlyEqual(rect.x(), 1)); + ASSERT_TRUE(SkScalarNearlyEqual(rect.y(), 1)); + ASSERT_TRUE(SkScalarNearlyEqual(rect.width(), 1)); + ASSERT_TRUE(SkScalarNearlyEqual(rect.height(), 1)); +} + +TEST(EmbeddedViewParams, GetBoundingRectAfterMutationsWithRotation90) { + MutatorsStack stack; + SkMatrix matrix; + matrix.setRotate(90); + stack.PushTransform(matrix); + + EmbeddedViewParams params(matrix, SkSize::Make(1, 1), stack); + const SkRect& rect = params.finalBoundingRect(); + + FML_DLOG(ERROR) << rect.x(); + ASSERT_TRUE(SkScalarNearlyEqual(rect.x(), -1)); + ASSERT_TRUE(SkScalarNearlyEqual(rect.y(), 0)); + ASSERT_TRUE(SkScalarNearlyEqual(rect.width(), 1)); + ASSERT_TRUE(SkScalarNearlyEqual(rect.height(), 1)); +} + +TEST(EmbeddedViewParams, GetBoundingRectAfterMutationsWithRotation45) { + MutatorsStack stack; + SkMatrix matrix; + matrix.setRotate(45); + stack.PushTransform(matrix); + + EmbeddedViewParams params(matrix, SkSize::Make(1, 1), stack); + const SkRect& rect = params.finalBoundingRect(); + ASSERT_TRUE(SkScalarNearlyEqual(rect.x(), -sqrt(2) / 2)); + ASSERT_TRUE(SkScalarNearlyEqual(rect.y(), 0)); + ASSERT_TRUE(SkScalarNearlyEqual(rect.width(), sqrt(2))); + ASSERT_TRUE(SkScalarNearlyEqual(rect.height(), sqrt(2))); +} + +TEST(EmbeddedViewParams, + GetBoundingRectAfterMutationsWithTranslateScaleAndRotation) { + SkMatrix matrix = SkMatrix::MakeTrans(2, 2); + matrix.preScale(3, 3); + matrix.preRotate(90); + + MutatorsStack stack; + stack.PushTransform(matrix); + + EmbeddedViewParams params(matrix, SkSize::Make(1, 1), stack); + const SkRect& rect = params.finalBoundingRect(); + ASSERT_TRUE(SkScalarNearlyEqual(rect.x(), -1)); + ASSERT_TRUE(SkScalarNearlyEqual(rect.y(), 2)); + ASSERT_TRUE(SkScalarNearlyEqual(rect.width(), 3)); + ASSERT_TRUE(SkScalarNearlyEqual(rect.height(), 3)); +} + +} // namespace testing +} // namespace flutter diff --git a/flow/embedded_views.h b/flow/embedded_views.h index 8bbef5a0a3f4d..a8cf65481da0e 100644 --- a/flow/embedded_views.h +++ b/flow/embedded_views.h @@ -186,21 +186,49 @@ class EmbeddedViewParams { public: EmbeddedViewParams() = default; + EmbeddedViewParams(SkMatrix matrix, + SkSize size_points, + MutatorsStack mutators_stack) + : matrix_(matrix), + size_points_(size_points), + mutators_stack_(mutators_stack) { + SkPath path; + SkRect starting_rect = SkRect::MakeSize(size_points); + path.addRect(starting_rect); + path.transform(matrix); + final_bounding_rect_ = path.computeTightBounds(); + } + EmbeddedViewParams(const EmbeddedViewParams& other) { - offsetPixels = other.offsetPixels; - sizePoints = other.sizePoints; - mutatorsStack = other.mutatorsStack; + size_points_ = other.size_points_; + mutators_stack_ = other.mutators_stack_; + matrix_ = other.matrix_; + final_bounding_rect_ = other.final_bounding_rect_; }; - SkPoint offsetPixels; - SkSize sizePoints; - MutatorsStack mutatorsStack; + // The original size of the platform view before any mutation matrix is + // applied. + const SkSize& sizePoints() const { return size_points_; }; + // The mutators stack contains the detailed step by step mutations for this + // platform view. + const MutatorsStack& mutatorsStack() const { return mutators_stack_; }; + // The bounding rect of the platform view after applying all the mutations. + // + // Clippings are ignored. + const SkRect& finalBoundingRect() const { return final_bounding_rect_; } bool operator==(const EmbeddedViewParams& other) const { - return offsetPixels == other.offsetPixels && - sizePoints == other.sizePoints && - mutatorsStack == other.mutatorsStack; + return size_points_ == other.size_points_ && + mutators_stack_ == other.mutators_stack_ && + final_bounding_rect_ == other.final_bounding_rect_ && + matrix_ == other.matrix_; } + + private: + SkMatrix matrix_; + SkSize size_points_; + MutatorsStack mutators_stack_; + SkRect final_bounding_rect_; }; enum class PostPrerollResult { kResubmitFrame, kSuccess }; diff --git a/flow/layers/platform_view_layer.cc b/flow/layers/platform_view_layer.cc index 81c40a99f0d89..551a270b16542 100644 --- a/flow/layers/platform_view_layer.cc +++ b/flow/layers/platform_view_layer.cc @@ -27,11 +27,8 @@ void PlatformViewLayer::Preroll(PrerollContext* context, } context->has_platform_view = true; std::unique_ptr params = - std::make_unique(); - params->offsetPixels = - SkPoint::Make(matrix.getTranslateX(), matrix.getTranslateY()); - params->sizePoints = size_; - params->mutatorsStack = context->mutators_stack; + std::make_unique(matrix, size_, + context->mutators_stack); context->view_embedder->PrerollCompositeEmbeddedView(view_id_, std::move(params)); } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index f590701e7e2cb..474e9f084c1ee 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -407,13 +407,14 @@ void FlutterPlatformViewsController::CompositeWithParams(int view_id, const EmbeddedViewParams& params) { - CGRect frame = CGRectMake(0, 0, params.sizePoints.width(), params.sizePoints.height()); + CGRect frame = CGRectMake(0, 0, params.sizePoints().width(), params.sizePoints().height()); UIView* touchInterceptor = touch_interceptors_[view_id].get(); touchInterceptor.layer.transform = CATransform3DIdentity; touchInterceptor.frame = frame; touchInterceptor.alpha = 1; - int currentClippingCount = CountClips(params.mutatorsStack); + const MutatorsStack& mutatorStack = params.mutatorsStack(); + int currentClippingCount = CountClips(mutatorStack); int previousClippingCount = clip_count_[view_id]; if (currentClippingCount != previousClippingCount) { clip_count_[view_id] = currentClippingCount; @@ -424,7 +425,7 @@ ReconstructClipViewsChain(currentClippingCount, touchInterceptor, oldPlatformViewRoot); root_views_[view_id] = fml::scoped_nsobject([newPlatformViewRoot retain]); } - ApplyMutators(params.mutatorsStack, touchInterceptor); + ApplyMutators(mutatorStack, touchInterceptor); } SkCanvas* FlutterPlatformViewsController::CompositeEmbeddedView(int view_id) { diff --git a/shell/platform/embedder/embedder_layers.cc b/shell/platform/embedder/embedder_layers.cc index 3b634235f820a..4716ea15683dd 100644 --- a/shell/platform/embedder/embedder_layers.cc +++ b/shell/platform/embedder/embedder_layers.cc @@ -108,7 +108,7 @@ void EmbedderLayers::PushPlatformViewLayer( view.struct_size = sizeof(FlutterPlatformView); view.identifier = identifier; - const auto& mutators = params.mutatorsStack; + const auto& mutators = params.mutatorsStack(); std::vector mutations_array; @@ -180,10 +180,10 @@ void EmbedderLayers::PushPlatformViewLayer( layer.platform_view = platform_views_referenced_.back().get(); const auto layer_bounds = - SkRect::MakeXYWH(params.offsetPixels.x(), // - params.offsetPixels.y(), // - params.sizePoints.width() * device_pixel_ratio_, // - params.sizePoints.height() * device_pixel_ratio_ // + SkRect::MakeXYWH(params.finalBoundingRect().x(), // + params.finalBoundingRect().y(), // + params.sizePoints().width() * device_pixel_ratio_, // + params.sizePoints().height() * device_pixel_ratio_ // ); const auto transformed_layer_bounds =