diff --git a/flow/embedded_views.cc b/flow/embedded_views.cc index 9bbd913748079..737288136ab71 100644 --- a/flow/embedded_views.cc +++ b/flow/embedded_views.cc @@ -20,6 +20,11 @@ void MutatorsStack::pushClipRRect(const SkRRect& rrect) { vector_.push_back(element); }; +void MutatorsStack::pushClipPath(const SkPath& path) { + std::shared_ptr element = std::make_shared(path); + vector_.push_back(element); +}; + void MutatorsStack::pushTransform(const SkMatrix& matrix) { std::shared_ptr element = std::make_shared(matrix); vector_.push_back(element); diff --git a/flow/embedded_views.h b/flow/embedded_views.h index 88cfac45d28b2..337ebb4a567a9 100644 --- a/flow/embedded_views.h +++ b/flow/embedded_views.h @@ -120,7 +120,6 @@ class MutatorsStack { void pushClipRect(const SkRect& rect); void pushClipRRect(const SkRRect& rrect); void pushClipPath(const SkPath& path); - void pushTransform(const SkMatrix& matrix); // Removes the `Mutator` on the top of the stack diff --git a/flow/layers/clip_path_layer.cc b/flow/layers/clip_path_layer.cc index 1d042b14b4ad9..5739172a20c11 100644 --- a/flow/layers/clip_path_layer.cc +++ b/flow/layers/clip_path_layer.cc @@ -60,6 +60,8 @@ void ClipPathLayer::Paint(PaintContext& context) const { SkAutoCanvasRestore save(context.internal_nodes_canvas, true); context.internal_nodes_canvas->clipPath(clip_path_, clip_behavior_ != Clip::hardEdge); + context.mutators_stack.pushClipPath(clip_path_); + if (clip_behavior_ == Clip::antiAliasWithSaveLayer) { context.internal_nodes_canvas->saveLayer(paint_bounds(), nullptr); } @@ -67,6 +69,7 @@ void ClipPathLayer::Paint(PaintContext& context) const { if (clip_behavior_ == Clip::antiAliasWithSaveLayer) { context.internal_nodes_canvas->restore(); } + context.mutators_stack.pop(); } } // namespace flutter diff --git a/flow/mutators_stack_unittests.cc b/flow/mutators_stack_unittests.cc index 06fc266ff52a8..c306eb63780ae 100644 --- a/flow/mutators_stack_unittests.cc +++ b/flow/mutators_stack_unittests.cc @@ -41,6 +41,15 @@ TEST(MutatorsStack, PushClipRRect) { ASSERT_TRUE(iter->get()->rrect() == rrect); } +TEST(MutatorsStack, PushClipPath) { + flutter::MutatorsStack stack; + SkPath path; + stack.pushClipPath(path); + auto iter = stack.bottom(); + ASSERT_TRUE(iter->get()->type() == flutter::MutatorType::clip_path); + ASSERT_TRUE(iter->get()->path() == path); +} + TEST(MutatorsStack, PushTransform) { MutatorsStack stack; SkMatrix matrix; @@ -102,6 +111,8 @@ TEST(MutatorsStack, Equality) { stack.pushClipRect(rect); SkRRect rrect = SkRRect::MakeEmpty(); stack.pushClipRRect(rrect); + SkPath path; + stack.pushClipPath(path); MutatorsStack stackOther; SkMatrix matrixOther = SkMatrix::MakeScale(1, 1); @@ -110,6 +121,8 @@ TEST(MutatorsStack, Equality) { stackOther.pushClipRect(rectOther); SkRRect rrectOther = SkRRect::MakeEmpty(); stackOther.pushClipRRect(rrectOther); + SkPath otherPath; + stackOther.pushClipPath(otherPath); ASSERT_TRUE(stack == stackOther); } @@ -177,6 +190,10 @@ TEST(Mutator, Equality) { Mutator otherMutator3 = Mutator(rrect); ASSERT_TRUE(mutator3 == otherMutator3); + SkPath path; + flutter::Mutator mutator4 = flutter::Mutator(path); + flutter::Mutator otherMutator4 = flutter::Mutator(path); + ASSERT_TRUE(mutator4 == otherMutator4); ASSERT_FALSE(mutator2 == mutator); } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index 47039d6759880..08ace583d48ab 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -261,7 +261,6 @@ } ++iter; } - // Reverse scale based on screen scale. // // The UIKit frame is set based on the logical resolution instead of physical. @@ -363,7 +362,6 @@ UIView* platform_view_root = root_views_[view_id].get(); UIView* overlay = overlays_[view_id]->overlay_view; FML_CHECK(platform_view_root.superview == overlay.superview); - if (platform_view_root.superview == flutter_view) { [flutter_view bringSubviewToFront:platform_view_root]; [flutter_view bringSubviewToFront:overlay]; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index dfa4816f48d38..61ecc4637ca34 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -42,7 +42,6 @@ @end namespace flutter { - // Converts a SkMatrix to CATransform3D. // Certain fields are ignored in CATransform3D since SkMatrix is 3x3 and CATransform3D is 4x4. CATransform3D GetCATransform3DFromSkMatrix(const SkMatrix& matrix); @@ -85,8 +84,8 @@ class FlutterPlatformViewsController { // Returns the `FlutterPlatformView` object associated with the view_id. // // If the `FlutterPlatformViewsController` does not contain any `FlutterPlatformView` object or - // a `FlutterPlatformView` object asscociated with the view_id cannot be found, the method returns - // nil. + // a `FlutterPlatformView` object asscociated with the view_id cannot be found, the method + // returns nil. NSObject* GetPlatformViewByID(int view_id); std::vector GetCurrentCanvases(); @@ -109,8 +108,8 @@ class FlutterPlatformViewsController { std::map>> factories_; std::map>> views_; std::map> touch_interceptors_; - // Mapping a platform view ID to the top most parent view (root_view) who is a direct child to the - // `flutter_view_`. + // Mapping a platform view ID to the top most parent view (root_view) who is a direct child to + // the `flutter_view_`. // // The platform view with the view ID is a child of the root view; If the platform view is not // clipped, and no clipping view is added, the root view will be the intercepting view. @@ -152,6 +151,7 @@ class FlutterPlatformViewsController { void EnsureGLOverlayInitialized(int64_t overlay_id, std::shared_ptr gl_context, GrContext* gr_context); + // Traverse the `mutators_stack` and return the number of clip operations. int CountClips(const MutatorsStack& mutators_stack); @@ -172,10 +172,10 @@ class FlutterPlatformViewsController { // Applies the mutators in the mutators_stack to the UIView chain that was constructed by // `ReconstructClipViewsChain` // - // Clips are applied to the super view with a CALayer mask. Transforms are applied to the current - // view that's at the head of the chain. For example the following mutators stack [T_1, C_2, T_3, - // T_4, C_5, T_6] where T denotes a transform and C denotes a clip, will result in the following - // UIView tree: + // Clips are applied to the super view with a CALayer mask. Transforms are applied to the + // current view that's at the head of the chain. For example the following mutators stack [T_1, + // C_2, T_3, T_4, C_5, T_6] where T denotes a transform and C denotes a clip, will result in the + // following UIView tree: // // C_2 -> C_5 -> PLATFORM_VIEW // (PLATFORM_VIEW is a subview of C_5 which is a subview of C_2) @@ -184,7 +184,6 @@ class FlutterPlatformViewsController { // // After each clip operation, we update the head to the super view of the current head. void ApplyMutators(const MutatorsStack& mutators_stack, UIView* embedded_view); - void CompositeWithParams(int view_id, const flutter::EmbeddedViewParams& params); FML_DISALLOW_COPY_AND_ASSIGN(FlutterPlatformViewsController); diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm index 7afb8c3314478..dc91dde315463 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm @@ -6,6 +6,8 @@ #include "flutter/shell/platform/darwin/ios/ios_surface.h" +static int kMaxPointsInVerb = 4; + namespace flutter { FlutterPlatformViewLayer::FlutterPlatformViewLayer(fml::scoped_nsobject overlay_view, @@ -129,6 +131,76 @@ - (void)clipRRect:(const SkRRect&)clipSkRRect { CGPathRelease(pathRef); } +- (void)clipPath:(const SkPath&)path { + CGMutablePathRef pathRef = CGPathCreateMutable(); + if (!path.isValid()) { + return; + } + if (path.isEmpty()) { + CAShapeLayer* clip = [[CAShapeLayer alloc] init]; + clip.path = pathRef; + self.layer.mask = clip; + CGPathRelease(pathRef); + return; + } + + // Loop through all verbs and translate them into CGPath + SkPath::Iter iter(path, true); + SkPoint pts[kMaxPointsInVerb]; + SkPath::Verb verb = iter.next(pts); + SkPoint last_pt_from_last_verb; + while (verb != SkPath::kDone_Verb) { + if (verb == SkPath::kLine_Verb || verb == SkPath::kQuad_Verb || verb == SkPath::kConic_Verb || + verb == SkPath::kCubic_Verb) { + FML_DCHECK(last_pt_from_last_verb == pts[0]); + } + switch (verb) { + case SkPath::kMove_Verb: { + CGPathMoveToPoint(pathRef, nil, pts[0].x(), pts[0].y()); + last_pt_from_last_verb = pts[0]; + break; + } + case SkPath::kLine_Verb: { + CGPathAddLineToPoint(pathRef, nil, pts[1].x(), pts[1].y()); + last_pt_from_last_verb = pts[1]; + break; + } + case SkPath::kQuad_Verb: { + CGPathAddQuadCurveToPoint(pathRef, nil, pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y()); + last_pt_from_last_verb = pts[2]; + break; + } + case SkPath::kConic_Verb: { + // Conic is not available in quartz, we use quad to approximate. + // TODO(cyanglaz): Better approximate the conic path. + // https://github.com/flutter/flutter/issues/35062 + CGPathAddQuadCurveToPoint(pathRef, nil, pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y()); + last_pt_from_last_verb = pts[2]; + break; + } + case SkPath::kCubic_Verb: { + CGPathAddCurveToPoint(pathRef, nil, pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y(), + pts[3].x(), pts[3].y()); + last_pt_from_last_verb = pts[3]; + break; + } + case SkPath::kClose_Verb: { + CGPathCloseSubpath(pathRef); + break; + } + case SkPath::kDone_Verb: { + break; + } + } + verb = iter.next(pts); + } + + CAShapeLayer* clip = [[CAShapeLayer alloc] init]; + clip.path = pathRef; + self.layer.mask = clip; + CGPathRelease(pathRef); +} + - (void)setClip:(flutter::MutatorType)type rect:(const SkRect&)rect rrect:(const SkRRect&)rrect @@ -143,7 +215,7 @@ - (void)setClip:(flutter::MutatorType)type [self clipRRect:rrect]; break; case flutter::clip_path: - // TODO(cyanglaz): Add clip path + [self clipPath:path]; break; default: break;