{"action":"created","comment":{"url":"https://api.github.com/repos/flutter/engine/pulls/comments/59448959","id":59448959,"diff_hunk":"@@ -0,0 +1,245 @@\n+// Copyright 2016 The Chromium Authors. All rights reserved.\n+// Use of this source code is governed by a BSD-style license that can be\n+// found in the LICENSE file.\n+\n+#include \"sky/shell/platform/ios/semantics_listener_impl.h\"\n+\n+namespace sky {\n+namespace shell {\n+\n+SemanticsListenerImpl::SemanticsListenerImpl(\n+    FlutterView* view,\n+    semantics::SemanticsServerPtr semanticsServer)\n+    : _view(view), _binding(this) {\n+  mojo::InterfaceHandle<semantics::SemanticsListener> listener;\n+  _binding.Bind(&listener);\n+  semanticsServer->AddSemanticsListener(listener.Pass());\n+}\n+\n+void SemanticsListenerImpl::UpdateSemanticsTree(\n+    mojo::Array<semantics::SemanticsNodePtr> nodes) {\n+  for (const semantics::SemanticsNodePtr& node : nodes) {\n+    updateSemanticsNode(node);\n+  }\n+  NSArray* accessibleElements = createAccessibleElements();\n+  [_view updateAccessibleElements:accessibleElements];\n+  [accessibleElements release];\n+}\n+\n+SemanticsListenerImpl::AccessibilityNode*\n+SemanticsListenerImpl::updateSemanticsNode(\n+    const semantics::SemanticsNodePtr& node) {\n+  AccessibilityNode* persistentNode;\n+  NodeMapIterator iter = _nodes.find(node->id);\n+  if (iter == _nodes.end()) {\n+    persistentNode = new AccessibilityNode(this, node);\n+    _nodes.insert(NodeMap::value_type(node->id, persistentNode));\n+  } else {\n+    persistentNode = iter->second;\n+    persistentNode->update(node);\n+  }\n+  assert(persistentNode != NULL);\n+  return persistentNode;\n+}\n+\n+void SemanticsListenerImpl::removePersistentNode(AccessibilityNode* node) {\n+  assert(_nodes.find(node->id) != _nodes.end());\n+  assert(_nodes.at(node->id)->parent == NULL);\n+  _nodes.erase(node->id);\n+  for (AccessibilityNode* child : node->children) {\n+    removePersistentNode(child);\n+  }\n+}\n+\n+NSArray* SemanticsListenerImpl::createAccessibleElements() {\n+  NSMutableArray* accessibleElements = [[NSMutableArray alloc] init];\n+  for (NodeMapIterator iter = _nodes.begin(); iter != _nodes.end(); iter++) {\n+    if (iter->second->parent == NULL) {\n+      iter->second->populateAccessibleElements(accessibleElements);\n+    }\n+  }\n+  return accessibleElements;\n+}\n+\n+SemanticsListenerImpl::~SemanticsListenerImpl() {}\n+\n+SemanticsListenerImpl::AccessibilityNode::AccessibilityNode(\n+    SemanticsListenerImpl* outer,\n+    const semantics::SemanticsNodePtr& node)\n+    : outer(outer) {\n+  update(node);\n+}\n+\n+void SemanticsListenerImpl::AccessibilityNode::update(\n+    const semantics::SemanticsNodePtr& node) {\n+  if (id == (uint32_t)-1) {\n+    id = node->id;\n+  }\n+  assert(id == node->id);\n+\n+  if (!node->flags.is_null()) {\n+    canBeTapped = node->flags->canBeTapped;","path":"sky/shell/platform/ios/semantics_listener_impl.mm","position":81,"original_position":81,"commit_id":"5a1fb887b5990fe14cf8bf304b64dc3d66183ae1","original_commit_id":"5a1fb887b5990fe14cf8bf304b64dc3d66183ae1","user":{"login":"eseidelGoogle","id":11857803,"avatar_url":"https://avatars.githubusercontent.com/u/11857803?v=3","gravatar_id":"","url":"https://api.github.com/users/eseidelGoogle","html_url":"https://github.com/eseidelGoogle","followers_url":"https://api.github.com/users/eseidelGoogle/followers","following_url":"https://api.github.com/users/eseidelGoogle/following{/other_user}","gists_url":"https://api.github.com/users/eseidelGoogle/gists{/gist_id}","starred_url":"https://api.github.com/users/eseidelGoogle/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/eseidelGoogle/subscriptions","organizations_url":"https://api.github.com/users/eseidelGoogle/orgs","repos_url":"https://api.github.com/users/eseidelGoogle/repos","events_url":"https://api.github.com/users/eseidelGoogle/events{/privacy}","received_events_url":"https://api.github.com/users/eseidelGoogle/received_events","type":"User","site_admin":false},"body":"Maybe we should group these all in a Flags object if they always get set/initialized together?","created_at":"2016-04-12T20:37:44Z","updated_at":"2016-04-12T20:37:44Z","html_url":"https://github.com/flutter/engine/pull/2594#discussion_r59448959","pull_request_url":"https://api.github.com/repos/flutter/engine/pulls/2594","_links":{"self":{"href":"https://api.github.com/repos/flutter/engine/pulls/comments/59448959"},"html":{"href":"https://github.com/flutter/engine/pull/2594#discussion_r59448959"},"pull_request":{"href":"https://api.github.com/repos/flutter/engine/pulls/2594"}}},"pull_request":{"url":"https://api.github.com/repos/flutter/engine/pulls/2594","id":66221261,"html_url":"https://github.com/flutter/engine/pull/2594","diff_url":"https://github.com/flutter/engine/pull/2594.diff","patch_url":"https://github.com/flutter/engine/pull/2594.patch","issue_url":"https://api.github.com/repos/flutter/engine/issues/2594","number":2594,"state":"open","locked":false,"title":"Report Flutter widgets to iOS accessibility API","user":{"login":"tvolkert","id":15253456,"avatar_url":"https://avatars.githubusercontent.com/u/15253456?v=3","gravatar_id":"","url":"https://api.github.com/users/tvolkert","html_url":"https://github.com/tvolkert","followers_url":"https://api.github.com/users/tvolkert/followers","following_url":"https://api.github.com/users/tvolkert/following{/other_user}","gists_url":"https://api.github.com/users/tvolkert/gists{/gist_id}","starred_url":"https://api.github.com/users/tvolkert/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tvolkert/subscriptions","organizations_url":"https://api.github.com/users/tvolkert/orgs","repos_url":"https://api.github.com/users/tvolkert/repos","events_url":"https://api.github.com/users/tvolkert/events{/privacy}","received_events_url":"https://api.github.com/users/tvolkert/received_events","type":"User","site_admin":false},"body":"This registers a SemanticsListener with the Dart VM\r\nso that the shell gets called back whenever the layout\r\ntree changes.  The listener rebuilds the accessibility\r\nelement array that iOS uses to drive its accessibility\r\ninterface.\r\n\r\nStill TODO:\r\n* finer-grained semantics of widget types\r\n* gesture reporting such as swiping / scrolling\r\n* proper relayout reporting","created_at":"2016-04-12T20:20:35Z","updated_at":"2016-04-12T20:37:44Z","closed_at":null,"merged_at":null,"merge_commit_sha":"585befdb07d3d3082b96deb4297f2afe27559417","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/flutter/engine/pulls/2594/commits","review_comments_url":"https://api.github.com/repos/flutter/engine/pulls/2594/comments","review_comment_url":"https://api.github.com/repos/flutter/engine/pulls/comments{/number}","comments_url":"https://api.github.com/repos/flutter/engine/issues/2594/comments","statuses_url":"https://api.github.com/repos/flutter/engine/statuses/5a1fb887b5990fe14cf8bf304b64dc3d66183ae1","head":{"label":"tvolkert:work","ref":"work","sha":"5a1fb887b5990fe14cf8bf304b64dc3d66183ae1","user":{"login":"tvolkert","id":15253456,"avatar_url":"https://avatars.githubusercontent.com/u/15253456?v=3","gravatar_id":"","url":"https://api.github.com/users/tvolkert","html_url":"https://github.com/tvolkert","followers_url":"https://api.github.com/users/tvolkert/followers","following_url":"https://api.github.com/users/tvolkert/following{/other_user}","gists_url":"https://api.github.com/users/tvolkert/gists{/gist_id}","starred_url":"https://api.github.com/users/tvolkert/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tvolkert/subscriptions","organizations_url":"https://api.github.com/users/tvolkert/orgs","repos_url":"https://api.github.com/users/tvolkert/repos","events_url":"https://api.github.com/users/tvolkert/events{/privacy}","received_events_url":"https://api.github.com/users/tvolkert/received_events","type":"User","site_admin":false},"repo":{"id":44769006,"name":"engine","full_name":"tvolkert/engine","owner":{"login":"tvolkert","id":15253456,"avatar_url":"https://avatars.githubusercontent.com/u/15253456?v=3","gravatar_id":"","url":"https://api.github.com/users/tvolkert","html_url":"https://github.com/tvolkert","followers_url":"https://api.github.com/users/tvolkert/followers","following_url":"https://api.github.com/users/tvolkert/following{/other_user}","gists_url":"https://api.github.com/users/tvolkert/gists{/gist_id}","starred_url":"https://api.github.com/users/tvolkert/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tvolkert/subscriptions","organizations_url":"https://api.github.com/users/tvolkert/orgs","repos_url":"https://api.github.com/users/tvolkert/repos","events_url":"https://api.github.com/users/tvolkert/events{/privacy}","received_events_url":"https://api.github.com/users/tvolkert/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/tvolkert/engine","description":"The Flutter engine","fork":true,"url":"https://api.github.com/repos/tvolkert/engine","forks_url":"https://api.github.com/repos/tvolkert/engine/forks","keys_url":"https://api.github.com/repos/tvolkert/engine/keys{/key_id}","collaborators_url":"https://api.github.com/repos/tvolkert/engine/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/tvolkert/engine/teams","hooks_url":"https://api.github.com/repos/tvolkert/engine/hooks","issue_events_url":"https://api.github.com/repos/tvolkert/engine/issues/events{/number}","events_url":"https://api.github.com/repos/tvolkert/engine/events","assignees_url":"https://api.github.com/repos/tvolkert/engine/assignees{/user}","branches_url":"https://api.github.com/repos/tvolkert/engine/branches{/branch}","tags_url":"https://api.github.com/repos/tvolkert/engine/tags","blobs_url":"https://api.github.com/repos/tvolkert/engine/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/tvolkert/engine/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/tvolkert/engine/git/refs{/sha}","trees_url":"https://api.github.com/repos/tvolkert/engine/git/trees{/sha}","statuses_url":"https://api.github.com/repos/tvolkert/engine/statuses/{sha}","languages_url":"https://api.github.com/repos/tvolkert/engine/languages","stargazers_url":"https://api.github.com/repos/tvolkert/engine/stargazers","contributors_url":"https://api.github.com/repos/tvolkert/engine/contributors","subscribers_url":"https://api.github.com/repos/tvolkert/engine/subscribers","subscription_url":"https://api.github.com/repos/tvolkert/engine/subscription","commits_url":"https://api.github.com/repos/tvolkert/engine/commits{/sha}","git_commits_url":"https://api.github.com/repos/tvolkert/engine/git/commits{/sha}","comments_url":"https://api.github.com/repos/tvolkert/engine/comments{/number}","issue_comment_url":"https://api.github.com/repos/tvolkert/engine/issues/comments{/number}","contents_url":"https://api.github.com/repos/tvolkert/engine/contents/{+path}","compare_url":"https://api.github.com/repos/tvolkert/engine/compare/{base}...{head}","merges_url":"https://api.github.com/repos/tvolkert/engine/merges","archive_url":"https://api.github.com/repos/tvolkert/engine/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/tvolkert/engine/downloads","issues_url":"https://api.github.com/repos/tvolkert/engine/issues{/number}","pulls_url":"https://api.github.com/repos/tvolkert/engine/pulls{/number}","milestones_url":"https://api.github.com/repos/tvolkert/engine/milestones{/number}","notifications_url":"https://api.github.com/repos/tvolkert/engine/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/tvolkert/engine/labels{/name}","releases_url":"https://api.github.com/repos/tvolkert/engine/releases{/id}","deployments_url":"https://api.github.com/repos/tvolkert/engine/deployments","created_at":"2015-10-22T19:41:35Z","updated_at":"2016-02-10T19:12:24Z","pushed_at":"2016-04-12T20:22:28Z","git_url":"git://github.com/tvolkert/engine.git","ssh_url":"git@github.com:tvolkert/engine.git","clone_url":"https://github.com/tvolkert/engine.git","svn_url":"https://github.com/tvolkert/engine","homepage":"http://flutter.io","size":81589,"stargazers_count":0,"watchers_count":0,"language":"C++","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"flutter:master","ref":"master","sha":"c3504b519fcd95179ea832460758712ecd0e433d","user":{"login":"flutter","id":14101776,"avatar_url":"https://avatars.githubusercontent.com/u/14101776?v=3","gravatar_id":"","url":"https://api.github.com/users/flutter","html_url":"https://github.com/flutter","followers_url":"https://api.github.com/users/flutter/followers","following_url":"https://api.github.com/users/flutter/following{/other_user}","gists_url":"https://api.github.com/users/flutter/gists{/gist_id}","starred_url":"https://api.github.com/users/flutter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/flutter/subscriptions","organizations_url":"https://api.github.com/users/flutter/orgs","repos_url":"https://api.github.com/users/flutter/repos","events_url":"https://api.github.com/users/flutter/events{/privacy}","received_events_url":"https://api.github.com/users/flutter/received_events","type":"Organization","site_admin":false},"repo":{"id":39211337,"name":"engine","full_name":"flutter/engine","owner":{"login":"flutter","id":14101776,"avatar_url":"https://avatars.githubusercontent.com/u/14101776?v=3","gravatar_id":"","url":"https://api.github.com/users/flutter","html_url":"https://github.com/flutter","followers_url":"https://api.github.com/users/flutter/followers","following_url":"https://api.github.com/users/flutter/following{/other_user}","gists_url":"https://api.github.com/users/flutter/gists{/gist_id}","starred_url":"https://api.github.com/users/flutter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/flutter/subscriptions","organizations_url":"https://api.github.com/users/flutter/orgs","repos_url":"https://api.github.com/users/flutter/repos","events_url":"https://api.github.com/users/flutter/events{/privacy}","received_events_url":"https://api.github.com/users/flutter/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/flutter/engine","description":"The Flutter engine","fork":false,"url":"https://api.github.com/repos/flutter/engine","forks_url":"https://api.github.com/repos/flutter/engine/forks","keys_url":"https://api.github.com/repos/flutter/engine/keys{/key_id}","collaborators_url":"https://api.github.com/repos/flutter/engine/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/flutter/engine/teams","hooks_url":"https://api.github.com/repos/flutter/engine/hooks","issue_events_url":"https://api.github.com/repos/flutter/engine/issues/events{/number}","events_url":"https://api.github.com/repos/flutter/engine/events","assignees_url":"https://api.github.com/repos/flutter/engine/assignees{/user}","branches_url":"https://api.github.com/repos/flutter/engine/branches{/branch}","tags_url":"https://api.github.com/repos/flutter/engine/tags","blobs_url":"https://api.github.com/repos/flutter/engine/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/flutter/engine/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/flutter/engine/git/refs{/sha}","trees_url":"https://api.github.com/repos/flutter/engine/git/trees{/sha}","statuses_url":"https://api.github.com/repos/flutter/engine/statuses/{sha}","languages_url":"https://api.github.com/repos/flutter/engine/languages","stargazers_url":"https://api.github.com/repos/flutter/engine/stargazers","contributors_url":"https://api.github.com/repos/flutter/engine/contributors","subscribers_url":"https://api.github.com/repos/flutter/engine/subscribers","subscription_url":"https://api.github.com/repos/flutter/engine/subscription","commits_url":"https://api.github.com/repos/flutter/engine/commits{/sha}","git_commits_url":"https://api.github.com/repos/flutter/engine/git/commits{/sha}","comments_url":"https://api.github.com/repos/flutter/engine/comments{/number}","issue_comment_url":"https://api.github.com/repos/flutter/engine/issues/comments{/number}","contents_url":"https://api.github.com/repos/flutter/engine/contents/{+path}","compare_url":"https://api.github.com/repos/flutter/engine/compare/{base}...{head}","merges_url":"https://api.github.com/repos/flutter/engine/merges","archive_url":"https://api.github.com/repos/flutter/engine/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/flutter/engine/downloads","issues_url":"https://api.github.com/repos/flutter/engine/issues{/number}","pulls_url":"https://api.github.com/repos/flutter/engine/pulls{/number}","milestones_url":"https://api.github.com/repos/flutter/engine/milestones{/number}","notifications_url":"https://api.github.com/repos/flutter/engine/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/flutter/engine/labels{/name}","releases_url":"https://api.github.com/repos/flutter/engine/releases{/id}","deployments_url":"https://api.github.com/repos/flutter/engine/deployments","created_at":"2015-07-16T17:39:56Z","updated_at":"2016-04-12T10:53:52Z","pushed_at":"2016-04-12T20:22:28Z","git_url":"git://github.com/flutter/engine.git","ssh_url":"git@github.com:flutter/engine.git","clone_url":"https://github.com/flutter/engine.git","svn_url":"https://github.com/flutter/engine","homepage":"http://flutter.io","size":103700,"stargazers_count":870,"watchers_count":870,"language":"C++","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":141,"mirror_url":null,"open_issues_count":1,"forks":141,"open_issues":1,"watchers":870,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/flutter/engine/pulls/2594"},"html":{"href":"https://github.com/flutter/engine/pull/2594"},"issue":{"href":"https://api.github.com/repos/flutter/engine/issues/2594"},"comments":{"href":"https://api.github.com/repos/flutter/engine/issues/2594/comments"},"review_comments":{"href":"https://api.github.com/repos/flutter/engine/pulls/2594/comments"},"review_comment":{"href":"https://api.github.com/repos/flutter/engine/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/flutter/engine/pulls/2594/commits"},"statuses":{"href":"https://api.github.com/repos/flutter/engine/statuses/5a1fb887b5990fe14cf8bf304b64dc3d66183ae1"}}}}