<commit_before>// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "sky/shell/platform/ios/framework/Source/accessibility_bridge.h"

#import <UIKit/UIKit.h>

#include "mojo/public/cpp/application/connect.h"

namespace {

static const uint32_t RootNodeId = 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;
  }

  SkMatrix44 transform =
      SkMatrix44(SkMatrix44::Identity_Constructor::kIdentity_Constructor);
  SkRect rect;
};

}  // anonymous namespace

@implementation AccessibilityNode {
  sky::shell::AccessibilityBridge* _bridge;

  semantics::SemanticFlagsPtr _flags;
  semantics::SemanticStringsPtr _strings;
  Geometry _geometry;
}

#pragma mark - Override base class designated initializers

// Method declared as unavailable in the interface
- (instancetype)init {
  [self release];
  [super doesNotRecognizeSelector:_cmd];
  return nil;
}

#pragma mark - Designated initializers

- (instancetype)initWithBridge:(sky::shell::AccessibilityBridge*)bridge
                           uid:(uint32_t)uid {
  DCHECK(bridge != nil) << "bridge must be set";
  DCHECK(uid >= RootNodeId);
  self = [super init];

  if (self) {
    _bridge = bridge;
    _uid = uid;
  }

  return self;
}

#pragma mark - Semantics node methods

- (void)update:(const semantics::SemanticsNodePtr&)mojoNode {
  DCHECK(_uid == mojoNode->id);

  if (!mojoNode->flags.is_null()) {
    _flags = mojoNode->flags.Pass();
  }

  if (!mojoNode->strings.is_null()) {
    _strings = mojoNode->strings.Pass();
  }

  if (!mojoNode->geometry.is_null()) {
    _geometry = mojoNode->geometry;
  }

  if (!mojoNode->children.is_null()) {
    // Mark existing children as orphans
    NSArray* oldChildren = _children;
    for (AccessibilityNode* child in oldChildren) {
      DCHECK(child->_parent != nil);
      child->_parent = nil;
    }

    // Set the new list of children
    NSMutableArray* children = [[NSMutableArray alloc] init];
    _children = children;
    for (const semantics::SemanticsNodePtr& mojoChild : mojoNode->children) {
      AccessibilityNode* child = _bridge->UpdateNode(mojoChild);
      child->_parent = self;
      [children insertObject:child atIndex:0];
    }

    // Remove those children that are still marked as orphans
    for (AccessibilityNode* child in oldChildren) {
      if (child->_parent == nil) {
        _bridge->RemoveNode(child);
      }
    }
    [oldChildren release];
  }
}

- (void)remove {
  _parent = nil;
  _bridge->RemoveNode(self);
}

#pragma mark - UIAccessibility overrides

- (BOOL)isAccessibilityElement {
  // Per UIAccessibilityContainer, accessibility containers MUST return
  // NO to -isAccessibilityElement
  return (_children.count == 0);
}

- (NSString*)accessibilityLabel {
  return (_strings.is_null() || _strings->label.get().empty())
             ? nil
             : @(_strings->label.data());
}

- (UIAccessibilityTraits)accessibilityTraits {
  // TODO(tvolkert): We need more semantic info in the mojom definition
  // in order to distinguish buttons, links, sliders, etc.
  return _flags->canBeTapped ? UIAccessibilityTraitButton
                             : UIAccessibilityTraitNone;
}

- (CGRect)accessibilityFrame {
  SkPoint quad[4];
  _geometry.rect.toQuad(quad);
  for (auto& point : quad) {
    SkScalar vector[4] = {point.x(), point.y(), 0, 1};
    _geometry.transform.mapScalars(vector);
    point.set(vector[0], vector[1]);
  }
  SkRect result;
  result.set(quad, 4);
  return CGRectMake(result.x(), result.y(), result.width(), result.height());
}

#pragma mark - UIAccessibilityElement protocol

- (id)accessibilityContainer {
  return (_uid == RootNodeId) ? _bridge->getView() : _parent;
}

