Skip to content

Commit 1bf01a1

Browse files
authored
fuchsia: Reliably forward View insets (flutter#25381)
1 parent 258f63a commit 1bf01a1

11 files changed

+148
-78
lines changed

flow/scene_update_context.cc

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -206,17 +206,12 @@ void SceneUpdateContext::UpdateView(int64_t view_id,
206206
return;
207207
}
208208

209-
if (size.width() > 0.f && size.height() > 0.f) {
210-
view_holder->SetProperties(size.width(), size.height(), 0, 0, 0, 0,
211-
view_holder->focusable());
209+
if (override_hit_testable.has_value()) {
210+
view_holder->set_hit_testable(*override_hit_testable);
212211
}
213-
214-
bool hit_testable = override_hit_testable.has_value()
215-
? *override_hit_testable
216-
: view_holder->hit_testable();
212+
view_holder->set_size(size);
217213
view_holder->UpdateScene(session_.get(), top_entity_->embedder_node(), offset,
218-
size, SkScalarRoundToInt(alphaf() * 255),
219-
hit_testable);
214+
SkScalarRoundToInt(alphaf() * 255));
220215

221216
// Assume embedded views are 10 "layers" wide.
222217
next_elevation_ += 10 * kScenicZElevationBetweenLayers;
@@ -238,6 +233,7 @@ void SceneUpdateContext::CreateView(int64_t view_id,
238233
}
239234

240235
void SceneUpdateContext::UpdateView(int64_t view_id,
236+
const SkRect& view_occlusion_hint,
241237
bool hit_testable,
242238
bool focusable) {
243239
auto* view_holder = ViewHolder::FromId(view_id);
@@ -248,6 +244,7 @@ void SceneUpdateContext::UpdateView(int64_t view_id,
248244

249245
view_holder->set_hit_testable(hit_testable);
250246
view_holder->set_focusable(focusable);
247+
view_holder->set_occlusion_hint(view_occlusion_hint);
251248
}
252249

253250
void SceneUpdateContext::DestroyView(

flow/scene_update_context.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,10 @@ class SceneUpdateContext : public flutter::ExternalViewEmbedder {
175175
bool focusable);
176176
void DestroyView(int64_t view_id,
177177
ViewHolder::ViewIdCallback on_view_destroyed);
178-
void UpdateView(int64_t view_id, bool hit_testable, bool focusable);
178+
void UpdateView(int64_t view_id,
179+
const SkRect& view_occlusion_hint,
180+
bool hit_testable,
181+
bool focusable);
179182
void UpdateView(int64_t view_id,
180183
const SkPoint& offset,
181184
const SkSize& size,

flow/view_holder.cc

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,7 @@ ViewHolder::ViewHolder(fuchsia::ui::views::ViewHolderToken view_holder_token,
104104
void ViewHolder::UpdateScene(scenic::Session* session,
105105
scenic::ContainerNode& container_node,
106106
const SkPoint& offset,
107-
const SkSize& size,
108-
SkAlpha opacity,
109-
bool hit_testable) {
107+
SkAlpha opacity) {
110108
if (pending_view_holder_token_.value) {
111109
entity_node_ = std::make_unique<scenic::EntityNode>(session);
112110
opacity_node_ = std::make_unique<scenic::OpacityNodeHACK>(session);
@@ -131,17 +129,8 @@ void ViewHolder::UpdateScene(scenic::Session* session,
131129
container_node.AddChild(*opacity_node_);
132130
opacity_node_->SetOpacity(opacity / 255.0f);
133131
entity_node_->SetTranslation(offset.x(), offset.y(), -0.1f);
134-
entity_node_->SetHitTestBehavior(
135-
hit_testable ? fuchsia::ui::gfx::HitTestBehavior::kDefault
136-
: fuchsia::ui::gfx::HitTestBehavior::kSuppress);
137-
if (has_pending_properties_) {
138-
// TODO(dworsham): This should be derived from size and elevation. We
139-
// should be able to Z-limit the view's box but otherwise it uses all of the
140-
// available airspace.
141-
view_holder_->SetViewProperties(std::move(pending_properties_));
142-
143-
has_pending_properties_ = false;
144-
}
132+
entity_node_->SetHitTestBehavior(hit_test_behavior_);
133+
view_holder_->SetViewProperties(view_properties_);
145134
}
146135

147136
void ViewHolder::SetProperties(double width,
@@ -151,9 +140,32 @@ void ViewHolder::SetProperties(double width,
151140
double insetBottom,
152141
double insetLeft,
153142
bool focusable) {
154-
pending_properties_ = ToViewProperties(width, height, insetTop, insetRight,
155-
insetBottom, insetLeft, focusable);
156-
has_pending_properties_ = true;
143+
view_properties_ = ToViewProperties(width, height, insetTop, insetRight,
144+
insetBottom, insetLeft, focusable);
145+
}
146+
147+
void ViewHolder::set_hit_testable(bool value) {
148+
hit_test_behavior_ = value ? fuchsia::ui::gfx::HitTestBehavior::kDefault
149+
: fuchsia::ui::gfx::HitTestBehavior::kSuppress;
150+
}
151+
152+
void ViewHolder::set_focusable(bool value) {
153+
view_properties_.focus_change = value;
154+
}
155+
156+
void ViewHolder::set_size(const SkSize& size) {
157+
// TODO(dworsham): The Z-bound should be derived from elevation. We should be
158+
// able to Z-limit the view's box but otherwise it uses all of the available
159+
// airspace.
160+
view_properties_.bounding_box.max.x = size.width();
161+
view_properties_.bounding_box.max.y = size.height();
162+
}
163+
164+
void ViewHolder::set_occlusion_hint(const SkRect& occlusion_hint) {
165+
view_properties_.inset_from_min.x = occlusion_hint.fLeft;
166+
view_properties_.inset_from_min.y = occlusion_hint.fTop;
167+
view_properties_.inset_from_max.x = occlusion_hint.fRight;
168+
view_properties_.inset_from_max.y = occlusion_hint.fBottom;
157169
}
158170

159171
} // namespace flutter

flow/view_holder.h

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "flutter/fml/task_runner.h"
2020
#include "third_party/skia/include/core/SkColor.h"
2121
#include "third_party/skia/include/core/SkPoint.h"
22+
#include "third_party/skia/include/core/SkRect.h"
2223
#include "third_party/skia/include/core/SkSize.h"
2324

2425
namespace flutter {
@@ -45,7 +46,7 @@ class ViewHolder {
4546

4647
~ViewHolder() = default;
4748

48-
// Sets the properties/opacity of the child view by issuing a Scenic command.
49+
// Sets the properties of the child view by issuing a Scenic command.
4950
void SetProperties(double width,
5051
double height,
5152
double insetTop,
@@ -59,15 +60,14 @@ class ViewHolder {
5960
void UpdateScene(scenic::Session* session,
6061
scenic::ContainerNode& container_node,
6162
const SkPoint& offset,
62-
const SkSize& size,
63-
SkAlpha opacity,
64-
bool hit_testable);
63+
SkAlpha opacity);
6564

66-
bool hit_testable() { return hit_testable_; }
67-
void set_hit_testable(bool value) { hit_testable_ = value; }
68-
69-
bool focusable() { return focusable_; }
70-
void set_focusable(bool value) { focusable_ = value; }
65+
// Alters various apsects of the ViewHolder's ViewProperties. The updates
66+
// are applied to Scenic on the new |UpdateScene| call.
67+
void set_hit_testable(bool value);
68+
void set_focusable(bool value);
69+
void set_size(const SkSize& size);
70+
void set_occlusion_hint(const SkRect& occlusion_hint);
7171

7272
private:
7373
ViewHolder(fuchsia::ui::views::ViewHolderToken view_holder_token,
@@ -78,14 +78,11 @@ class ViewHolder {
7878
std::unique_ptr<scenic::ViewHolder> view_holder_;
7979

8080
fuchsia::ui::views::ViewHolderToken pending_view_holder_token_;
81-
82-
bool hit_testable_ = true;
83-
bool focusable_ = true;
84-
8581
ViewIdCallback on_view_created_;
8682

87-
fuchsia::ui::gfx::ViewProperties pending_properties_;
88-
bool has_pending_properties_ = false;
83+
fuchsia::ui::gfx::HitTestBehavior hit_test_behavior_ =
84+
fuchsia::ui::gfx::HitTestBehavior::kDefault;
85+
fuchsia::ui::gfx::ViewProperties view_properties_;
8986

9087
FML_DISALLOW_COPY_AND_ASSIGN(ViewHolder);
9188
};

shell/platform/fuchsia/flutter/engine.cc

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,9 @@ Engine::Engine(Delegate& delegate,
180180
&Engine::CreateView, this, std::placeholders::_1, std::placeholders::_2,
181181
std::placeholders::_3, std::placeholders::_4);
182182

183-
OnUpdateView on_update_view_callback =
184-
std::bind(&Engine::UpdateView, this, std::placeholders::_1,
185-
std::placeholders::_2, std::placeholders::_3);
183+
OnUpdateView on_update_view_callback = std::bind(
184+
&Engine::UpdateView, this, std::placeholders::_1, std::placeholders::_2,
185+
std::placeholders::_3, std::placeholders::_4);
186186

187187
OnDestroyView on_destroy_view_callback = std::bind(
188188
&Engine::DestroyView, this, std::placeholders::_1, std::placeholders::_2);
@@ -600,28 +600,31 @@ void Engine::CreateView(int64_t view_id,
600600
FML_CHECK(external_view_embedder_);
601601
external_view_embedder_->CreateView(view_id,
602602
std::move(on_view_bound));
603-
external_view_embedder_->SetViewProperties(view_id, hit_testable,
604-
focusable);
603+
external_view_embedder_->SetViewProperties(
604+
view_id, SkRect::MakeEmpty(), hit_testable, focusable);
605605
}
606606
});
607607
}
608608

609-
void Engine::UpdateView(int64_t view_id, bool hit_testable, bool focusable) {
609+
void Engine::UpdateView(int64_t view_id,
610+
SkRect occlusion_hint,
611+
bool hit_testable,
612+
bool focusable) {
610613
FML_CHECK(shell_);
611614

612615
shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(
613-
[this, view_id, hit_testable, focusable]() {
616+
[this, view_id, occlusion_hint, hit_testable, focusable]() {
614617
#if defined(LEGACY_FUCHSIA_EMBEDDER)
615618
if (use_legacy_renderer_) {
616619
FML_CHECK(legacy_external_view_embedder_);
617-
legacy_external_view_embedder_->UpdateView(view_id, hit_testable,
618-
focusable);
620+
legacy_external_view_embedder_->UpdateView(view_id, occlusion_hint,
621+
hit_testable, focusable);
619622
} else
620623
#endif
621624
{
622625
FML_CHECK(external_view_embedder_);
623-
external_view_embedder_->SetViewProperties(view_id, hit_testable,
624-
focusable);
626+
external_view_embedder_->SetViewProperties(view_id, occlusion_hint,
627+
hit_testable, focusable);
625628
}
626629
});
627630
}

shell/platform/fuchsia/flutter/engine.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,12 @@ class Engine final {
110110
ViewIdCallback on_view_bound,
111111
bool hit_testable,
112112
bool focusable);
113-
void UpdateView(int64_t view_id, bool hit_testable, bool focusable);
113+
void UpdateView(int64_t view_id,
114+
SkRect occlusion_hint,
115+
bool hit_testable,
116+
bool focusable);
114117
void DestroyView(int64_t view_id, ViewIdCallback on_view_unbound);
118+
115119
std::shared_ptr<flutter::ExternalViewEmbedder> GetExternalViewEmbedder();
116120

117121
std::unique_ptr<flutter::Surface> CreateSurface();

shell/platform/fuchsia/flutter/fuchsia_external_view_embedder.cc

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -303,26 +303,32 @@ void FuchsiaExternalViewEmbedder::SubmitFrame(
303303
view_holder.hit_testable = view_holder.pending_hit_testable;
304304
}
305305

306-
// Set size and focusable.
306+
// Set size, occlusion hint, and focusable.
307307
//
308308
// Scenic rejects `SetViewProperties` calls with a zero size.
309309
if (!view_size.isEmpty() &&
310310
(view_size != view_holder.size ||
311+
view_holder.pending_occlusion_hint != view_holder.occlusion_hint ||
311312
view_holder.pending_focusable != view_holder.focusable)) {
313+
view_holder.size = view_size;
314+
view_holder.occlusion_hint = view_holder.pending_occlusion_hint;
315+
view_holder.focusable = view_holder.pending_focusable;
312316
view_holder.view_holder.SetViewProperties({
313317
.bounding_box =
314318
{
315319
.min = {.x = 0.f, .y = 0.f, .z = -1000.f},
316-
.max = {.x = view_size.fWidth,
317-
.y = view_size.fHeight,
320+
.max = {.x = view_holder.size.fWidth,
321+
.y = view_holder.size.fHeight,
318322
.z = 0.f},
319323
},
320-
.inset_from_min = {.x = 0.f, .y = 0.f, .z = 0.f},
321-
.inset_from_max = {.x = 0.f, .y = 0.f, .z = 0.f},
322-
.focus_change = view_holder.pending_focusable,
324+
.inset_from_min = {.x = view_holder.occlusion_hint.fLeft,
325+
.y = view_holder.occlusion_hint.fTop,
326+
.z = 0.f},
327+
.inset_from_max = {.x = view_holder.occlusion_hint.fRight,
328+
.y = view_holder.occlusion_hint.fBottom,
329+
.z = 0.f},
330+
.focus_change = view_holder.focusable,
323331
});
324-
view_holder.size = view_size;
325-
view_holder.focusable = view_holder.pending_focusable;
326332
}
327333

328334
// Attach the ScenicView to the main scene graph.
@@ -509,13 +515,16 @@ void FuchsiaExternalViewEmbedder::DestroyView(int64_t view_id,
509515
on_view_unbound(resource_id);
510516
}
511517

512-
void FuchsiaExternalViewEmbedder::SetViewProperties(int64_t view_id,
513-
bool hit_testable,
514-
bool focusable) {
518+
void FuchsiaExternalViewEmbedder::SetViewProperties(
519+
int64_t view_id,
520+
const SkRect& occlusion_hint,
521+
bool hit_testable,
522+
bool focusable) {
515523
auto found = scenic_views_.find(view_id);
516524
FML_DCHECK(found != scenic_views_.end());
517525
auto& view_holder = found->second;
518526

527+
view_holder.pending_occlusion_hint = occlusion_hint;
519528
view_holder.pending_hit_testable = hit_testable;
520529
view_holder.pending_focusable = focusable;
521530
}

shell/platform/fuchsia/flutter/fuchsia_external_view_embedder.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "third_party/skia/include/core/SkCanvas.h"
2424
#include "third_party/skia/include/core/SkPictureRecorder.h"
2525
#include "third_party/skia/include/core/SkPoint.h"
26+
#include "third_party/skia/include/core/SkRect.h"
2627
#include "third_party/skia/include/core/SkSize.h"
2728
#include "third_party/skia/include/gpu/GrDirectContext.h"
2829

@@ -94,7 +95,10 @@ class FuchsiaExternalViewEmbedder final : public flutter::ExternalViewEmbedder {
9495
void EnableWireframe(bool enable);
9596
void CreateView(int64_t view_id, ViewIdCallback on_view_bound);
9697
void DestroyView(int64_t view_id, ViewIdCallback on_view_unbound);
97-
void SetViewProperties(int64_t view_id, bool hit_testable, bool focusable);
98+
void SetViewProperties(int64_t view_id,
99+
const SkRect& occlusion_hint,
100+
bool hit_testable,
101+
bool focusable);
98102

99103
private:
100104
// Reset state for a new frame.
@@ -124,13 +128,15 @@ class FuchsiaExternalViewEmbedder final : public flutter::ExternalViewEmbedder {
124128
SkPoint offset = SkPoint::Make(0.f, 0.f);
125129
SkSize scale = SkSize::MakeEmpty();
126130
SkSize size = SkSize::MakeEmpty();
131+
SkRect occlusion_hint = SkRect::MakeEmpty();
127132
float elevation = 0.f;
128133
float opacity = 1.f;
129-
bool hit_testable = false;
130-
bool focusable = false;
134+
bool hit_testable = true;
135+
bool focusable = true;
131136

132-
bool pending_hit_testable = false;
133-
bool pending_focusable = false;
137+
SkRect pending_occlusion_hint = SkRect::MakeEmpty();
138+
bool pending_hit_testable = true;
139+
bool pending_focusable = true;
134140
};
135141

136142
struct ScenicLayer {

shell/platform/fuchsia/flutter/platform_view.cc

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,9 +1005,47 @@ void PlatformView::HandleFlutterPlatformViewsChannelPlatformMessage(
10051005
return;
10061006
}
10071007

1008-
on_update_view_callback_(view_id->value.GetUint64(),
1009-
hit_testable->value.GetBool(),
1010-
focusable->value.GetBool());
1008+
SkRect view_occlusion_hint_raw = SkRect::MakeEmpty();
1009+
auto view_occlusion_hint = args.FindMember("");
1010+
if (view_occlusion_hint != args.MemberEnd()) {
1011+
if (view_occlusion_hint->value.IsArray()) {
1012+
const auto& view_occlusion_hint_array =
1013+
view_occlusion_hint->value.GetArray();
1014+
if (view_occlusion_hint_array.Size() == 4) {
1015+
bool parse_error = false;
1016+
for (int i = 0; i < 4; i++) {
1017+
auto& array_val = view_occlusion_hint_array[i];
1018+
if (!array_val.IsDouble()) {
1019+
FML_LOG(ERROR) << "Argument 'viewOcclusionHintLTRB' element " << i
1020+
<< " is not a double";
1021+
parse_error = true;
1022+
break;
1023+
}
1024+
}
1025+
1026+
if (!parse_error) {
1027+
view_occlusion_hint_raw =
1028+
SkRect::MakeLTRB(view_occlusion_hint_array[0].GetDouble(),
1029+
view_occlusion_hint_array[1].GetDouble(),
1030+
view_occlusion_hint_array[2].GetDouble(),
1031+
view_occlusion_hint_array[3].GetDouble());
1032+
}
1033+
} else {
1034+
FML_LOG(ERROR)
1035+
<< "Argument 'viewOcclusionHintLTRB' expected size 4; got "
1036+
<< view_occlusion_hint_array.Size();
1037+
}
1038+
} else {
1039+
FML_LOG(ERROR)
1040+
<< "Argument 'viewOcclusionHintLTRB' is not a double array";
1041+
}
1042+
} else {
1043+
FML_LOG(WARNING) << "Argument 'viewOcclusionHintLTRB' is missing";
1044+
}
1045+
1046+
on_update_view_callback_(
1047+
view_id->value.GetUint64(), view_occlusion_hint_raw,
1048+
hit_testable->value.GetBool(), focusable->value.GetBool());
10111049
} else if (method->value == "View.dispose") {
10121050
auto args_it = root.FindMember("args");
10131051
if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {

0 commit comments

Comments
 (0)