提交 2dc88cc6 编写于 作者: A Adam Barth 提交者: GitHub

Switch backend to consume new semantics API (#3103)

上级 4f370b3e
......@@ -26,6 +26,10 @@ Threads::Threads(ftl::RefPtr<ftl::TaskRunner> platform,
Threads::~Threads() {}
const ftl::RefPtr<ftl::TaskRunner>& Threads::Platform() {
return Get().platform_;
}
const ftl::RefPtr<ftl::TaskRunner>& Threads::Gpu() {
return Get().gpu_;
}
......
......@@ -12,4 +12,12 @@ SemanticsNode::SemanticsNode() = default;
SemanticsNode::~SemanticsNode() = default;
bool SemanticsNode::HasAction(SemanticsAction action) {
return (actions & static_cast<int32_t>(action)) != 0;
}
bool SemanticsNode::HasFlag(SemanticsFlags flag) {
return (flags & static_cast<int32_t>(flag)) != 0;
}
} // namespace blink
......@@ -37,6 +37,9 @@ struct SemanticsNode {
SemanticsNode();
~SemanticsNode();
bool HasAction(SemanticsAction action);
bool HasFlag(SemanticsFlags flag);
int32_t id = 0;
int32_t flags = 0;
int32_t actions = 0;
......
......@@ -12,8 +12,8 @@
namespace shell {
Animator::Animator(Rasterizer* rasterizer, Engine* engine)
: rasterizer_(rasterizer->GetWeakRasterizerPtr()),
Animator::Animator(ftl::WeakPtr<Rasterizer> rasterizer, Engine* engine)
: rasterizer_(rasterizer),
engine_(engine),
layer_tree_pipeline_(ftl::MakeRefCounted<LayerTreePipeline>(3)),
pending_frame_semaphore_(1),
......@@ -77,16 +77,12 @@ void Animator::Render(std::unique_ptr<flow::LayerTree> layer_tree) {
// Commit the pending continuation.
producer_continuation_.Complete(std::move(layer_tree));
// Notify the rasterizer that the pipeline has items it may consume.
auto weak_rasterizer(rasterizer_);
auto pipeline = layer_tree_pipeline_;
blink::Threads::Gpu()->PostTask([weak_rasterizer, pipeline]() {
if (!weak_rasterizer) {
return;
}
weak_rasterizer->Draw(pipeline);
});
blink::Threads::Gpu()->PostTask(
[ rasterizer = rasterizer_, pipeline = layer_tree_pipeline_ ]() {
if (!rasterizer.get())
return;
rasterizer->Draw(pipeline);
});
}
void Animator::RequestFrame() {
......@@ -107,16 +103,11 @@ void Animator::RequestFrame() {
// started an expensive operation right after posting this message however.
// To support that, we need edge triggered wakes on VSync.
auto weak = weak_factory_.GetWeakPtr();
blink::Threads::UI()->PostTask([weak]() {
if (!weak) {
blink::Threads::UI()->PostTask([self = weak_factory_.GetWeakPtr()]() {
if (!self.get())
return;
}
TRACE_EVENT_INSTANT0("flutter", "RequestFrame", TRACE_EVENT_SCOPE_PROCESS);
weak->AwaitVSync(base::Bind(&Animator::BeginFrame, weak));
self->AwaitVSync(base::Bind(&Animator::BeginFrame, self));
});
}
......
......@@ -19,7 +19,7 @@ namespace shell {
class Animator {
public:
explicit Animator(Rasterizer* rasterizer, Engine* engine);
explicit Animator(ftl::WeakPtr<Rasterizer> rasterizer, Engine* engine);
~Animator();
......
......@@ -20,8 +20,10 @@
#include "flutter/runtime/dart_init.h"
#include "flutter/runtime/runtime_init.h"
#include "flutter/shell/common/animator.h"
#include "flutter/shell/common/platform_view.h"
#include "flutter/sky/engine/public/web/Sky.h"
#include "lib/ftl/files/path.h"
#include "lib/ftl/functional/make_copyable.h"
#include "mojo/public/cpp/application/connect.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
......@@ -47,8 +49,10 @@ std::string FindPackagesPath(const std::string& main_dart) {
} // namespace
Engine::Engine(Rasterizer* rasterizer)
: animator_(new Animator(rasterizer, this)),
Engine::Engine(PlatformView* platform_view)
: platform_view_(platform_view->GetWeakPtr()),
animator_(new Animator(platform_view->rasterizer().GetWeakRasterizerPtr(),
this)),
binding_(this),
activity_running_(false),
have_surface_(false),
......@@ -160,6 +164,18 @@ void Engine::DispatchPointerDataPacket(const PointerDataPacket& packet) {
runtime_->DispatchPointerDataPacket(packet);
}
void Engine::DispatchSemanticsAction(int id, blink::SemanticsAction action) {
TRACE_EVENT0("flutter", "Engine::DispatchPointerDataPacket");
if (runtime_)
runtime_->DispatchSemanticsAction(id, action);
}
void Engine::SetSemanticsEnabled(bool enabled) {
TRACE_EVENT0("flutter", "Engine::DispatchPointerDataPacket");
if (runtime_)
runtime_->SetSemanticsEnabled(enabled);
}
void Engine::RunFromSnapshotStream(
const std::string& script_uri,
mojo::ScopedDataPipeConsumerHandle snapshot) {
......@@ -334,6 +350,12 @@ void Engine::Render(std::unique_ptr<flow::LayerTree> layer_tree) {
animator_->Render(std::move(layer_tree));
}
void Engine::UpdateSemantics(std::vector<blink::SemanticsNode> update) {}
void Engine::UpdateSemantics(std::vector<blink::SemanticsNode> update) {
blink::Threads::Platform()->PostTask(ftl::MakeCopyable(
[ platform_view = platform_view_, update = std::move(update) ]() mutable {
if (platform_view)
platform_view->UpdateSemantics(std::move(update));
}));
}
} // namespace shell
......@@ -24,12 +24,13 @@
#include "third_party/skia/include/core/SkPicture.h"
namespace shell {
class PlatformView;
class Animator;
using PointerDataPacket = blink::PointerDataPacket;
class Engine : public sky::SkyEngine, public blink::RuntimeDelegate {
public:
explicit Engine(Rasterizer* rasterizer);
explicit Engine(PlatformView* platform_view);
~Engine() override;
......@@ -51,6 +52,8 @@ class Engine : public sky::SkyEngine, public blink::RuntimeDelegate {
void OnOutputSurfaceCreated(const ftl::Closure& gpu_continuation);
void OnOutputSurfaceDestroyed(const ftl::Closure& gpu_continuation);
void DispatchPointerDataPacket(const PointerDataPacket& packet);
void DispatchSemanticsAction(int id, blink::SemanticsAction action);
void SetSemanticsEnabled(bool enabled);
private:
// SkyEngine implementation:
......@@ -91,6 +94,7 @@ class Engine : public sky::SkyEngine, public blink::RuntimeDelegate {
void ConfigureAssetBundle(const std::string& path);
void ConfigureRuntime(const std::string& script_uri);
ftl::WeakPtr<PlatformView> platform_view_;
std::unique_ptr<Animator> animator_;
sky::ServicesDataPtr services_;
......
......@@ -15,8 +15,10 @@
namespace shell {
PlatformView::PlatformView(std::unique_ptr<Rasterizer> rasterizer)
: rasterizer_(std::move(rasterizer)), size_(SkISize::Make(0, 0)) {
engine_.reset(new Engine(rasterizer_.get()));
: rasterizer_(std::move(rasterizer)),
size_(SkISize::Make(0, 0)),
weak_factory_(this) {
engine_.reset(new Engine(this));
}
PlatformView::~PlatformView() {
......@@ -30,10 +32,28 @@ PlatformView::~PlatformView() {
blink::Threads::UI()->PostTask([engine]() { delete engine; });
}
void PlatformView::DispatchSemanticsAction(int32_t id,
blink::SemanticsAction action) {
blink::Threads::UI()->PostTask(
[ engine = engine_->GetWeakPtr(), id, action ] {
if (engine.get()) {
engine->DispatchSemanticsAction(
id, static_cast<blink::SemanticsAction>(action));
}
});
}
void PlatformView::SetSemanticsEnabled(bool enabled) {
blink::Threads::UI()->PostTask([ engine = engine_->GetWeakPtr(), enabled ] {
if (engine.get())
engine->SetSemanticsEnabled(enabled);
});
}
void PlatformView::ConnectToEngine(
mojo::InterfaceRequest<sky::SkyEngine> request) {
blink::Threads::UI()->PostTask(ftl::MakeCopyable([
view = GetWeakViewPtr(), engine = engine().GetWeakPtr(),
view = GetWeakPtr(), engine = engine().GetWeakPtr(),
request = std::move(request)
]() mutable {
if (engine.get())
......@@ -90,6 +110,10 @@ void PlatformView::NotifyDestroyed() {
latch.Wait();
}
ftl::WeakPtr<PlatformView> PlatformView::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
SkISize PlatformView::GetSize() {
return size_;
}
......@@ -98,6 +122,8 @@ void PlatformView::Resize(const SkISize& size) {
size_ = size;
}
void PlatformView::UpdateSemantics(std::vector<blink::SemanticsNode> update) {}
void PlatformView::SetupResourceContextOnIOThread() {
ftl::AutoResetWaitableEvent latch;
......
......@@ -7,6 +7,7 @@
#include <memory>
#include "flutter/lib/ui/semantics/semantics_node.h"
#include "flutter/shell/common/engine.h"
#include "flutter/shell/common/shell.h"
#include "flutter/shell/common/surface.h"
......@@ -35,6 +36,9 @@ class PlatformView {
virtual ~PlatformView();
void DispatchSemanticsAction(int32_t id, blink::SemanticsAction action);
void SetSemanticsEnabled(bool enabled);
void ConnectToEngine(mojo::InterfaceRequest<sky::SkyEngine> request);
void NotifyCreated(std::unique_ptr<Surface> surface);
......@@ -44,7 +48,7 @@ class PlatformView {
void NotifyDestroyed();
virtual ftl::WeakPtr<PlatformView> GetWeakViewPtr() = 0;
ftl::WeakPtr<PlatformView> GetWeakPtr();
virtual bool ResourceContextMakeCurrent() = 0;
......@@ -52,6 +56,8 @@ class PlatformView {
virtual void Resize(const SkISize& size);
virtual void UpdateSemantics(std::vector<blink::SemanticsNode> update);
Rasterizer& rasterizer() { return *rasterizer_; }
Engine& engine() { return *engine_; }
......@@ -60,17 +66,19 @@ class PlatformView {
const std::string& assets_directory) = 0;
protected:
SurfaceConfig surface_config_;
std::unique_ptr<Rasterizer> rasterizer_;
std::unique_ptr<Engine> engine_;
SkISize size_;
explicit PlatformView(std::unique_ptr<Rasterizer> rasterizer);
void SetupResourceContextOnIOThreadPerform(
ftl::AutoResetWaitableEvent* event);
SurfaceConfig surface_config_;
std::unique_ptr<Rasterizer> rasterizer_;
std::unique_ptr<Engine> engine_;
SkISize size_;
private:
ftl::WeakPtrFactory<PlatformView> weak_factory_;
FTL_DISALLOW_COPY_AND_ASSIGN(PlatformView);
};
......
......@@ -46,7 +46,6 @@ import org.chromium.mojom.editing.Keyboard;
import org.chromium.mojom.flutter.platform.ApplicationMessages;
import org.chromium.mojom.mojo.ServiceProvider;
import org.chromium.mojom.raw_keyboard.RawKeyboardService;
import org.chromium.mojom.semantics.SemanticsServer;
import org.chromium.mojom.sky.AppLifecycleState;
import org.chromium.mojom.sky.ServicesData;
import org.chromium.mojom.sky.SkyEngine;
......@@ -578,7 +577,8 @@ public class FlutterView extends SurfaceView
private static native Bitmap nativeGetBitmap(long nativePlatformViewAndroid);
private static native void nativeDispatchPointerDataPacket(long nativePlatformViewAndroid, ByteBuffer buffer, int position);
private static native void nativeDispatchSemanticsAction(long nativePlatformViewAndroid, int id, int action);
private static native void nativeSetSemanticsEnabled(long nativePlatformViewAndroid, boolean enabled);
private static native void nativeInvokePlatformMessageResponseCallback(long nativePlatformViewAndroid, int responseId, String buffer);
@CalledByNative
......@@ -603,11 +603,21 @@ public class FlutterView extends SurfaceView
nativeInvokePlatformMessageResponseCallback(mNativePlatformView, responseId, null);
}
@CalledByNative
private void updateSemantics(ByteBuffer buffer, String[] strings) {
if (mAccessibilityNodeProvider != null)
mAccessibilityNodeProvider.updateSemantics(buffer, strings);
}
// ACCESSIBILITY
private boolean mAccessibilityEnabled = false;
private boolean mTouchExplorationEnabled = false;
protected void dispatchSemanticsAction(int id, int action) {
nativeDispatchSemanticsAction(mNativePlatformView, id, action);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
......@@ -669,21 +679,14 @@ public class FlutterView extends SurfaceView
void ensureAccessibilityEnabled() {
if (mAccessibilityNodeProvider == null) {
mAccessibilityNodeProvider = new AccessibilityBridge(this, createSemanticsServer());
mAccessibilityNodeProvider = new AccessibilityBridge(this);
nativeSetSemanticsEnabled(mNativePlatformView, true);
}
}
private SemanticsServer.Proxy createSemanticsServer() {
Core core = CoreImpl.getInstance();
Pair<SemanticsServer.Proxy, InterfaceRequest<SemanticsServer>> server =
SemanticsServer.MANAGER.getInterfaceRequest(core);
mDartServiceProvider.connectToService(SemanticsServer.MANAGER.getName(), server.second.passHandle());
return server.first;
}
void resetAccessibilityTree() {
if (mAccessibilityNodeProvider != null) {
mAccessibilityNodeProvider.reset(createSemanticsServer());
mAccessibilityNodeProvider.reset();
}
}
......
......@@ -9,9 +9,12 @@
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/types.h>
#include <memory>
#include <utility>
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/bind.h"
#include "base/location.h"
......@@ -29,7 +32,7 @@
namespace shell {
PlatformViewAndroid::PlatformViewAndroid()
: PlatformView(std::make_unique<GPURasterizer>()), weak_factory_(this) {}
: PlatformView(std::make_unique<GPURasterizer>()) {}
PlatformViewAndroid::~PlatformViewAndroid() = default;
......@@ -159,6 +162,20 @@ void PlatformViewAndroid::HandlePlatformMessage(
}
}
void PlatformViewAndroid::DispatchSemanticsAction(JNIEnv* env,
jobject obj,
jint id,
jint action) {
PlatformView::DispatchSemanticsAction(
id, static_cast<blink::SemanticsAction>(action));
}
void PlatformViewAndroid::SetSemanticsEnabled(JNIEnv* env,
jobject obj,
jboolean enabled) {
PlatformView::SetSemanticsEnabled(enabled);
}
void PlatformViewAndroid::ReleaseSurface() {
if (surface_gl_) {
NotifyDestroyed();
......@@ -166,10 +183,6 @@ void PlatformViewAndroid::ReleaseSurface() {
}
}
ftl::WeakPtr<shell::PlatformView> PlatformViewAndroid::GetWeakViewPtr() {
return weak_factory_.GetWeakPtr();
}
bool PlatformViewAndroid::ResourceContextMakeCurrent() {
return surface_gl_ ? surface_gl_->GLOffscreenContextMakeCurrent() : false;
}
......@@ -184,6 +197,56 @@ void PlatformViewAndroid::Resize(const SkISize& size) {
}
}
void PlatformViewAndroid::UpdateSemantics(
std::vector<blink::SemanticsNode> update) {
constexpr size_t kBytesPerNode = 25 * sizeof(int32_t);
constexpr size_t kBytesPerChild = sizeof(int32_t);
JNIEnv* env = base::android::AttachCurrentThread();
{
base::android::ScopedJavaLocalRef<jobject> view = flutter_view_.get(env);
if (view.is_null())
return;
size_t num_bytes = 0;
for (const blink::SemanticsNode& node : update) {
num_bytes += kBytesPerNode;
num_bytes += node.children.size() * kBytesPerChild;
}
std::vector<char> buffer(num_bytes);
int32_t* buffer_int32 = reinterpret_cast<int32_t*>(&buffer[0]);
float* buffer_float32 = reinterpret_cast<float*>(&buffer[0]);
std::vector<std::string> strings;
size_t position = 0;
for (const blink::SemanticsNode& node : update) {
buffer_int32[position++] = node.id;
buffer_int32[position++] = node.flags;
buffer_int32[position++] = node.actions;
if (node.label.empty()) {
buffer_int32[position++] = -1;
} else {
buffer_int32[position++] = strings.size();
strings.push_back(node.label);
}
buffer_float32[position++] = node.rect.left();
buffer_float32[position++] = node.rect.top();
buffer_float32[position++] = node.rect.right();
buffer_float32[position++] = node.rect.bottom();
node.transform.asColMajorf(&buffer_float32[position]);
position += 16;
buffer_int32[position++] = node.children.size();
for (int32_t child : node.children)
buffer_int32[position++] = child;
}
Java_FlutterView_updateSemantics(
env, view.obj(), env->NewDirectByteBuffer(buffer.data(), buffer.size()),
base::android::ToJavaArrayOfStrings(env, strings).obj());
}
}
void PlatformViewAndroid::RunFromSource(const std::string& main,
const std::string& packages,
const std::string& assets_directory) {
......
......@@ -44,20 +44,24 @@ class PlatformViewAndroid : public PlatformView {
jint response_id,
jstring response);
void DispatchSemanticsAction(JNIEnv* env, jobject obj, jint id, jint action);
void SetSemanticsEnabled(JNIEnv* env, jobject obj, jboolean enabled);
base::android::ScopedJavaLocalRef<jobject> GetBitmap(JNIEnv* env,
jobject obj);
ftl::WeakPtr<shell::PlatformView> GetWeakViewPtr() override;
bool ResourceContextMakeCurrent() override;
virtual SkISize GetSize();
SkISize GetSize() override;
void Resize(const SkISize& size) override;
virtual void Resize(const SkISize& size);
void UpdateSemantics(std::vector<blink::SemanticsNode> update) override;
virtual void RunFromSource(const std::string& main,
const std::string& packages,
const std::string& assets_directory);
void RunFromSource(const std::string& main,
const std::string& packages,
const std::string& assets_directory) override;
void set_flutter_view(const JavaObjectWeakGlobalRef& flutter_view) {
flutter_view_ = flutter_view;
......@@ -66,7 +70,6 @@ class PlatformViewAndroid : public PlatformView {
private:
std::unique_ptr<AndroidSurfaceGL> surface_gl_;
JavaObjectWeakGlobalRef flutter_view_;
ftl::WeakPtrFactory<PlatformViewAndroid> weak_factory_;
// We use id 0 to mean that no response is expected.
int next_response_id_ = 1;
......
......@@ -25,8 +25,6 @@ class PlatformViewMac : public PlatformView, public GPUSurfaceGLDelegate {
sky::SkyEnginePtr& engineProxy();
ftl::WeakPtr<PlatformView> GetWeakViewPtr() override;
bool GLContextMakeCurrent() override;
bool GLContextClearCurrent() override;
......@@ -45,7 +43,6 @@ class PlatformViewMac : public PlatformView, public GPUSurfaceGLDelegate {
base::scoped_nsobject<NSOpenGLView> opengl_view_;
base::scoped_nsobject<NSOpenGLContext> resource_loading_context_;
sky::SkyEnginePtr sky_engine_;
ftl::WeakPtrFactory<PlatformViewMac> weak_factory_;
bool IsValid() const;
......
......@@ -23,8 +23,7 @@ PlatformViewMac::PlatformViewMac(NSOpenGLView* gl_view)
opengl_view_([gl_view retain]),
resource_loading_context_([[NSOpenGLContext alloc]
initWithFormat:gl_view.pixelFormat
shareContext:gl_view.openGLContext]),
weak_factory_(this) {
shareContext:gl_view.openGLContext]) {
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
if (paths.count > 0) {
......@@ -93,10 +92,6 @@ sky::SkyEnginePtr& PlatformViewMac::engineProxy() {
return sky_engine_;
}
ftl::WeakPtr<PlatformView> PlatformViewMac::GetWeakViewPtr() {
return weak_factory_.GetWeakPtr();
}
intptr_t PlatformViewMac::GLContextFBO() const {
// Default window bound framebuffer FBO 0.
return 0;
......
......@@ -44,6 +44,7 @@ shared_library("flutter_framework_dylib") {
deps = [
"//base:base",
"//dart/runtime:libdart",
"//flutter/lib/ui",
"//flutter/services/activity",
"//flutter/services/editing",
"//flutter/services/engine:interfaces",
......
......@@ -364,11 +364,11 @@ static inline PointerChangeMapperPhase PointerChangePhaseFromUITouchPhase(
// There doesn't appear to be any way to determine whether the accessibility
// inspector is enabled on the simulator. We conservatively always turn on the
// accessibility bridge in the simulator.
bool enable = true;
bool enabled = true;
#else
bool enable = UIAccessibilityIsVoiceOverRunning();
bool enabled = UIAccessibilityIsVoiceOverRunning();
#endif
_platformView->ToggleAccessibility(self.view, enable);
_platformView->ToggleAccessibility(self.view, enabled);
}
#pragma mark - Locale updates
......
......@@ -6,16 +6,13 @@
#define SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_ACCESSIBILITY_BRIDGE_H_
#include <memory>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "flutter/services/semantics/semantics.mojom.h"
#include "flutter/lib/ui/semantics/semantics_node.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h"
#include "flutter/sky/engine/platform/geometry/FloatRect.h"
#include "lib/ftl/macros.h"
#include "mojo/public/cpp/bindings/array.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/interfaces/application/service_provider.mojom.h"
#include "third_party/skia/include/core/SkMatrix44.h"
#include "third_party/skia/include/core/SkRect.h"
......@@ -23,50 +20,47 @@ namespace shell {
class AccessibilityBridge;
} // namespace shell
@interface SemanticObject : NSObject
@interface SemanticsObject : NSObject
/**
* The globally unique identifier for this node.
*/
@property(nonatomic, readonly) uint32_t uid;
@property(nonatomic, readonly) int32_t uid;
/**
* The parent of this node in the node tree. Will be nil for the root node and
* during transient state changes.
*/
@property(nonatomic, assign) SemanticObject* parent;
@property(nonatomic, assign) SemanticsObject* parent;
- (instancetype)init __attribute__((unavailable("Use initWithBridge instead")));
- (instancetype)initWithBridge:(shell::AccessibilityBridge*)bridge
uid:(uint32_t)uid NS_DESIGNATED_INITIALIZER;
uid:(int32_t)uid NS_DESIGNATED_INITIALIZER;
@end
namespace shell {
class PlatformViewIOS;
class AccessibilityBridge final : public semantics::SemanticsListener {
class AccessibilityBridge final {
public:
AccessibilityBridge(UIView*, mojo::ServiceProvider*);
~AccessibilityBridge() override;
AccessibilityBridge(UIView* view, PlatformViewIOS* platform_view);
~AccessibilityBridge();
void UpdateSemanticsTree(mojo::Array<semantics::SemanticsNodePtr>) override;
void UpdateSemantics(std::vector<blink::SemanticsNode> nodes);
void DispatchSemanticsAction(int32_t id, blink::SemanticsAction action);
UIView* view() { return view_; }
semantics::SemanticsServer* server() { return semantics_server_.get(); }
UIView* view() const { return view_; }
private:
SemanticObject* UpdateSemanticObject(
const semantics::SemanticsNodePtr& node,
std::set<SemanticObject*>* updated_objects,
std::set<SemanticObject*>* removed_objects);
void RemoveSemanticObject(SemanticObject* node,
std::set<SemanticObject*>* updated_objects);
SemanticsObject* GetOrCreateObject(int32_t id);
void VisitObjectsRecursively(SemanticsObject* object,
std::unordered_set<int>* visited_objects);
void ReleaseObjects(const std::unordered_map<int, SemanticsObject*>& objects);
UIView* view_;
semantics::SemanticsServerPtr semantics_server_;
std::unordered_map<int, SemanticObject*> objects_;
mojo::Binding<semantics::SemanticsListener> binding_;
PlatformViewIOS* platform_view_;
std::unordered_map<int, SemanticsObject*> objects_;
FTL_DISALLOW_COPY_AND_ASSIGN(AccessibilityBridge);
};
......
......@@ -4,45 +4,42 @@
#include "flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h"
#import <UIKit/UIKit.h>
#include <vector>
#include <utility>
#import <UIKit/UIKit.h>
#include "base/logging.h"
#include "mojo/public/cpp/application/connect.h"
#include "lib/ftl/logging.h"
#include "flutter/shell/platform/darwin/ios/platform_view_ios.h"
namespace {
constexpr uint32_t kRootNodeId = 0;
constexpr int32_t kRootNodeId = 0;
// Contains better abstractions than the raw Mojo data structure
struct Geometry {
Geometry& operator=(const semantics::SemanticGeometryPtr& other) {
if (!other->transform.is_null()) {
transform.setColMajorf(other->transform.data());
}
rect.setXYWH(other->left, other->top, other->width, other->height);
return *this;
blink::SemanticsAction GetSemanticsActionForScrollDirection(
UIAccessibilityScrollDirection direction) {
switch (direction) {
case UIAccessibilityScrollDirectionRight:
case UIAccessibilityScrollDirectionPrevious: // TODO(abarth): Support RTL.
return blink::SemanticsAction::kScrollRight;
case UIAccessibilityScrollDirectionLeft:
case UIAccessibilityScrollDirectionNext: // TODO(abarth): Support RTL.
return blink::SemanticsAction::kScrollLeft;
case UIAccessibilityScrollDirectionUp:
return blink::SemanticsAction::kScrollUp;
case UIAccessibilityScrollDirectionDown:
return blink::SemanticsAction::kScrollDown;
}
SkMatrix44 transform = SkMatrix44(SkMatrix44::kIdentity_Constructor);
SkRect rect;
};
FTL_DCHECK(false); // Unreachable
return blink::SemanticsAction::kScrollDown;
}
} // namespace
@implementation SemanticObject {
@implementation SemanticsObject {
shell::AccessibilityBridge* _bridge;
semantics::SemanticFlagsPtr _flags;
semantics::SemanticStringsPtr _strings;
Geometry _geometry;
bool _canBeTapped;
bool _canBeLongPressed;
bool _canBeScrolledHorizontally;
bool _canBeScrolledVertically;
bool _canBeAdjusted;
std::vector<SemanticObject*> _children;
blink::SemanticsNode _node;
std::vector<SemanticsObject*> _children;
}
#pragma mark - Override base class designated initializers
......@@ -57,9 +54,9 @@ struct Geometry {
#pragma mark - Designated initializers
- (instancetype)initWithBridge:(shell::AccessibilityBridge*)bridge
uid:(uint32_t)uid {
DCHECK(bridge != nil) << "bridge must be set";
DCHECK(uid >= kRootNodeId);
uid:(int32_t)uid {
FTL_DCHECK(bridge != nil) << "bridge must be set";
FTL_DCHECK(uid >= kRootNodeId);
self = [super init];
if (self) {
......@@ -72,52 +69,11 @@ struct Geometry {
#pragma mark - Semantic object methods
- (void)updateWith:(const semantics::SemanticsNodePtr&)node {
DCHECK(_uid == node->id);
if (!node->flags.is_null()) {
_flags = node->flags.Pass();
}
if (!node->strings.is_null()) {
_strings = node->strings.Pass();
}
if (!node->geometry.is_null()) {
_geometry = node->geometry;
}
if (!node->actions.is_null()) {
_canBeTapped = false;
_canBeLongPressed = false;
_canBeScrolledHorizontally = false;
_canBeScrolledVertically = false;
for (int action : node->actions) {
switch (static_cast<semantics::SemanticAction>(action)) {
case semantics::SemanticAction::TAP:
_canBeTapped = true;
break;
case semantics::SemanticAction::LONG_PRESS:
_canBeLongPressed = true;
break;
case semantics::SemanticAction::SCROLL_LEFT:
case semantics::SemanticAction::SCROLL_RIGHT:
_canBeScrolledHorizontally = true;
break;
case semantics::SemanticAction::SCROLL_UP:
case semantics::SemanticAction::SCROLL_DOWN:
_canBeScrolledVertically = true;
break;
case semantics::SemanticAction::INCREASE:
case semantics::SemanticAction::DECREASE:
_canBeAdjusted = true;
break;
}
}
}
- (void)setSemanticsNode:(const blink::SemanticsNode*)node {
_node = *node;
}
- (std::vector<SemanticObject*>*)children {
- (std::vector<SemanticsObject*>*)children {
return &_children;
}
......@@ -133,39 +89,40 @@ struct Geometry {
// Note: hit detection will only apply to elements that report
// -isAccessibilityElement of YES. The framework will continue scanning the
// entire element tree looking for such a hit.
return _canBeTapped || _children.empty();
return _node.HasAction(blink::SemanticsAction::kTap) || _children.empty();
}
- (NSString*)accessibilityLabel {
if (_strings.is_null() || _strings->label.get().empty()) {
if (_node.label.empty()) {
return nil;
}
return @(_strings->label.data());
return @(_node.label.data());
}
- (UIAccessibilityTraits)accessibilityTraits {
UIAccessibilityTraits traits = UIAccessibilityTraitNone;
if (_canBeTapped) {
if (_node.HasAction(blink::SemanticsAction::kTap)) {
traits |= UIAccessibilityTraitButton;
}
if (_canBeAdjusted) {
if (_node.HasAction(blink::SemanticsAction::kIncrease)
|| _node.HasAction(blink::SemanticsAction::kDecrease)) {
traits |= UIAccessibilityTraitAdjustable;
}
return traits;
}
- (CGRect)accessibilityFrame {
SkMatrix44 globalTransform = _geometry.transform;
for (SemanticObject* parent = _parent; parent; parent = parent.parent) {
globalTransform = globalTransform * parent->_geometry.transform;
SkMatrix44 globalTransform = _node.transform;
for (SemanticsObject* parent = _parent; parent; parent = parent.parent) {
globalTransform = globalTransform * parent->_node.transform;
}
SkPoint quad[4];
_geometry.rect.toQuad(quad);
_node.rect.toQuad(quad);
for (auto& point : quad) {
SkScalar vector[4] = {point.x(), point.y(), 0, 1};
globalTransform.mapScalars(vector);
point.set(vector[0], vector[1]);
point.set(vector[0] / vector[3], vector[1] / vector[3]);
}
SkRect rect;
rect.set(quad, 4);
......@@ -210,61 +167,22 @@ struct Geometry {
}
- (void)accessibilityIncrement {
if (_canBeAdjusted) {
_bridge->server()->PerformAction(_uid, semantics::SemanticAction::INCREASE);
if (_node.HasAction(blink::SemanticsAction::kIncrease)) {
_bridge->DispatchSemanticsAction(_uid, blink::SemanticsAction::kIncrease);
}
}
- (void)accessibilityDecrement {
if (_canBeAdjusted) {
_bridge->server()->PerformAction(_uid, semantics::SemanticAction::DECREASE);
if (_node.HasAction(blink::SemanticsAction::kDecrease)) {
_bridge->DispatchSemanticsAction(_uid, blink::SemanticsAction::kDecrease);
}
}
- (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction {
BOOL canBeScrolled = NO;
switch (direction) {
case UIAccessibilityScrollDirectionRight:
case UIAccessibilityScrollDirectionLeft:
canBeScrolled = _canBeScrolledHorizontally;
break;
case UIAccessibilityScrollDirectionUp:
case UIAccessibilityScrollDirectionDown:
canBeScrolled = _canBeScrolledVertically;
break;
default:
// Note: page turning of reading content is not currently supported
// (UIAccessibilityScrollDirectionNext,
// UIAccessibilityScrollDirectionPrevious)
canBeScrolled = NO;
break;
}
if (!canBeScrolled) {
blink::SemanticsAction action = GetSemanticsActionForScrollDirection(direction);
if (_node.HasAction(action))
return NO;
}
switch (direction) {
case UIAccessibilityScrollDirectionRight:
_bridge->server()->PerformAction(_uid,
semantics::SemanticAction::SCROLL_RIGHT);
break;
case UIAccessibilityScrollDirectionLeft:
_bridge->server()->PerformAction(_uid,
semantics::SemanticAction::SCROLL_LEFT);
break;
case UIAccessibilityScrollDirectionUp:
_bridge->server()->PerformAction(_uid,
semantics::SemanticAction::SCROLL_UP);
break;
case UIAccessibilityScrollDirectionDown:
_bridge->server()->PerformAction(_uid,
semantics::SemanticAction::SCROLL_DOWN);
break;
default:
DCHECK(false) << "Unsupported scroll direction: " << direction;
}
_bridge->DispatchSemanticsAction(_uid, action);
// TODO(tvolkert): provide meaningful string (e.g. "page 2 of 5")
UIAccessibilityPostNotification(UIAccessibilityPageScrolledNotification, nil);
return YES;
......@@ -287,38 +205,46 @@ struct Geometry {
namespace shell {
AccessibilityBridge::AccessibilityBridge(UIView* view,
mojo::ServiceProvider* serviceProvider)
: view_(view), binding_(this) {
mojo::ConnectToService(serviceProvider, mojo::GetProxy(&semantics_server_));
mojo::InterfaceHandle<semantics::SemanticsListener> listener;
binding_.Bind(&listener);
semantics_server_->AddSemanticsListener(listener.Pass());
}
PlatformViewIOS* platform_view)
: view_(view), platform_view_(platform_view) {}
AccessibilityBridge::~AccessibilityBridge() {
for (const auto& entry : objects_) {
SemanticObject* object = entry.second;
[object neuter];
[object release];
}
ReleaseObjects(objects_);
objects_.clear();
}
void AccessibilityBridge::UpdateSemanticsTree(
mojo::Array<semantics::SemanticsNodePtr> nodes) {
std::set<SemanticObject*> updated_objects;
std::set<SemanticObject*> removed_objects;
for (const semantics::SemanticsNodePtr& node : nodes) {
UpdateSemanticObject(node, &updated_objects, &removed_objects);
void AccessibilityBridge::UpdateSemantics(std::vector<blink::SemanticsNode> nodes) {
for (const blink::SemanticsNode& node : nodes) {
SemanticsObject* object = GetOrCreateObject(node.id);
[object setSemanticsNode:&node];
const size_t childrenCount = node.children.size();
auto& children = *[object children];
children.resize(childrenCount);
for (size_t i = 0; i < childrenCount; ++i) {
SemanticsObject* child = GetOrCreateObject(node.children[i]);
child.parent = object;
children[i] = child;
}
}
for (SemanticObject* object : removed_objects) {
if (!updated_objects.count(object)) {
RemoveSemanticObject(object, &updated_objects);
}
SemanticsObject* root = objects_[kRootNodeId];
std::unordered_set<int> visited_objects;
if (root)
VisitObjectsRecursively(root, &visited_objects);
std::unordered_map<int, SemanticsObject*> doomed_objects;
doomed_objects.swap(objects_);
for (int uid : visited_objects) {
auto it = doomed_objects.find(uid);
objects_.insert(*it);
doomed_objects.erase(it);
// TODO(abarth): Use extract once we're at C++17.
}
SemanticObject* root = objects_[kRootNodeId];
ReleaseObjects(doomed_objects);
doomed_objects.clear();
if (root) {
if (!view_.accessibilityElements) {
view_.accessibilityElements = @[ root ];
......@@ -330,46 +256,36 @@ void AccessibilityBridge::UpdateSemanticsTree(
nil);
}
SemanticObject* AccessibilityBridge::UpdateSemanticObject(
const semantics::SemanticsNodePtr& node,
std::set<SemanticObject*>* updated_objects,
std::set<SemanticObject*>* removed_objects) {
SemanticObject* object = objects_[node->id];
void AccessibilityBridge::DispatchSemanticsAction(
int32_t uid,
blink::SemanticsAction action) {
platform_view_->DispatchSemanticsAction(uid, action);
}
SemanticsObject* AccessibilityBridge::GetOrCreateObject(int32_t uid) {
SemanticsObject* object = objects_[uid];
if (!object) {
object = [[SemanticObject alloc] initWithBridge:this uid:node->id];
objects_[node->id] = object;
}
[object updateWith:node];
updated_objects->insert(object);
if (!node->children.is_null()) {
std::vector<SemanticObject*>* children = [object children];
removed_objects->insert(children->begin(), children->end());
children->clear();
children->reserve(node->children.size());
for (const auto& child_node : node->children) {
SemanticObject* child_object =
UpdateSemanticObject(child_node, updated_objects, removed_objects);
child_object.parent = object;
children->push_back(child_object);
}
object = [[SemanticsObject alloc] initWithBridge:this uid:uid];
objects_[uid] = object;
}
return object;
}
void AccessibilityBridge::RemoveSemanticObject(
SemanticObject* object,
std::set<SemanticObject*>* updated_objects) {
DCHECK(objects_[object.uid] == object);
objects_.erase(object.uid);
for (SemanticObject* child : *[object children]) {
if (!updated_objects->count(child)) {
DCHECK(child.parent == object);
child.parent = nil;
RemoveSemanticObject(child, updated_objects);
}
void AccessibilityBridge::VisitObjectsRecursively(
SemanticsObject* object,
std::unordered_set<int>* visited_objects) {
visited_objects->insert(object.uid);
for (SemanticsObject* child : *[object children])
VisitObjectsRecursively(child, visited_objects);
}
void AccessibilityBridge::ReleaseObjects(
const std::unordered_map<int, SemanticsObject*>& objects) {
for (const auto& entry : objects) {
SemanticsObject* object = entry.second;
[object neuter];
[object release];
}
[object neuter];
[object release];
}
} // namespace shell
......@@ -29,7 +29,7 @@ class PlatformViewIOS : public PlatformView, public GPUSurfaceGLDelegate {
~PlatformViewIOS() override;
void ToggleAccessibility(UIView* view, bool enable);
void ToggleAccessibility(UIView* view, bool enabled);
void ConnectToEngineAndSetupServices();
......@@ -39,8 +39,6 @@ class PlatformViewIOS : public PlatformView, public GPUSurfaceGLDelegate {
ApplicationMessagesImpl& AppMessageReceiver();
ftl::WeakPtr<PlatformView> GetWeakViewPtr() override;
bool ResourceContextMakeCurrent() override;
bool GLContextMakeCurrent() override;
......@@ -55,6 +53,8 @@ class PlatformViewIOS : public PlatformView, public GPUSurfaceGLDelegate {
const std::string& packages,
const std::string& assets_directory) override;
void UpdateSemantics(std::vector<blink::SemanticsNode> update) override;
private:
std::unique_ptr<IOSGLContext> context_;
sky::SkyEnginePtr engine_;
......@@ -62,7 +62,6 @@ class PlatformViewIOS : public PlatformView, public GPUSurfaceGLDelegate {
flutter::platform::ApplicationMessagesPtr app_message_sender_;
ApplicationMessagesImpl app_message_receiver_;
std::unique_ptr<AccessibilityBridge> accessibility_bridge_;
ftl::WeakPtrFactory<PlatformViewIOS> weak_factory_;
void SetupAndLoadFromSource(const std::string& main,
const std::string& packages,
......
......@@ -273,8 +273,7 @@ class IOSGLContext {
PlatformViewIOS::PlatformViewIOS(CAEAGLLayer* layer)
: PlatformView(std::make_unique<GPURasterizer>()),
context_(std::make_unique<IOSGLContext>(surface_config_, layer)),
weak_factory_(this) {
context_(std::make_unique<IOSGLContext>(surface_config_, layer)) {
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
shell::Shell::Shared().tracing_controller().set_traces_base_path(
......@@ -295,15 +294,16 @@ shell::ApplicationMessagesImpl& PlatformViewIOS::AppMessageReceiver() {
return app_message_receiver_;
}
void PlatformViewIOS::ToggleAccessibility(UIView* view, bool enable) {
if (enable) {
if (!accessibility_bridge_ && dart_services_.get() != nullptr) {
void PlatformViewIOS::ToggleAccessibility(UIView* view, bool enabled) {
if (enabled) {
if (!accessibility_bridge_) {
accessibility_bridge_.reset(
new shell::AccessibilityBridge(view, dart_services_.get()));
new shell::AccessibilityBridge(view, this));
}
} else {
accessibility_bridge_ = nullptr;
}
SetSemanticsEnabled(enabled);
}
void PlatformViewIOS::ConnectToEngineAndSetupServices() {
......@@ -347,10 +347,6 @@ void PlatformViewIOS::SetupAndLoadFromSource(
engine_->RunFromFile(main, packages, assets_directory);
}
ftl::WeakPtr<PlatformView> PlatformViewIOS::GetWeakViewPtr() {
return weak_factory_.GetWeakPtr();
}
bool PlatformViewIOS::ResourceContextMakeCurrent() {
return context_ != nullptr ? context_->ResourceMakeCurrent() : false;
}
......@@ -387,4 +383,10 @@ void PlatformViewIOS::RunFromSource(const std::string& main,
delete latch;
}
void PlatformViewIOS::UpdateSemantics(
std::vector<blink::SemanticsNode> update) {
if (accessibility_bridge_)
accessibility_bridge_->UpdateSemantics(std::move(update));
}
} // namespace shell
......@@ -18,8 +18,7 @@ PlatformViewGLFW::PlatformViewGLFW()
: PlatformView(std::make_unique<GPURasterizer>()),
valid_(false),
glfw_window_(nullptr),
buttons_(0),
weak_factory_(this) {
buttons_(0) {
if (!glfwInit()) {
return;
}
......@@ -78,10 +77,6 @@ bool PlatformViewGLFW::IsValid() const {
return valid_;
}
ftl::WeakPtr<PlatformView> PlatformViewGLFW::GetWeakViewPtr() {
return weak_factory_.GetWeakPtr();
}
intptr_t PlatformViewGLFW::GLContextFBO() const {
// The default window bound FBO.
return 0;
......
......@@ -26,8 +26,6 @@ class PlatformViewGLFW : public PlatformView, public GPUSurfaceGLDelegate {
bool IsValid() const;
ftl::WeakPtr<PlatformView> GetWeakViewPtr() override;
bool ResourceContextMakeCurrent() override;
bool GLContextMakeCurrent() override;
......@@ -47,7 +45,6 @@ class PlatformViewGLFW : public PlatformView, public GPUSurfaceGLDelegate {
GLFWwindow* glfw_window_;
sky::SkyEnginePtr engine_;
int buttons_;
ftl::WeakPtrFactory<PlatformViewGLFW> weak_factory_;
void OnWindowSizeChanged(int width, int height);
......
......@@ -4,21 +4,16 @@
#include "flutter/shell/testing/platform_view_test.h"
#include "flutter/shell/common/shell.h"
#include "flutter/shell/common/null_rasterizer.h"
#include "flutter/shell/common/shell.h"
namespace shell {
PlatformViewTest::PlatformViewTest()
: PlatformView(std::unique_ptr<Rasterizer>(new NullRasterizer())),
weak_factory_(this) {}
: PlatformView(std::unique_ptr<Rasterizer>(new NullRasterizer())) {}
PlatformViewTest::~PlatformViewTest() = default;
ftl::WeakPtr<PlatformView> PlatformViewTest::GetWeakViewPtr() {
return weak_factory_.GetWeakPtr();
}
bool PlatformViewTest::ResourceContextMakeCurrent() {
return false;
}
......
......@@ -19,8 +19,6 @@ class PlatformViewTest : public PlatformView {
~PlatformViewTest();
ftl::WeakPtr<PlatformView> GetWeakViewPtr() override;
bool ResourceContextMakeCurrent() override;
void RunFromSource(const std::string& main,
......@@ -28,8 +26,6 @@ class PlatformViewTest : public PlatformView {
const std::string& assets_directory) override;
private:
ftl::WeakPtrFactory<PlatformViewTest> weak_factory_;
FTL_DISALLOW_COPY_AND_ASSIGN(PlatformViewTest);
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册