#pragma mark - UIAccessibilityContainer overrides
<commit_msg>Correctly report accessibilityFrame as screen coordinates (#2660)<commit_after>// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "sky/shell/platform/ios/framework/Source/accessibility_bridge.h"

#import <UIKit/UIKit.h>

#include "mojo/public/cpp/application/connect.h"

namespace {

static const uint32_t RootNodeId = 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;
  }

  SkMatrix44 transform =
      SkMatrix44(SkMatrix44::Identity_Constructor::kIdentity_Constructor);
  SkRect rect;
};

}  // anonymous namespace

@implementation AccessibilityNode {
  sky::shell::AccessibilityBridge* _bridge;

  semantics::SemanticFlagsPtr _flags;
  semantics::SemanticStringsPtr _strings;
  Geometry _geometry;
}

#pragma mark - Override base class designated initializers

// Method declared as unavailable in the interface
- (instancetype)init {
  [self release];
  [super doesNotRecognizeSelector:_cmd];
  return nil;
}

#pragma mark - Designated initializers

- (instancetype)initWithBridge:(sky::shell::AccessibilityBridge*)bridge
                           uid:(uint32_t)uid {
  DCHECK(bridge != nil) << "bridge must be set";
  DCHECK(uid >= RootNodeId);
  self = [super init];

  if (self) {
    _bridge = bridge;
    _uid = uid;
  }

  return self;
}

#pragma mark - Semantics node methods

- (void)update:(const semantics::SemanticsNodePtr&)mojoNode {
  DCHECK(_uid == mojoNode->id);

  if (!mojoNode->flags.is_null()) {
    _flags = mojoNode->flags.Pass();
  }

  if (!mojoNode->strings.is_null()) {
    _strings = mojoNode->strings.Pass();
  }

  if (!mojoNode->geometry.is_null()) {
    _geometry = mojoNode->geometry;
  }

  if (!mojoNode->children.is_null()) {
    // Mark existing children as orphans
    NSArray* oldChildren = _children;
    for (AccessibilityNode* child in oldChildren) {
      DCHECK(child->_parent != nil);
      child->_parent = nil;
    }

    // Set the new list of children
    NSMutableArray* children = [[NSMutableArray alloc] init];
    _children = children;
    for (const semantics::SemanticsNodePtr& mojoChild : mojoNode->children) {
      AccessibilityNode* child = _bridge->UpdateNode(mojoChild);
      child->_parent = self;
      [children insertObject:child atIndex:0];
    }

    // Remove those children that are still marked as orphans
    for (AccessibilityNode* child in oldChildren) {
      if (child->_parent == nil) {
        _bridge->RemoveNode(child);
      }
    }
    [oldChildren release];
  }
}

- (void)remove {
  _parent = nil;
  _bridge->RemoveNode(self);
}

#pragma mark - UIAccessibility overrides

- (BOOL)isAccessibilityElement {
  // 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 (_flags->canBeTapped || _children.count == 0);
}

- (NSString*)accessibilityLabel {
  return (_strings.is_null() || _strings->label.get().empty())
             ? nil
             : @(_strings->label.data());
}

- (UIAccessibilityTraits)accessibilityTraits {
  // TODO(tvolkert): We need more semantic info in the mojom definition
  // in order to distinguish buttons, links, sliders, etc.
  return _flags->canBeTapped ? UIAccessibilityTraitButton
                             : UIAccessibilityTraitNone;
}

- (CGRect)accessibilityFrame {
  SkMatrix44 globalTransform = _geometry.transform;
  for (AccessibilityNode* parent = _parent; parent; parent = parent.parent) {
    globalTransform = globalTransform * parent->_geometry.transform;
  }

  SkPoint quad[4];
  _geometry.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]);
  }
  SkRect rect;
  rect.set(quad, 4);

  auto result = CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
  return UIAccessibilityConvertFrameToScreenCoordinates(result,
                                                        _bridge->getView());
}

#pragma mark - UIAccessibilityElement protocol

- (id)accessibilityContainer {
  return (_uid == RootNodeId) ? _bridge->getView() : _parent;
}

#pragma mark - UIAccessibilityContainer overrides

{'fraction_non_alphanumeric': 0.12181464975431379, 'fraction_numerical': 0.0061707233459033254, 'mean_word_length': 3.577405857740586, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 62, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4939232', 'n_tokens_mistral': 2746, 'n_tokens_neox': 2640, 'n_words': 648}