[go: nahoru, domu]

Skip to content

Commit

Permalink
iOS PlatformView clip path (flutter#9478)
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Yang committed Jul 2, 2019
1 parent c19b53c commit a9ee687
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 14 deletions.
5 changes: 5 additions & 0 deletions flow/embedded_views.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ void MutatorsStack::pushClipRRect(const SkRRect& rrect) {
vector_.push_back(element);
};

void MutatorsStack::pushClipPath(const SkPath& path) {
std::shared_ptr<Mutator> element = std::make_shared<Mutator>(path);
vector_.push_back(element);
};

void MutatorsStack::pushTransform(const SkMatrix& matrix) {
std::shared_ptr<Mutator> element = std::make_shared<Mutator>(matrix);
vector_.push_back(element);
Expand Down
1 change: 0 additions & 1 deletion flow/embedded_views.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions flow/layers/clip_path_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,16 @@ 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);
}
PaintChildren(context);
if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
context.internal_nodes_canvas->restore();
}
context.mutators_stack.pop();
}

} // namespace flutter
17 changes: 17 additions & 0 deletions flow/mutators_stack_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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);
}
Expand Down Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,6 @@
}
++iter;
}

// Reverse scale based on screen scale.
//
// The UIKit frame is set based on the logical resolution instead of physical.
Expand Down Expand Up @@ -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];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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<FlutterPlatformView>* GetPlatformViewByID(int view_id);

std::vector<SkCanvas*> GetCurrentCanvases();
Expand All @@ -109,8 +108,8 @@ class FlutterPlatformViewsController {
std::map<std::string, fml::scoped_nsobject<NSObject<FlutterPlatformViewFactory>>> factories_;
std::map<int64_t, fml::scoped_nsobject<NSObject<FlutterPlatformView>>> views_;
std::map<int64_t, fml::scoped_nsobject<FlutterTouchInterceptingView>> 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.
Expand Down Expand Up @@ -152,6 +151,7 @@ class FlutterPlatformViewsController {
void EnsureGLOverlayInitialized(int64_t overlay_id,
std::shared_ptr<IOSGLContext> gl_context,
GrContext* gr_context);

// Traverse the `mutators_stack` and return the number of clip operations.
int CountClips(const MutatorsStack& mutators_stack);

Expand All @@ -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)
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#include "flutter/shell/platform/darwin/ios/ios_surface.h"

static int kMaxPointsInVerb = 4;

namespace flutter {

FlutterPlatformViewLayer::FlutterPlatformViewLayer(fml::scoped_nsobject<UIView> overlay_view,
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down

0 comments on commit a9ee687

Please sign in to comment.