diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index a8e366a4750d8..4c12c44f45b87 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -80,6 +80,7 @@ ../../../flutter/flow/surface_frame_unittests.cc ../../../flutter/flow/testing ../../../flutter/flow/texture_unittests.cc +../../../flutter/flow/view_slicer_unittests.cc ../../../flutter/flutter_frontend_server ../../../flutter/fml/ascii_trie_unittests.cc ../../../flutter/fml/backtrace_unittests.cc diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index f197935de751c..ae19a7e9828f6 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -41734,6 +41734,8 @@ ORIGIN: ../../../flutter/flow/surface.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/flow/surface.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/flow/surface_frame.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/flow/surface_frame.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/flow/view_slicer.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/flow/view_slicer.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/flutter_vma/flutter_skia_vma.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/flutter_vma/flutter_skia_vma.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/flutter_vma/flutter_vma.cc + ../../../flutter/LICENSE @@ -44607,6 +44609,8 @@ FILE: ../../../flutter/flow/surface.cc FILE: ../../../flutter/flow/surface.h FILE: ../../../flutter/flow/surface_frame.cc FILE: ../../../flutter/flow/surface_frame.h +FILE: ../../../flutter/flow/view_slicer.cc +FILE: ../../../flutter/flow/view_slicer.h FILE: ../../../flutter/flutter_vma/flutter_skia_vma.cc FILE: ../../../flutter/flutter_vma/flutter_skia_vma.h FILE: ../../../flutter/flutter_vma/flutter_vma.cc diff --git a/flow/BUILD.gn b/flow/BUILD.gn index 9ea33535d7070..cfa3fbe1f8712 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -88,6 +88,8 @@ source_set("flow") { "surface.h", "surface_frame.cc", "surface_frame.h", + "view_slicer.cc", + "view_slicer.h", ] public_configs = [ "//flutter:config" ] @@ -183,6 +185,7 @@ if (enable_unittests) { "testing/mock_layer_unittests.cc", "testing/mock_texture_unittests.cc", "texture_unittests.cc", + "view_slicer_unittests.cc", ] deps = [ diff --git a/flow/view_slicer.cc b/flow/view_slicer.cc new file mode 100644 index 0000000000000..f2d7afea1f3d8 --- /dev/null +++ b/flow/view_slicer.cc @@ -0,0 +1,116 @@ +// 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/view_slicer.h" + +#include +#include "flow/embedded_views.h" +#include "fml/logging.h" + +namespace flutter { + +std::unordered_map SliceViews( + DlCanvas* background_canvas, + const std::vector& composition_order, + const std::unordered_map>& + slices, + const std::unordered_map& view_rects) { + std::unordered_map overlay_layers; + + auto current_frame_view_count = composition_order.size(); + + // Restore the clip context after exiting this method since it's changed + // below. + DlAutoCanvasRestore save(background_canvas, /*do_save=*/true); + + for (size_t i = 0; i < current_frame_view_count; i++) { + int64_t view_id = composition_order[i]; + EmbedderViewSlice* slice = slices.at(view_id).get(); + if (slice->canvas() == nullptr) { + continue; + } + + slice->end_recording(); + + SkRect full_joined_rect = SkRect::MakeEmpty(); + + // Determinate if Flutter UI intersects with any of the previous + // platform views stacked by z position. + // + // This is done by querying the r-tree that holds the records for the + // picture recorder corresponding to the flow layers added after a platform + // view layer. + for (int j = i; j >= 0; j--) { + int64_t current_view_id = composition_order[j]; + auto maybe_rect = view_rects.find(current_view_id); + FML_DCHECK(maybe_rect != view_rects.end()); + if (maybe_rect == view_rects.end()) { + continue; + } + + SkRect current_view_rect = maybe_rect->second; + const SkIRect rounded_in_platform_view_rect = current_view_rect.roundIn(); + + // Each rect corresponds to a native view that renders Flutter UI. + std::vector intersection_rects = + slice->region(current_view_rect).getRects(); + + // Ignore intersections of single width/height on the edge of the platform + // view. + // This is to address the following performance issue when interleaving + // adjacent platform views and layers: Since we `roundOut` both platform + // view rects and the layer rects, as long as the coordinate is + // fractional, there will be an intersection of a single pixel width (or + // height) after rounding out, even if they do not intersect before + // rounding out. We have to round out both platform view rect and the + // layer rect. Rounding in platform view rect will result in missing pixel + // on the intersection edge. Rounding in layer rect will result in missing + // pixel on the edge of the layer on top of the platform view. + for (auto it = intersection_rects.begin(); it != intersection_rects.end(); + /*no-op*/) { + // If intersection_rect does not intersect with the *rounded in* + // platform view rect, then the intersection must be a single pixel + // width (or height) on edge. + if (!SkIRect::Intersects(*it, rounded_in_platform_view_rect)) { + it = intersection_rects.erase(it); + } else { + ++it; + } + } + + // Limit the number of native views, so it doesn't grow forever. + // + // In this case, the rects are merged into a single one that is the union + // of all the rects. + SkRect partial_joined_rect = SkRect::MakeEmpty(); + for (const SkIRect& rect : intersection_rects) { + partial_joined_rect.join(SkRect::Make(rect)); + } + + // Get the intersection rect with the `current_view_rect`, + partial_joined_rect.intersect(SkRect::Make(current_view_rect.roundOut())); + + // Join the `partial_joined_rect` into `full_joined_rect` to get the rect + // above the current `slice` + full_joined_rect.join(partial_joined_rect); + } + + if (!full_joined_rect.isEmpty()) { + overlay_layers.insert({view_id, full_joined_rect}); + + // Clip the background canvas, so it doesn't contain any of the pixels + // drawn on the overlay layer. + background_canvas->ClipRect(full_joined_rect, + DlCanvas::ClipOp::kDifference); + } + slice->render_into(background_canvas); + } + + // Manually trigger the DlAutoCanvasRestore before we submit the frame + save.Restore(); + + return overlay_layers; +} + +} // namespace flutter diff --git a/flow/view_slicer.h b/flow/view_slicer.h new file mode 100644 index 0000000000000..74f5f5eafc354 --- /dev/null +++ b/flow/view_slicer.h @@ -0,0 +1,25 @@ +// 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. + +#ifndef FLUTTER_FLOW_VIEW_SLICER_H_ +#define FLUTTER_FLOW_VIEW_SLICER_H_ + +#include +#include "display_list/dl_canvas.h" +#include "flow/embedded_views.h" + +namespace flutter { + +/// @brief Compute the required overlay layers and clip the view slices +/// according to the size and position of the platform views. +std::unordered_map SliceViews( + DlCanvas* background_canvas, + const std::vector& composition_order, + const std::unordered_map>& + slices, + const std::unordered_map& view_rects); + +} // namespace flutter + +#endif // FLUTTER_FLOW_VIEW_SLICER_H_ diff --git a/flow/view_slicer_unittests.cc b/flow/view_slicer_unittests.cc new file mode 100644 index 0000000000000..12829b07fb6f6 --- /dev/null +++ b/flow/view_slicer_unittests.cc @@ -0,0 +1,138 @@ +// 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 +#include "display_list/dl_builder.h" +#include "flow/embedded_views.h" +#include "flutter/flow/view_slicer.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { + +namespace { +void AddSliceOfSize( + std::unordered_map>& slices, + int64_t id, + SkRect rect) { + slices[id] = std::make_unique(rect); + DlPaint paint; + paint.setColor(DlColor::kBlack()); + slices[id]->canvas()->DrawRect(rect, paint); +} +} // namespace + +TEST(ViewSlicerTest, CanSlicerNonOverlappingViews) { + DisplayListBuilder builder(SkRect::MakeLTRB(0, 0, 100, 100)); + + std::vector composition_order = {1}; + std::unordered_map> slices; + AddSliceOfSize(slices, 1, SkRect::MakeLTRB(99, 99, 100, 100)); + + std::unordered_map view_rects = { + {1, SkRect::MakeLTRB(50, 50, 60, 60)}}; + + auto computed_overlays = + SliceViews(&builder, composition_order, slices, view_rects); + + EXPECT_TRUE(computed_overlays.empty()); +} + +TEST(ViewSlicerTest, IgnoresFractionalOverlaps) { + DisplayListBuilder builder(SkRect::MakeLTRB(0, 0, 100, 100)); + + std::vector composition_order = {1}; + std::unordered_map> slices; + AddSliceOfSize(slices, 1, SkRect::MakeLTRB(0, 0, 50.49, 50.49)); + + std::unordered_map view_rects = { + {1, SkRect::MakeLTRB(50.5, 50.5, 100, 100)}}; + + auto computed_overlays = + SliceViews(&builder, composition_order, slices, view_rects); + + EXPECT_TRUE(computed_overlays.empty()); +} + +TEST(ViewSlicerTest, ComputesOverlapWith1PV) { + DisplayListBuilder builder(SkRect::MakeLTRB(0, 0, 100, 100)); + + std::vector composition_order = {1}; + std::unordered_map> slices; + AddSliceOfSize(slices, 1, SkRect::MakeLTRB(0, 0, 50, 50)); + + std::unordered_map view_rects = { + {1, SkRect::MakeLTRB(0, 0, 100, 100)}}; + + auto computed_overlays = + SliceViews(&builder, composition_order, slices, view_rects); + + EXPECT_EQ(computed_overlays.size(), 1u); + auto overlay = computed_overlays.find(1); + ASSERT_NE(overlay, computed_overlays.end()); + + EXPECT_EQ(overlay->second, SkRect::MakeLTRB(0, 0, 50, 50)); +} + +TEST(ViewSlicerTest, ComputesOverlapWith2PV) { + DisplayListBuilder builder(SkRect::MakeLTRB(0, 0, 100, 100)); + + std::vector composition_order = {1, 2}; + std::unordered_map> slices; + AddSliceOfSize(slices, 1, SkRect::MakeLTRB(0, 0, 50, 50)); + AddSliceOfSize(slices, 2, SkRect::MakeLTRB(50, 50, 100, 100)); + + std::unordered_map view_rects = { + {1, SkRect::MakeLTRB(0, 0, 50, 50)}, // + {2, SkRect::MakeLTRB(50, 50, 100, 100)}, // + }; + + auto computed_overlays = + SliceViews(&builder, composition_order, slices, view_rects); + + EXPECT_EQ(computed_overlays.size(), 2u); + + auto overlay = computed_overlays.find(1); + ASSERT_NE(overlay, computed_overlays.end()); + + EXPECT_EQ(overlay->second, SkRect::MakeLTRB(0, 0, 50, 50)); + + overlay = computed_overlays.find(2); + ASSERT_NE(overlay, computed_overlays.end()); + EXPECT_EQ(overlay->second, SkRect::MakeLTRB(50, 50, 100, 100)); +} + +TEST(ViewSlicerTest, OverlappingTwoPVs) { + DisplayListBuilder builder(SkRect::MakeLTRB(0, 0, 100, 100)); + + std::vector composition_order = {1, 2}; + std::unordered_map> slices; + // This embeded view overlaps both platform views: + // + // [ A [ ]] + // [_____[ C ]] + // [ B [ ]] + // [ ] + AddSliceOfSize(slices, 1, SkRect::MakeLTRB(0, 0, 0, 0)); + AddSliceOfSize(slices, 2, SkRect::MakeLTRB(0, 0, 100, 100)); + + std::unordered_map view_rects = { + {1, SkRect::MakeLTRB(0, 0, 50, 50)}, // + {2, SkRect::MakeLTRB(50, 50, 100, 100)}, // + }; + + auto computed_overlays = + SliceViews(&builder, composition_order, slices, view_rects); + + EXPECT_EQ(computed_overlays.size(), 1u); + + auto overlay = computed_overlays.find(2); + ASSERT_NE(overlay, computed_overlays.end()); + + // We create a single overlay for both overlapping sections. + EXPECT_EQ(overlay->second, SkRect::MakeLTRB(0, 0, 100, 100)); +} + +} // namespace testing +} // namespace flutter diff --git a/shell/platform/android/external_view_embedder/external_view_embedder.cc b/shell/platform/android/external_view_embedder/external_view_embedder.cc index f6ce9eb161273..a957df9a54042 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder.cc +++ b/shell/platform/android/external_view_embedder/external_view_embedder.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "flutter/shell/platform/android/external_view_embedder/external_view_embedder.h" +#include "flow/view_slicer.h" #include "flutter/common/constants.h" #include "flutter/fml/synchronization/waitable_event.h" #include "flutter/fml/trace_event.h" @@ -78,72 +79,17 @@ void AndroidExternalViewEmbedder::SubmitFlutterView( return; } - std::unordered_map overlay_layers; - DlCanvas* background_canvas = frame->Canvas(); - auto current_frame_view_count = composition_order_.size(); - - // Restore the clip context after exiting this method since it's changed - // below. - DlAutoCanvasRestore save(background_canvas, /*do_save=*/true); - - for (size_t i = 0; i < current_frame_view_count; i++) { - int64_t view_id = composition_order_[i]; - EmbedderViewSlice* slice = slices_.at(view_id).get(); - if (slice->canvas() == nullptr) { - continue; - } - - slice->end_recording(); - - SkRect full_joined_rect = SkRect::MakeEmpty(); - - // Determinate if Flutter UI intersects with any of the previous - // platform views stacked by z position. - // - // This is done by querying the r-tree that holds the records for the - // picture recorder corresponding to the flow layers added after a platform - // view layer. - for (ssize_t j = i; j >= 0; j--) { - int64_t current_view_id = composition_order_[j]; - SkRect current_view_rect = GetViewRect(current_view_id); - // The rect above the `current_view_rect` - SkRect partial_joined_rect = SkRect::MakeEmpty(); - // Each rect corresponds to a native view that renders Flutter UI. - std::vector intersection_rects = - slice->region(current_view_rect).getRects(); - - // Limit the number of native views, so it doesn't grow forever. - // - // In this case, the rects are merged into a single one that is the union - // of all the rects. - for (const SkIRect& rect : intersection_rects) { - partial_joined_rect.join(SkRect::Make(rect)); - } - // Get the intersection rect with the `current_view_rect`, - partial_joined_rect.intersect(current_view_rect); - // Join the `partial_joined_rect` into `full_joined_rect` to get the rect - // above the current `slice` - full_joined_rect.join(partial_joined_rect); - } - if (!full_joined_rect.isEmpty()) { - // Subpixels in the platform may not align with the canvas subpixels. - // - // To workaround it, round the floating point bounds and make the rect - // slightly larger. - // - // For example, {0.3, 0.5, 3.1, 4.7} becomes {0, 0, 4, 5}. - full_joined_rect.set(full_joined_rect.roundOut()); - overlay_layers.insert({view_id, full_joined_rect}); - // Clip the background canvas, so it doesn't contain any of the pixels - // drawn on the overlay layer. - background_canvas->ClipRect(full_joined_rect, - DlCanvas::ClipOp::kDifference); - } - slice->render_into(background_canvas); + std::unordered_map view_rects; + for (auto platform_id : composition_order_) { + view_rects[platform_id] = GetViewRect(platform_id); } - // Manually trigger the DlAutoCanvasRestore before we submit the frame - save.Restore(); + std::unordered_map overlay_layers = + SliceViews(frame->Canvas(), // + composition_order_, // + slices_, // + view_rects // + ); // Submit the background canvas frame before switching the GL context to // the overlay surfaces. diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index 551be716b15de..e3b3d94e9dd03 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -6,6 +6,7 @@ #include +#include "flutter/flow/view_slicer.h" #include "flutter/fml/platform/darwin/scoped_nsobject.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" @@ -672,102 +673,37 @@ static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect, DlCanvas* background_canvas = frame->Canvas(); - // Resolve all pending GPU operations before allocating a new surface. - background_canvas->Flush(); + std::unordered_map view_rects; + for (auto view_id : composition_order_) { + view_rects[view_id] = GetPlatformViewRect(view_id); + } - // Clipping the background canvas before drawing the picture recorders requires - // saving and restoring the clip context. - DlAutoCanvasRestore save(background_canvas, /*do_save=*/true); + std::unordered_map overlay_layers = + SliceViews(background_canvas, composition_order_, slices_, view_rects); - // Maps a platform view id to a vector of `FlutterPlatformViewLayer`. LayersMap platform_view_layers; - auto did_submit = true; - auto num_platform_views = composition_order_.size(); - - // TODO(hellohuanlin) this double for-loop is expensive with wasted computations. - // See: https://github.com/flutter/flutter/issues/145802 - for (size_t i = 0; i < num_platform_views; i++) { - int64_t platform_view_id = composition_order_[i]; - EmbedderViewSlice* slice = slices_[platform_view_id].get(); - slice->end_recording(); - - // Check if the current picture contains overlays that intersect with the - // current platform view or any of the previous platform views. - for (size_t j = i + 1; j > 0; j--) { - int64_t current_platform_view_id = composition_order_[j - 1]; - SkRect platform_view_rect = GetPlatformViewRect(current_platform_view_id); - std::vector intersection_rects = slice->region(platform_view_rect).getRects(); - const SkIRect rounded_in_platform_view_rect = platform_view_rect.roundIn(); - // Ignore intersections of single width/height on the edge of the platform view. - // This is to address the following performance issue when interleaving adjacent - // platform views and layers: - // Since we `roundOut` both platform view rects and the layer rects, as long as - // the coordinate is fractional, there will be an intersection of a single pixel width - // (or height) after rounding out, even if they do not intersect before rounding out. - // We have to round out both platform view rect and the layer rect. - // Rounding in platform view rect will result in missing pixel on the intersection edge. - // Rounding in layer rect will result in missing pixel on the edge of the layer on top - // of the platform view. - for (auto it = intersection_rects.begin(); it != intersection_rects.end(); /*no-op*/) { - // If intersection_rect does not intersect with the *rounded in* platform - // view rect, then the intersection must be a single pixel width (or height) on edge. - if (!SkIRect::Intersects(*it, rounded_in_platform_view_rect)) { - it = intersection_rects.erase(it); - } else { - ++it; - } - } - auto allocation_size = intersection_rects.size(); - - // For testing purposes, the overlay id is used to find the overlay view. - // This is the index of the layer for the current platform view. - auto overlay_id = platform_view_layers[current_platform_view_id].size(); - - // If the max number of allocations per platform view is exceeded, - // then join all the rects into a single one. - // - // TODO(egarciad): Consider making this configurable. - // https://github.com/flutter/flutter/issues/52510 - if (allocation_size > kMaxLayerAllocations) { - SkIRect joined_rect = SkIRect::MakeEmpty(); - for (const SkIRect& rect : intersection_rects) { - joined_rect.join(rect); - } - // Replace the rects in the intersection rects list for a single rect that is - // the union of all the rects in the list. - intersection_rects.clear(); - intersection_rects.push_back(joined_rect); - } - for (SkIRect& joined_rect : intersection_rects) { - // Get the intersection rect between the current rect - // and the platform view rect. - joined_rect.intersect(platform_view_rect.roundOut()); - // Clip the background canvas, so it doesn't contain any of the pixels drawn - // on the overlay layer. - background_canvas->ClipRect(SkRect::Make(joined_rect), DlCanvas::ClipOp::kDifference); - // Get a new host layer. - std::shared_ptr layer = - GetLayer(gr_context, // - ios_context, // - slice, // - joined_rect, // - current_platform_view_id, // - overlay_id, // - ((FlutterView*)flutter_view_.get()).pixelFormat // - ); - did_submit &= layer->did_submit_last_frame; - platform_view_layers[current_platform_view_id].push_back(layer); - overlay_id++; - } + int overlay_id = 0; + for (int64_t view_id : composition_order_) { + std::unordered_map::const_iterator overlay = overlay_layers.find(view_id); + if (overlay == overlay_layers.end()) { + continue; } - slice->render_into(background_canvas); + std::shared_ptr layer = + GetLayer(gr_context, // + ios_context, // + slices_[view_id].get(), // + overlay->second, // + view_id, // + overlay_id, // + ((FlutterView*)flutter_view_.get()).pixelFormat // + ); + did_submit &= layer->did_submit_last_frame; + platform_view_layers[view_id].push_back(layer); + overlay_id++; } - // Manually trigger the SkAutoCanvasRestore before we submit the frame - save.Restore(); - // If a layer was allocated in the previous frame, but it's not used in the current frame, // then it can be removed from the scene. RemoveUnusedLayers(); @@ -824,7 +760,7 @@ static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect, GrDirectContext* gr_context, const std::shared_ptr& ios_context, EmbedderViewSlice* slice, - SkIRect rect, + SkRect rect, int64_t view_id, int64_t overlay_id, MTLPixelFormat pixel_format) { @@ -859,7 +795,7 @@ static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect, DlCanvas* overlay_canvas = frame->Canvas(); int restore_count = overlay_canvas->GetSaveCount(); overlay_canvas->Save(); - overlay_canvas->ClipRect(SkRect::Make(rect)); + overlay_canvas->ClipRect(rect); overlay_canvas->Clear(DlColor::kTransparent()); slice->render_into(overlay_canvas); overlay_canvas->RestoreToCount(restore_count); diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index 6373e1feaa40c..7a01af6cb2309 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -284,8 +284,6 @@ class FlutterPlatformViewsController { void PushVisitedPlatformView(int64_t view_id) { visited_platform_views_.push_back(view_id); } private: - static const size_t kMaxLayerAllocations = 2; - using LayersMap = std::map>>; void OnCreate(FlutterMethodCall* call, FlutterResult result) __attribute__((cf_audited_transfer)); @@ -330,7 +328,7 @@ class FlutterPlatformViewsController { std::shared_ptr GetLayer(GrDirectContext* gr_context, const std::shared_ptr& ios_context, EmbedderViewSlice* slice, - SkIRect rect, + SkRect rect, int64_t view_id, int64_t overlay_id, MTLPixelFormat pixel_format); @@ -358,7 +356,7 @@ class FlutterPlatformViewsController { // operation until the next platform view or the end of the last leaf node in the layer tree. // // The Slices are deleted by the FlutterPlatformViewsController.reset(). - std::map> slices_; + std::unordered_map> slices_; fml::scoped_nsobject channel_; fml::scoped_nsobject flutter_view_; diff --git a/testing/scenario_app/ios/Scenarios/ScenariosUITests/UnobstructedPlatformViewTests.m b/testing/scenario_app/ios/Scenarios/ScenariosUITests/UnobstructedPlatformViewTests.m index 5fc45893706f8..3f6014f3b2761 100644 --- a/testing/scenario_app/ios/Scenarios/ScenariosUITests/UnobstructedPlatformViewTests.m +++ b/testing/scenario_app/ios/Scenarios/ScenariosUITests/UnobstructedPlatformViewTests.m @@ -234,21 +234,14 @@ - (void)testMultiplePlatformViewsWithOverlays { XCTAssertEqual(platform_view2.frame.size.width, 250); XCTAssertEqual(platform_view2.frame.size.height, 250); - XCUIElement* overlay1 = app.otherElements[@"platform_view[0].overlay[0]"]; + XCUIElement* overlay1 = app.otherElements[@"platform_view[1].overlay[0]"]; XCTAssertTrue(overlay1.exists); XCTAssertEqual(overlay1.frame.origin.x, 25); - XCTAssertEqual(overlay1.frame.origin.y, 300); + XCTAssertEqual(overlay1.frame.origin.y, 0); XCTAssertEqual(overlay1.frame.size.width, 225); - XCTAssertEqual(overlay1.frame.size.height, 200); - - XCUIElement* overlay2 = app.otherElements[@"platform_view[1].overlay[0]"]; - XCTAssertTrue(overlay2.exists); - XCTAssertEqual(overlay2.frame.origin.x, 25); - XCTAssertEqual(overlay2.frame.origin.y, 0); - XCTAssertEqual(overlay2.frame.size.width, 225); - XCTAssertEqual(overlay2.frame.size.height, 250); + XCTAssertEqual(overlay1.frame.size.height, 500); - XCUIElement* overlayView0 = app.otherElements[@"platform_view[0].overlay_view[0]"]; + XCUIElement* overlayView0 = app.otherElements[@"platform_view[1].overlay_view[0]"]; XCTAssertTrue(overlayView0.exists); // Overlay should always be the same frame as the app. XCTAssertEqualWithAccuracy(overlayView0.frame.origin.x, app.frame.origin.x, kCompareAccuracy); @@ -256,15 +249,6 @@ - (void)testMultiplePlatformViewsWithOverlays { XCTAssertEqualWithAccuracy(overlayView0.frame.size.width, app.frame.size.width, kCompareAccuracy); XCTAssertEqualWithAccuracy(overlayView0.frame.size.height, app.frame.size.height, kCompareAccuracy); - - XCUIElement* overlayView1 = app.otherElements[@"platform_view[1].overlay_view[0]"]; - XCTAssertTrue(overlayView1.exists); - // Overlay should always be the same frame as the app. - XCTAssertEqualWithAccuracy(overlayView1.frame.origin.x, app.frame.origin.x, kCompareAccuracy); - XCTAssertEqualWithAccuracy(overlayView1.frame.origin.y, app.frame.origin.x, kCompareAccuracy); - XCTAssertEqualWithAccuracy(overlayView1.frame.size.width, app.frame.size.width, kCompareAccuracy); - XCTAssertEqualWithAccuracy(overlayView1.frame.size.height, app.frame.size.height, - kCompareAccuracy); } // More then two overlays are merged into a single layer.