未验证 提交 1bf01a1f 编写于 作者: D David Worsham 提交者: GitHub

fuchsia: Reliably forward View insets (#25381)

上级 258f63a9
......@@ -206,17 +206,12 @@ void SceneUpdateContext::UpdateView(int64_t view_id,
return;
}
if (size.width() > 0.f && size.height() > 0.f) {
view_holder->SetProperties(size.width(), size.height(), 0, 0, 0, 0,
view_holder->focusable());
if (override_hit_testable.has_value()) {
view_holder->set_hit_testable(*override_hit_testable);
}
bool hit_testable = override_hit_testable.has_value()
? *override_hit_testable
: view_holder->hit_testable();
view_holder->set_size(size);
view_holder->UpdateScene(session_.get(), top_entity_->embedder_node(), offset,
size, SkScalarRoundToInt(alphaf() * 255),
hit_testable);
SkScalarRoundToInt(alphaf() * 255));
// Assume embedded views are 10 "layers" wide.
next_elevation_ += 10 * kScenicZElevationBetweenLayers;
......@@ -238,6 +233,7 @@ void SceneUpdateContext::CreateView(int64_t view_id,
}
void SceneUpdateContext::UpdateView(int64_t view_id,
const SkRect& view_occlusion_hint,
bool hit_testable,
bool focusable) {
auto* view_holder = ViewHolder::FromId(view_id);
......@@ -248,6 +244,7 @@ void SceneUpdateContext::UpdateView(int64_t view_id,
view_holder->set_hit_testable(hit_testable);
view_holder->set_focusable(focusable);
view_holder->set_occlusion_hint(view_occlusion_hint);
}
void SceneUpdateContext::DestroyView(
......
......@@ -175,7 +175,10 @@ class SceneUpdateContext : public flutter::ExternalViewEmbedder {
bool focusable);
void DestroyView(int64_t view_id,
ViewHolder::ViewIdCallback on_view_destroyed);
void UpdateView(int64_t view_id, bool hit_testable, bool focusable);
void UpdateView(int64_t view_id,
const SkRect& view_occlusion_hint,
bool hit_testable,
bool focusable);
void UpdateView(int64_t view_id,
const SkPoint& offset,
const SkSize& size,
......
......@@ -104,9 +104,7 @@ ViewHolder::ViewHolder(fuchsia::ui::views::ViewHolderToken view_holder_token,
void ViewHolder::UpdateScene(scenic::Session* session,
scenic::ContainerNode& container_node,
const SkPoint& offset,
const SkSize& size,
SkAlpha opacity,
bool hit_testable) {
SkAlpha opacity) {
if (pending_view_holder_token_.value) {
entity_node_ = std::make_unique<scenic::EntityNode>(session);
opacity_node_ = std::make_unique<scenic::OpacityNodeHACK>(session);
......@@ -131,17 +129,8 @@ void ViewHolder::UpdateScene(scenic::Session* session,
container_node.AddChild(*opacity_node_);
opacity_node_->SetOpacity(opacity / 255.0f);
entity_node_->SetTranslation(offset.x(), offset.y(), -0.1f);
entity_node_->SetHitTestBehavior(
hit_testable ? fuchsia::ui::gfx::HitTestBehavior::kDefault
: fuchsia::ui::gfx::HitTestBehavior::kSuppress);
if (has_pending_properties_) {
// TODO(dworsham): This should be derived from size and elevation. We
// should be able to Z-limit the view's box but otherwise it uses all of the
// available airspace.
view_holder_->SetViewProperties(std::move(pending_properties_));
has_pending_properties_ = false;
}
entity_node_->SetHitTestBehavior(hit_test_behavior_);
view_holder_->SetViewProperties(view_properties_);
}
void ViewHolder::SetProperties(double width,
......@@ -151,9 +140,32 @@ void ViewHolder::SetProperties(double width,
double insetBottom,
double insetLeft,
bool focusable) {
pending_properties_ = ToViewProperties(width, height, insetTop, insetRight,
insetBottom, insetLeft, focusable);
has_pending_properties_ = true;
view_properties_ = ToViewProperties(width, height, insetTop, insetRight,
insetBottom, insetLeft, focusable);
}
void ViewHolder::set_hit_testable(bool value) {
hit_test_behavior_ = value ? fuchsia::ui::gfx::HitTestBehavior::kDefault
: fuchsia::ui::gfx::HitTestBehavior::kSuppress;
}
void ViewHolder::set_focusable(bool value) {
view_properties_.focus_change = value;
}
void ViewHolder::set_size(const SkSize& size) {
// TODO(dworsham): The Z-bound should be derived from elevation. We should be
// able to Z-limit the view's box but otherwise it uses all of the available
// airspace.
view_properties_.bounding_box.max.x = size.width();
view_properties_.bounding_box.max.y = size.height();
}
void ViewHolder::set_occlusion_hint(const SkRect& occlusion_hint) {
view_properties_.inset_from_min.x = occlusion_hint.fLeft;
view_properties_.inset_from_min.y = occlusion_hint.fTop;
view_properties_.inset_from_max.x = occlusion_hint.fRight;
view_properties_.inset_from_max.y = occlusion_hint.fBottom;
}
} // namespace flutter
......@@ -19,6 +19,7 @@
#include "flutter/fml/task_runner.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkPoint.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkSize.h"
namespace flutter {
......@@ -45,7 +46,7 @@ class ViewHolder {
~ViewHolder() = default;
// Sets the properties/opacity of the child view by issuing a Scenic command.
// Sets the properties of the child view by issuing a Scenic command.
void SetProperties(double width,
double height,
double insetTop,
......@@ -59,15 +60,14 @@ class ViewHolder {
void UpdateScene(scenic::Session* session,
scenic::ContainerNode& container_node,
const SkPoint& offset,
const SkSize& size,
SkAlpha opacity,
bool hit_testable);
SkAlpha opacity);
bool hit_testable() { return hit_testable_; }
void set_hit_testable(bool value) { hit_testable_ = value; }
bool focusable() { return focusable_; }
void set_focusable(bool value) { focusable_ = value; }
// Alters various apsects of the ViewHolder's ViewProperties. The updates
// are applied to Scenic on the new |UpdateScene| call.
void set_hit_testable(bool value);
void set_focusable(bool value);
void set_size(const SkSize& size);
void set_occlusion_hint(const SkRect& occlusion_hint);
private:
ViewHolder(fuchsia::ui::views::ViewHolderToken view_holder_token,
......@@ -78,14 +78,11 @@ class ViewHolder {
std::unique_ptr<scenic::ViewHolder> view_holder_;
fuchsia::ui::views::ViewHolderToken pending_view_holder_token_;
bool hit_testable_ = true;
bool focusable_ = true;
ViewIdCallback on_view_created_;
fuchsia::ui::gfx::ViewProperties pending_properties_;
bool has_pending_properties_ = false;
fuchsia::ui::gfx::HitTestBehavior hit_test_behavior_ =
fuchsia::ui::gfx::HitTestBehavior::kDefault;
fuchsia::ui::gfx::ViewProperties view_properties_;
FML_DISALLOW_COPY_AND_ASSIGN(ViewHolder);
};
......
......@@ -180,9 +180,9 @@ Engine::Engine(Delegate& delegate,
&Engine::CreateView, this, std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3, std::placeholders::_4);
OnUpdateView on_update_view_callback =
std::bind(&Engine::UpdateView, this, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_3);
OnUpdateView on_update_view_callback = std::bind(
&Engine::UpdateView, this, std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3, std::placeholders::_4);
OnDestroyView on_destroy_view_callback = std::bind(
&Engine::DestroyView, this, std::placeholders::_1, std::placeholders::_2);
......@@ -600,28 +600,31 @@ void Engine::CreateView(int64_t view_id,
FML_CHECK(external_view_embedder_);
external_view_embedder_->CreateView(view_id,
std::move(on_view_bound));
external_view_embedder_->SetViewProperties(view_id, hit_testable,
focusable);
external_view_embedder_->SetViewProperties(
view_id, SkRect::MakeEmpty(), hit_testable, focusable);
}
});
}
void Engine::UpdateView(int64_t view_id, bool hit_testable, bool focusable) {
void Engine::UpdateView(int64_t view_id,
SkRect occlusion_hint,
bool hit_testable,
bool focusable) {
FML_CHECK(shell_);
shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(
[this, view_id, hit_testable, focusable]() {
[this, view_id, occlusion_hint, hit_testable, focusable]() {
#if defined(LEGACY_FUCHSIA_EMBEDDER)
if (use_legacy_renderer_) {
FML_CHECK(legacy_external_view_embedder_);
legacy_external_view_embedder_->UpdateView(view_id, hit_testable,
focusable);
legacy_external_view_embedder_->UpdateView(view_id, occlusion_hint,
hit_testable, focusable);
} else
#endif
{
FML_CHECK(external_view_embedder_);
external_view_embedder_->SetViewProperties(view_id, hit_testable,
focusable);
external_view_embedder_->SetViewProperties(view_id, occlusion_hint,
hit_testable, focusable);
}
});
}
......
......@@ -110,8 +110,12 @@ class Engine final {
ViewIdCallback on_view_bound,
bool hit_testable,
bool focusable);
void UpdateView(int64_t view_id, bool hit_testable, bool focusable);
void UpdateView(int64_t view_id,
SkRect occlusion_hint,
bool hit_testable,
bool focusable);
void DestroyView(int64_t view_id, ViewIdCallback on_view_unbound);
std::shared_ptr<flutter::ExternalViewEmbedder> GetExternalViewEmbedder();
std::unique_ptr<flutter::Surface> CreateSurface();
......
......@@ -303,26 +303,32 @@ void FuchsiaExternalViewEmbedder::SubmitFrame(
view_holder.hit_testable = view_holder.pending_hit_testable;
}
// Set size and focusable.
// Set size, occlusion hint, and focusable.
//
// Scenic rejects `SetViewProperties` calls with a zero size.
if (!view_size.isEmpty() &&
(view_size != view_holder.size ||
view_holder.pending_occlusion_hint != view_holder.occlusion_hint ||
view_holder.pending_focusable != view_holder.focusable)) {
view_holder.size = view_size;
view_holder.occlusion_hint = view_holder.pending_occlusion_hint;
view_holder.focusable = view_holder.pending_focusable;
view_holder.view_holder.SetViewProperties({
.bounding_box =
{
.min = {.x = 0.f, .y = 0.f, .z = -1000.f},
.max = {.x = view_size.fWidth,
.y = view_size.fHeight,
.max = {.x = view_holder.size.fWidth,
.y = view_holder.size.fHeight,
.z = 0.f},
},
.inset_from_min = {.x = 0.f, .y = 0.f, .z = 0.f},
.inset_from_max = {.x = 0.f, .y = 0.f, .z = 0.f},
.focus_change = view_holder.pending_focusable,
.inset_from_min = {.x = view_holder.occlusion_hint.fLeft,
.y = view_holder.occlusion_hint.fTop,
.z = 0.f},
.inset_from_max = {.x = view_holder.occlusion_hint.fRight,
.y = view_holder.occlusion_hint.fBottom,
.z = 0.f},
.focus_change = view_holder.focusable,
});
view_holder.size = view_size;
view_holder.focusable = view_holder.pending_focusable;
}
// Attach the ScenicView to the main scene graph.
......@@ -509,13 +515,16 @@ void FuchsiaExternalViewEmbedder::DestroyView(int64_t view_id,
on_view_unbound(resource_id);
}
void FuchsiaExternalViewEmbedder::SetViewProperties(int64_t view_id,
bool hit_testable,
bool focusable) {
void FuchsiaExternalViewEmbedder::SetViewProperties(
int64_t view_id,
const SkRect& occlusion_hint,
bool hit_testable,
bool focusable) {
auto found = scenic_views_.find(view_id);
FML_DCHECK(found != scenic_views_.end());
auto& view_holder = found->second;
view_holder.pending_occlusion_hint = occlusion_hint;
view_holder.pending_hit_testable = hit_testable;
view_holder.pending_focusable = focusable;
}
......
......@@ -23,6 +23,7 @@
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkPoint.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkSize.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
......@@ -94,7 +95,10 @@ class FuchsiaExternalViewEmbedder final : public flutter::ExternalViewEmbedder {
void EnableWireframe(bool enable);
void CreateView(int64_t view_id, ViewIdCallback on_view_bound);
void DestroyView(int64_t view_id, ViewIdCallback on_view_unbound);
void SetViewProperties(int64_t view_id, bool hit_testable, bool focusable);
void SetViewProperties(int64_t view_id,
const SkRect& occlusion_hint,
bool hit_testable,
bool focusable);
private:
// Reset state for a new frame.
......@@ -124,13 +128,15 @@ class FuchsiaExternalViewEmbedder final : public flutter::ExternalViewEmbedder {
SkPoint offset = SkPoint::Make(0.f, 0.f);
SkSize scale = SkSize::MakeEmpty();
SkSize size = SkSize::MakeEmpty();
SkRect occlusion_hint = SkRect::MakeEmpty();
float elevation = 0.f;
float opacity = 1.f;
bool hit_testable = false;
bool focusable = false;
bool hit_testable = true;
bool focusable = true;
bool pending_hit_testable = false;
bool pending_focusable = false;
SkRect pending_occlusion_hint = SkRect::MakeEmpty();
bool pending_hit_testable = true;
bool pending_focusable = true;
};
struct ScenicLayer {
......
......@@ -1005,9 +1005,47 @@ void PlatformView::HandleFlutterPlatformViewsChannelPlatformMessage(
return;
}
on_update_view_callback_(view_id->value.GetUint64(),
hit_testable->value.GetBool(),
focusable->value.GetBool());
SkRect view_occlusion_hint_raw = SkRect::MakeEmpty();
auto view_occlusion_hint = args.FindMember("");
if (view_occlusion_hint != args.MemberEnd()) {
if (view_occlusion_hint->value.IsArray()) {
const auto& view_occlusion_hint_array =
view_occlusion_hint->value.GetArray();
if (view_occlusion_hint_array.Size() == 4) {
bool parse_error = false;
for (int i = 0; i < 4; i++) {
auto& array_val = view_occlusion_hint_array[i];
if (!array_val.IsDouble()) {
FML_LOG(ERROR) << "Argument 'viewOcclusionHintLTRB' element " << i
<< " is not a double";
parse_error = true;
break;
}
}
if (!parse_error) {
view_occlusion_hint_raw =
SkRect::MakeLTRB(view_occlusion_hint_array[0].GetDouble(),
view_occlusion_hint_array[1].GetDouble(),
view_occlusion_hint_array[2].GetDouble(),
view_occlusion_hint_array[3].GetDouble());
}
} else {
FML_LOG(ERROR)
<< "Argument 'viewOcclusionHintLTRB' expected size 4; got "
<< view_occlusion_hint_array.Size();
}
} else {
FML_LOG(ERROR)
<< "Argument 'viewOcclusionHintLTRB' is not a double array";
}
} else {
FML_LOG(WARNING) << "Argument 'viewOcclusionHintLTRB' is missing";
}
on_update_view_callback_(
view_id->value.GetUint64(), view_occlusion_hint_raw,
hit_testable->value.GetBool(), focusable->value.GetBool());
} else if (method->value == "View.dispose") {
auto args_it = root.FindMember("args");
if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
......
......@@ -30,7 +30,7 @@ namespace flutter_runner {
using OnEnableWireframe = fit::function<void(bool)>;
using OnCreateView = fit::function<void(int64_t, ViewIdCallback, bool, bool)>;
using OnUpdateView = fit::function<void(int64_t, bool, bool)>;
using OnUpdateView = fit::function<void(int64_t, SkRect, bool, bool)>;
using OnDestroyView = fit::function<void(int64_t, ViewIdCallback)>;
using OnCreateSurface = fit::function<std::unique_ptr<flutter::Surface>()>;
......
......@@ -597,7 +597,7 @@ TEST_F(PlatformViewTests, CreateViewTest) {
// Test wireframe callback function. If the message sent to the platform
// view was properly handled and parsed, this function should be called,
// setting |wireframe_enabled| to true.
int64_t create_view_called = false;
bool create_view_called = false;
auto CreateViewCallback = [&create_view_called](
int64_t view_id,
flutter_runner::ViewIdCallback on_view_bound,
......@@ -651,9 +651,10 @@ TEST_F(PlatformViewTests, UpdateViewTest) {
// Test wireframe callback function. If the message sent to the platform
// view was properly handled and parsed, this function should be called,
// setting |wireframe_enabled| to true.
int64_t update_view_called = false;
bool update_view_called = false;
auto UpdateViewCallback = [&update_view_called](
int64_t view_id, bool hit_testable,
int64_t view_id, SkRect occlusion_hint,
bool hit_testable,
bool focusable) { update_view_called = true; };
flutter_runner::PlatformView platform_view =
......@@ -707,7 +708,7 @@ TEST_F(PlatformViewTests, DestroyViewTest) {
// Test wireframe callback function. If the message sent to the platform
// view was properly handled and parsed, this function should be called,
// setting |wireframe_enabled| to true.
int64_t destroy_view_called = false;
bool destroy_view_called = false;
auto DestroyViewCallback =
[&destroy_view_called](int64_t view_id,
flutter_runner::ViewIdCallback on_view_unbound) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册